Update V8 to version 4.1.0.21

This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.

Original commit message:

Version 4.1.0.21 (cherry-pick)

Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412

Unlink pages from the space page list after evacuation.

BUG=430201
LOG=N
R=jkummerow@chromium.org

Review URL: https://codereview.chromium.org/953813002

Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}

---

FPIIM-449

Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/test/benchmarks/testcfg.py b/test/benchmarks/testcfg.py
index 6607bef..29e0c37 100644
--- a/test/benchmarks/testcfg.py
+++ b/test/benchmarks/testcfg.py
@@ -186,7 +186,7 @@
     # Both --nocrankshaft and --stressopt are very slow. Add TF but without
     # always opt to match the way the benchmarks are run for performance
     # testing.
-    return [[], ["--turbo-filter=*"]]
+    return [[], ["--turbo-asm", "--turbo-filter=*"]]
 
 
 def GetSuite(name, root):
diff --git a/test/cctest/cctest.cc b/test/cctest/cctest.cc
index f03710a..170aa5a 100644
--- a/test/cctest/cctest.cc
+++ b/test/cctest/cctest.cc
@@ -34,12 +34,12 @@
 #include "test/cctest/profiler-extension.h"
 #include "test/cctest/trace-extension.h"
 
-#if (defined(_WIN32) || defined(_WIN64))
+#if V8_OS_WIN
 #include <windows.h>  // NOLINT
-#if defined(_MSC_VER)
+#if V8_CC_MSVC
 #include <crtdbg.h>
-#endif  // defined(_MSC_VER)
-#endif  // defined(_WIN32) || defined(_WIN64)
+#endif
+#endif
 
 enum InitializationState {kUnset, kUnintialized, kInitialized};
 static InitializationState initialization_state_  = kUnset;
@@ -47,7 +47,7 @@
 
 CcTest* CcTest::last_ = NULL;
 bool CcTest::initialize_called_ = false;
-bool CcTest::isolate_used_ = false;
+v8::base::Atomic32 CcTest::isolate_used_ = 0;
 v8::Isolate* CcTest::isolate_ = NULL;
 
 
@@ -145,12 +145,12 @@
 
 
 int main(int argc, char* argv[]) {
-#if (defined(_WIN32) || defined(_WIN64))
+#if V8_OS_WIN
   UINT new_flags =
       SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
   UINT existing_flags = SetErrorMode(new_flags);
   SetErrorMode(existing_flags | new_flags);
-#if defined(_MSC_VER)
+#if V8_CC_MSVC
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
@@ -158,8 +158,8 @@
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
   _set_error_mode(_OUT_TO_STDERR);
-#endif  // _MSC_VER
-#endif  // defined(_WIN32) || defined(_WIN64)
+#endif  // V8_CC_MSVC
+#endif  // V8_OS_WIN
 
   v8::V8::InitializeICU();
   v8::Platform* platform = v8::platform::CreateDefaultPlatform();
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index 6a57763..4d1c467 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -53,22 +53,27 @@
         'compiler/graph-tester.h',
         'compiler/simplified-graph-builder.cc',
         'compiler/simplified-graph-builder.h',
+        'compiler/test-basic-block-profiler.cc',
         'compiler/test-branch-combine.cc',
         'compiler/test-changes-lowering.cc',
         'compiler/test-codegen-deopt.cc',
+        'compiler/test-control-reducer.cc',
         'compiler/test-gap-resolver.cc',
         'compiler/test-graph-reducer.cc',
+        'compiler/test-graph-visualizer.cc',
         'compiler/test-instruction.cc',
         'compiler/test-js-context-specialization.cc',
         'compiler/test-js-constant-cache.cc',
         'compiler/test-js-typed-lowering.cc',
+        'compiler/test-jump-threading.cc',
         'compiler/test-linkage.cc',
+        'compiler/test-loop-assignment-analysis.cc',
+        'compiler/test-loop-analysis.cc',
         'compiler/test-machine-operator-reducer.cc',
         'compiler/test-node-algorithm.cc',
         'compiler/test-node-cache.cc',
         'compiler/test-node.cc',
         'compiler/test-operator.cc',
-        'compiler/test-phi-reducer.cc',
         'compiler/test-pipeline.cc',
         'compiler/test-representation-change.cc',
         'compiler/test-run-deopt.cc',
@@ -80,10 +85,12 @@
         'compiler/test-run-jsops.cc',
         'compiler/test-run-machops.cc',
         'compiler/test-run-properties.cc',
+        'compiler/test-run-stackcheck.cc',
         'compiler/test-run-variables.cc',
         'compiler/test-schedule.cc',
         'compiler/test-scheduler.cc',
         'compiler/test-simplified-lowering.cc',
+        'compiler/test-typer.cc',
         'cctest.cc',
         'gay-fixed.cc',
         'gay-precision.cc',
@@ -97,13 +104,13 @@
         'test-atomicops.cc',
         'test-bignum.cc',
         'test-bignum-dtoa.cc',
+        'test-bit-vector.cc',
         'test-checks.cc',
         'test-circular-queue.cc',
         'test-compiler.cc',
         'test-constantpool.cc',
         'test-conversions.cc',
         'test-cpu-profiler.cc',
-        'test-dataflow.cc',
         'test-date.cc',
         'test-debug.cc',
         'test-declarative-accessors.cc',
@@ -114,6 +121,7 @@
         'test-double.cc',
         'test-dtoa.cc',
         'test-fast-dtoa.cc',
+        'test-feedback-vector.cc',
         'test-fixed-dtoa.cc',
         'test-flags.cc',
         'test-func-name-inference.cc',
@@ -134,7 +142,6 @@
         'test-mementos.cc',
         'test-object-observe.cc',
         'test-ordered-hash-table.cc',
-        'test-ostreams.cc',
         'test-parsing.cc',
         'test-platform.cc',
         'test-profile-generator.cc',
@@ -142,6 +149,7 @@
         'test-regexp.cc',
         'test-reloc-info.cc',
         'test-representation.cc',
+        'test-sampler-api.cc',
         'test-serialize.cc',
         'test-spaces.cc',
         'test-strings.cc',
@@ -149,8 +157,10 @@
         'test-strtod.cc',
         'test-thread-termination.cc',
         'test-threads.cc',
+        'test-transitions.cc',
         'test-types.cc',
         'test-unbound-queue.cc',
+        'test-unboxed-doubles.cc',
         'test-unique.cc',
         'test-unscopables-hidden-prototype.cc',
         'test-utils.cc',
@@ -250,13 +260,14 @@
           # cctest can't be built against a shared library, so we need to
           # depend on the underlying static target in that case.
           'conditions': [
-            ['v8_use_snapshot=="true"', {
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==0', {
               'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
-            },
-            {
-              'dependencies': [
-                '../../tools/gyp/v8.gyp:v8_nosnapshot',
-              ],
+            }],
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==1', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_external_snapshot'],
+            }],
+            ['v8_use_snapshot!="true"', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_nosnapshot'],
             }],
           ],
         }, {
@@ -294,7 +305,6 @@
             '../../tools/js2c.py',
             '<@(_outputs)',
             'TEST',  # type
-            'off',  # compression
             '<@(file_list)',
           ],
         }
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index 6d27074..a8239d2 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -117,7 +117,7 @@
 
   static v8::Isolate* isolate() {
     CHECK(isolate_ != NULL);
-    isolate_used_ = true;
+    v8::base::NoBarrier_Store(&isolate_used_, 1);
     return isolate_;
   }
 
@@ -149,7 +149,7 @@
   // TODO(dcarney): Remove.
   // This must be called first in a test.
   static void InitializeVM() {
-    CHECK(!isolate_used_);
+    CHECK(!v8::base::NoBarrier_Load(&isolate_used_));
     CHECK(!initialize_called_);
     initialize_called_ = true;
     v8::HandleScope handle_scope(CcTest::isolate());
@@ -181,7 +181,7 @@
   static CcTest* last_;
   static v8::Isolate* isolate_;
   static bool initialize_called_;
-  static bool isolate_used_;
+  static v8::base::Atomic32 isolate_used_;
 };
 
 // Switches between all the Api tests using the threading support.
@@ -481,15 +481,31 @@
 
 
 // Helper function that simulates a full new-space in the heap.
-static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
-  int new_linear_size = static_cast<int>(
-      *space->allocation_limit_address() - *space->allocation_top_address());
-  if (new_linear_size == 0) return;
+static inline bool FillUpOnePage(v8::internal::NewSpace* space) {
   v8::internal::AllocationResult allocation =
-      space->AllocateRaw(new_linear_size);
+      space->AllocateRaw(v8::internal::Page::kMaxRegularHeapObjectSize);
+  if (allocation.IsRetry()) return false;
   v8::internal::FreeListNode* node =
       v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
-  node->set_size(space->heap(), new_linear_size);
+  node->set_size(space->heap(), v8::internal::Page::kMaxRegularHeapObjectSize);
+  return true;
+}
+
+
+static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
+  int new_linear_size = static_cast<int>(*space->allocation_limit_address() -
+                                         *space->allocation_top_address());
+  if (new_linear_size > 0) {
+    // Fill up the current page.
+    v8::internal::AllocationResult allocation =
+        space->AllocateRaw(new_linear_size);
+    v8::internal::FreeListNode* node =
+        v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+    node->set_size(space->heap(), new_linear_size);
+  }
+  // Fill up all remaining pages.
+  while (FillUpOnePage(space))
+    ;
 }
 
 
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 5198af6..cc5414d 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -29,6 +29,7 @@
 [ALWAYS, {
   # All tests prefixed with 'Bug' are expected to fail.
   'test-api/Bug*': [FAIL],
+  'test-serialize/Bug*': [FAIL],
 
   ##############################################################################
 
@@ -80,58 +81,14 @@
   ##############################################################################
   # TurboFan compiler failures.
 
-  # TODO(sigurds): The schedule is borked with multiple inlinees,
-  # and cannot handle free-floating loops yet
-  'test-run-inlining/InlineTwiceDependentDiamond': [SKIP],
-  'test-run-inlining/InlineTwiceDependentDiamondDifferent': [SKIP],
-  'test-run-inlining/InlineLoop': [SKIP],
-
   # Some tests are just too slow to run for now.
   'test-api/Threading*': [PASS, NO_VARIANTS],
   'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [PASS, NO_VARIANTS],
   'test-heap-profiler/ManyLocalsInSharedContext': [PASS, NO_VARIANTS],
   'test-debug/ThreadedDebugging': [PASS, NO_VARIANTS],
   'test-debug/DebugBreakLoop': [PASS, NO_VARIANTS],
-
-  # Support for breakpoints requires using LoadICs and StoreICs.
-  'test-debug/BreakPointICStore': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICLoad': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICCall': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICCallWithGC': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointConstructCallWithGC': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointReturn': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/ScriptBreakPointByNameThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/ScriptBreakPointByIdThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLinear': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepKeyedLoadLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepKeyedStoreLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepNamedLoadLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepNamedStoreLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLinearMixedICs': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepDeclarations': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLocals': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepIf': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepSwitch': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepWhile': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepDoWhile': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepFor': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForContinue': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForIn': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepWith': [PASS, NO_VARIANTS],
-  'test-debug/DebugConditional': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutSimple': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutTree': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutBranch': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreakStackInspection': [PASS, NO_VARIANTS],
-  'test-debug/BreakMessageWhenMessageHandlerIsReset': [PASS, NO_VARIANTS],
-  'test-debug/NoDebugBreakInAfterCompileMessageHandler': [PASS, NO_VARIANTS],
-  'test-debug/DisableBreak': [PASS, NO_VARIANTS],
-  'test-debug/RegExpDebugBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreakFunctionApply': [PASS, NO_VARIANTS],
-  'test-debug/DeoptimizeDuringDebugBreak': [PASS, NO_VARIANTS],
+  # BUG(3742).
+  'test-mark-compact/MarkCompactCollector': [PASS, ['arch==arm', NO_VARIANTS]],
 
   # Support for %GetFrameDetails is missing and requires checkpoints.
   'test-api/Regress385349': [PASS, NO_VARIANTS],
@@ -148,6 +105,17 @@
   'test-debug/CallingContextIsNotDebugContext': [PASS, NO_VARIANTS],
   'test-debug/DebugEventContext': [PASS, NO_VARIANTS],
   'test-debug/DebugBreakInline': [PASS, NO_VARIANTS],
+  'test-debug/BreakMessageWhenMessageHandlerIsReset': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreak': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreakFunctionApply': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreakStackInspection': [PASS, NO_VARIANTS],
+  'test-debug/DeoptimizeDuringDebugBreak': [PASS, NO_VARIANTS],
+  'test-debug/DisableBreak': [PASS, NO_VARIANTS],
+  'test-debug/NoDebugBreakInAfterCompileMessageHandler': [PASS, NO_VARIANTS],
+  'test-debug/RegExpDebugBreak': [PASS, NO_VARIANTS],
+
+  # TODO(titzer): Triggers bug in late control reduction.
+  'test-run-inlining/InlineLoopGuardedEmpty': [SKIP],
 
   ############################################################################
   # Slow tests.
@@ -298,6 +266,19 @@
 }],  # 'arch == mipsel or arch == mips'
 
 ##############################################################################
+['arch == mips', {
+  # Too slow with TF.
+  'test-api/ExternalArrays': [PASS, NO_VARIANTS],
+
+  # TODO(mips-team): Currently fails on mips board.
+  'test-simplified-lowering/RunNumberMultiply_TruncatingToUint32': [SKIP],
+  'test-parsing/TooManyArguments': [SKIP],
+  'test-api/Threading3': [SKIP],
+  'test-api/RequestInterruptTestWithNativeAccessor': [SKIP],
+  'test-api/RequestInterruptTestWithAccessor': [SKIP],
+}],  # 'arch == mips'
+
+##############################################################################
 ['arch == mips64el', {
 
   # BUG(2657): Test sometimes times out on MIPS simulator.
@@ -334,12 +315,6 @@
   'test-log/LogAccessorCallbacks': [SKIP],
   'test-log/LogCallbacks': [SKIP],
   'test-log/ProfLazyMode': [SKIP],
-
-  # platform-tls.h does not contain an ANDROID-related header.
-  'test-platform-tls/FastTLS': [SKIP],
-
-  # This test times out.
-  'test-threads/ThreadJoinSelf': [SKIP],
 }],  # 'arch == android_arm or arch == android_ia32'
 
 ##############################################################################
diff --git a/test/cctest/compiler/call-tester.h b/test/cctest/compiler/call-tester.h
index e864160..cad171e 100644
--- a/test/cctest/compiler/call-tester.h
+++ b/test/cctest/compiler/call-tester.h
@@ -207,7 +207,43 @@
         Simulator::CallArgument::End()};
     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
   }
-#elif USE_SIMULATOR && V8_TARGET_ARCH_ARM
+#elif USE_SIMULATOR && V8_TARGET_ARCH_MIPS64
+  uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
+                          int64_t p3 = 0, int64_t p4 = 0) {
+    Simulator* simulator = Simulator::current(isolate_);
+    return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
+  }
+
+  template <typename R, typename F>
+  R DoCall(F* f) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
+  }
+  template <typename R, typename F, typename P1>
+  R DoCall(F* f, P1 p1) {
+    return ReturnValueTraits<R>::Cast(
+        CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
+  }
+  template <typename R, typename F, typename P1, typename P2>
+  R DoCall(F* f, P1 p1, P2 p2) {
+    return ReturnValueTraits<R>::Cast(
+        CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+                      ParameterTraits<P2>::Cast(p2)));
+  }
+  template <typename R, typename F, typename P1, typename P2, typename P3>
+  R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(
+        FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+        ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
+  }
+  template <typename R, typename F, typename P1, typename P2, typename P3,
+            typename P4>
+  R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(
+        FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+        ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
+        ParameterTraits<P4>::Cast(p4)));
+  }
+#elif USE_SIMULATOR && (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS)
   uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
                           int32_t p3 = 0, int32_t p4 = 0) {
     Simulator* simulator = Simulator::current(isolate_);
diff --git a/test/cctest/compiler/codegen-tester.cc b/test/cctest/compiler/codegen-tester.cc
index b1874f5..5311001 100644
--- a/test/cctest/compiler/codegen-tester.cc
+++ b/test/cctest/compiler/codegen-tester.cc
@@ -14,7 +14,6 @@
 TEST(CompareWrapper) {
   // Who tests the testers?
   // If CompareWrapper is broken, then test expectations will be broken.
-  RawMachineAssemblerTester<int32_t> m;
   CompareWrapper wWord32Equal(IrOpcode::kWord32Equal);
   CompareWrapper wInt32LessThan(IrOpcode::kInt32LessThan);
   CompareWrapper wInt32LessThanOrEqual(IrOpcode::kInt32LessThanOrEqual);
@@ -477,10 +476,10 @@
 
 
 TEST(RunHeapNumberConstant) {
-  RawMachineAssemblerTester<Object*> m;
-  Handle<Object> number = m.isolate()->factory()->NewHeapNumber(100.5);
+  RawMachineAssemblerTester<HeapObject*> m;
+  Handle<HeapObject> number = m.isolate()->factory()->NewHeapNumber(100.5);
   m.Return(m.HeapConstant(number));
-  Object* result = m.Call();
+  HeapObject* result = m.Call();
   CHECK_EQ(result, *number);
 }
 
diff --git a/test/cctest/compiler/codegen-tester.h b/test/cctest/compiler/codegen-tester.h
index 6aa5bae..283d533 100644
--- a/test/cctest/compiler/codegen-tester.h
+++ b/test/cctest/compiler/codegen-tester.h
@@ -7,6 +7,7 @@
 
 #include "src/v8.h"
 
+#include "src/compiler/instruction-selector.h"
 #include "src/compiler/pipeline.h"
 #include "src/compiler/raw-machine-assembler.h"
 #include "src/simulator.h"
@@ -23,7 +24,9 @@
  public:
   MachineAssemblerTester(MachineType return_type, MachineType p0,
                          MachineType p1, MachineType p2, MachineType p3,
-                         MachineType p4)
+                         MachineType p4,
+                         MachineOperatorBuilder::Flags flags =
+                             MachineOperatorBuilder::Flag::kNoFlags)
       : HandleAndZoneScope(),
         CallHelper(
             main_isolate(),
@@ -31,7 +34,7 @@
         MachineAssembler(
             new (main_zone()) Graph(main_zone()),
             MakeMachineSignature(main_zone(), return_type, p0, p1, p2, p3, p4),
-            kMachPtr) {}
+            kMachPtr, flags) {}
 
   Node* LoadFromPointer(void* address, MachineType rep, int32_t offset = 0) {
     return this->Load(rep, this->PointerConstant(address),
@@ -65,10 +68,8 @@
       Schedule* schedule = this->Export();
       CallDescriptor* call_descriptor = this->call_descriptor();
       Graph* graph = this->graph();
-      CompilationInfo info(graph->zone()->isolate(), graph->zone());
-      Linkage linkage(&info, call_descriptor);
-      Pipeline pipeline(&info);
-      code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph, schedule);
+      code_ =
+          Pipeline::GenerateCodeForTesting(call_descriptor, graph, schedule);
     }
     return this->code_.ToHandleChecked()->entry();
   }
@@ -89,8 +90,8 @@
                             MachineType p3 = kMachNone,
                             MachineType p4 = kMachNone)
       : MachineAssemblerTester<RawMachineAssembler>(
-            ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3,
-            p4) {}
+            ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3, p4,
+            InstructionSelector::SupportedMachineOperatorFlags()) {}
 
   template <typename Ci, typename Fn>
   void Run(const Ci& ci, const Fn& fn) {
diff --git a/test/cctest/compiler/function-tester.h b/test/cctest/compiler/function-tester.h
index c869f00..7e16eea 100644
--- a/test/cctest/compiler/function-tester.h
+++ b/test/cctest/compiler/function-tester.h
@@ -8,7 +8,9 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
+#include "src/ast-numbering.h"
 #include "src/compiler.h"
+#include "src/compiler/linkage.h"
 #include "src/compiler/pipeline.h"
 #include "src/execution.h"
 #include "src/full-codegen.h"
@@ -37,52 +39,16 @@
     CHECK_EQ(0, flags_ & ~supported_flags);
   }
 
+  explicit FunctionTester(Graph* graph)
+      : isolate(main_isolate()),
+        function(NewFunction("(function(a,b){})")),
+        flags_(0) {
+    CompileGraph(graph);
+  }
+
   Isolate* isolate;
   Handle<JSFunction> function;
 
-  Handle<JSFunction> Compile(Handle<JSFunction> function) {
-#if V8_TURBOFAN_TARGET
-    CompilationInfoWithZone info(function);
-
-    CHECK(Parser::Parse(&info));
-    info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-    if (flags_ & CompilationInfo::kContextSpecializing) {
-      info.MarkAsContextSpecializing();
-    }
-    if (flags_ & CompilationInfo::kInliningEnabled) {
-      info.MarkAsInliningEnabled();
-    }
-    if (flags_ & CompilationInfo::kTypingEnabled) {
-      info.MarkAsTypingEnabled();
-    }
-    CHECK(Rewriter::Rewrite(&info));
-    CHECK(Scope::Analyze(&info));
-    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
-
-    Pipeline pipeline(&info);
-    Handle<Code> code = pipeline.GenerateCode();
-    if (FLAG_turbo_deoptimization) {
-      info.context()->native_context()->AddOptimizedCode(*code);
-    }
-
-    CHECK(!code.is_null());
-    function->ReplaceCode(*code);
-#elif USE_CRANKSHAFT
-    Handle<Code> unoptimized = Handle<Code>(function->code());
-    Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
-                                                   Compiler::NOT_CONCURRENT);
-    CHECK(!code.is_null());
-#if ENABLE_DISASSEMBLER
-    if (FLAG_print_opt_code) {
-      CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
-      code->Disassemble("test code", tracing_scope.file());
-    }
-#endif
-    function->ReplaceCode(*code);
-#endif
-    return function;
-  }
-
   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
     Handle<Object> args[] = {a, b};
     return Execution::Call(isolate, function, undefined(), 2, args, false);
@@ -183,8 +149,78 @@
 
   Handle<Object> false_value() { return isolate->factory()->false_value(); }
 
+  Handle<JSFunction> Compile(Handle<JSFunction> function) {
+// TODO(titzer): make this method private.
+#if V8_TURBOFAN_TARGET
+    CompilationInfoWithZone info(function);
+
+    CHECK(Parser::Parse(&info));
+    info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
+    if (flags_ & CompilationInfo::kContextSpecializing) {
+      info.MarkAsContextSpecializing();
+    }
+    if (flags_ & CompilationInfo::kInliningEnabled) {
+      info.MarkAsInliningEnabled();
+    }
+    if (flags_ & CompilationInfo::kTypingEnabled) {
+      info.MarkAsTypingEnabled();
+    }
+    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
+
+    Pipeline pipeline(&info);
+    Handle<Code> code = pipeline.GenerateCode();
+    if (FLAG_turbo_deoptimization) {
+      info.context()->native_context()->AddOptimizedCode(*code);
+    }
+
+    CHECK(!code.is_null());
+    function->ReplaceCode(*code);
+#elif USE_CRANKSHAFT
+    Handle<Code> unoptimized = Handle<Code>(function->code());
+    Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
+                                                   Compiler::NOT_CONCURRENT);
+    CHECK(!code.is_null());
+#if ENABLE_DISASSEMBLER
+    if (FLAG_print_opt_code) {
+      CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
+      code->Disassemble("test code", tracing_scope.file());
+    }
+#endif
+    function->ReplaceCode(*code);
+#endif
+    return function;
+  }
+
+  static Handle<JSFunction> ForMachineGraph(Graph* graph) {
+    JSFunction* p = NULL;
+    {  // because of the implicit handle scope of FunctionTester.
+      FunctionTester f(graph);
+      p = *f.function;
+    }
+    return Handle<JSFunction>(p);  // allocated in outer handle scope.
+  }
+
  private:
   uint32_t flags_;
+
+  // Compile the given machine graph instead of the source of the function
+  // and replace the JSFunction's code with the result.
+  Handle<JSFunction> CompileGraph(Graph* graph) {
+    CHECK(Pipeline::SupportedTarget());
+    CompilationInfoWithZone info(function);
+
+    CHECK(Parser::Parse(&info));
+    info.SetOptimizing(BailoutId::None(),
+                       Handle<Code>(function->shared()->code()));
+    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
+
+    Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);
+    CHECK(!code.is_null());
+    function->ReplaceCode(*code);
+    return function;
+  }
 };
 }
 }
diff --git a/test/cctest/compiler/graph-builder-tester.cc b/test/cctest/compiler/graph-builder-tester.cc
index bfa8226..b0f470b 100644
--- a/test/cctest/compiler/graph-builder-tester.cc
+++ b/test/cctest/compiler/graph-builder-tester.cc
@@ -35,11 +35,9 @@
   if (!Pipeline::SupportedBackend()) return NULL;
   if (code_.is_null()) {
     Zone* zone = graph_->zone();
-    CompilationInfo info(zone->isolate(), zone);
-    Linkage linkage(&info,
-                    Linkage::GetSimplifiedCDescriptor(zone, machine_sig_));
-    Pipeline pipeline(&info);
-    code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph_);
+    CallDescriptor* desc =
+        Linkage::GetSimplifiedCDescriptor(zone, machine_sig_);
+    code_ = Pipeline::GenerateCodeForTesting(desc, graph_);
   }
   return code_.ToHandleChecked()->entry();
 }
diff --git a/test/cctest/compiler/graph-builder-tester.h b/test/cctest/compiler/graph-builder-tester.h
index df79250..772de4d 100644
--- a/test/cctest/compiler/graph-builder-tester.h
+++ b/test/cctest/compiler/graph-builder-tester.h
@@ -27,8 +27,8 @@
 
  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL {
-    return graph()->NewNode(op, value_input_count, value_inputs);
+                         Node** value_inputs, bool incomplete) FINAL {
+    return graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   }
 };
 
@@ -61,6 +61,7 @@
   explicit GraphAndBuilders(Zone* zone)
       : main_graph_(new (zone) Graph(zone)),
         main_common_(zone),
+        main_machine_(zone),
         main_simplified_(zone) {}
 
  protected:
diff --git a/test/cctest/compiler/simplified-graph-builder.cc b/test/cctest/compiler/simplified-graph-builder.cc
index c44d5ed..baa03fb 100644
--- a/test/cctest/compiler/simplified-graph-builder.cc
+++ b/test/cctest/compiler/simplified-graph-builder.cc
@@ -5,7 +5,6 @@
 #include "test/cctest/compiler/simplified-graph-builder.h"
 
 #include "src/compiler/operator-properties.h"
-#include "src/compiler/operator-properties-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -45,20 +44,20 @@
 
 Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
                                        int value_input_count,
-                                       Node** value_inputs) {
-  DCHECK(op->InputCount() == value_input_count);
+                                       Node** value_inputs, bool incomplete) {
+  DCHECK(op->ValueInputCount() == value_input_count);
 
   DCHECK(!OperatorProperties::HasContextInput(op));
   DCHECK(!OperatorProperties::HasFrameStateInput(op));
-  bool has_control = OperatorProperties::GetControlInputCount(op) == 1;
-  bool has_effect = OperatorProperties::GetEffectInputCount(op) == 1;
+  bool has_control = op->ControlInputCount() == 1;
+  bool has_effect = op->EffectInputCount() == 1;
 
-  DCHECK(OperatorProperties::GetControlInputCount(op) < 2);
-  DCHECK(OperatorProperties::GetEffectInputCount(op) < 2);
+  DCHECK(op->ControlInputCount() < 2);
+  DCHECK(op->EffectInputCount() < 2);
 
   Node* result = NULL;
   if (!has_control && !has_effect) {
-    result = graph()->NewNode(op, value_input_count, value_inputs);
+    result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
     int input_count_with_deps = value_input_count;
     if (has_control) ++input_count_with_deps;
@@ -72,14 +71,12 @@
     if (has_control) {
       *current_input++ = graph()->start();
     }
-    result = graph()->NewNode(op, input_count_with_deps, buffer);
+    result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
     if (has_effect) {
       effect_ = result;
     }
-    if (OperatorProperties::HasControlOutput(result->op())) {
-      // This graph builder does not support control flow.
-      UNREACHABLE();
-    }
+    // This graph builder does not support control flow.
+    CHECK_EQ(0, op->ControlOutputCount());
   }
 
   return result;
diff --git a/test/cctest/compiler/simplified-graph-builder.h b/test/cctest/compiler/simplified-graph-builder.h
index 1b637b7..537094a 100644
--- a/test/cctest/compiler/simplified-graph-builder.h
+++ b/test/cctest/compiler/simplified-graph-builder.h
@@ -45,8 +45,8 @@
   Node* Int32Constant(int32_t value) {
     return NewNode(common()->Int32Constant(value));
   }
-  Node* HeapConstant(Handle<Object> object) {
-    Unique<Object> val = Unique<Object>::CreateUninitialized(object);
+  Node* HeapConstant(Handle<HeapObject> object) {
+    Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
     return NewNode(common()->HeapConstant(val));
   }
 
@@ -127,19 +127,17 @@
   Node* StoreField(const FieldAccess& access, Node* object, Node* value) {
     return NewNode(simplified()->StoreField(access), object, value);
   }
-  Node* LoadElement(const ElementAccess& access, Node* object, Node* index,
-                    Node* length) {
-    return NewNode(simplified()->LoadElement(access), object, index, length);
+  Node* LoadElement(const ElementAccess& access, Node* object, Node* index) {
+    return NewNode(simplified()->LoadElement(access), object, index);
   }
   Node* StoreElement(const ElementAccess& access, Node* object, Node* index,
-                     Node* length, Node* value) {
-    return NewNode(simplified()->StoreElement(access), object, index, length,
-                   value);
+                     Node* value) {
+    return NewNode(simplified()->StoreElement(access), object, index, value);
   }
 
  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL;
+                         Node** value_inputs, bool incomplete) FINAL;
 
  private:
   Node* effect_;
diff --git a/test/cctest/compiler/test-basic-block-profiler.cc b/test/cctest/compiler/test-basic-block-profiler.cc
new file mode 100644
index 0000000..703fc17
--- /dev/null
+++ b/test/cctest/compiler/test-basic-block-profiler.cc
@@ -0,0 +1,114 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/basic-block-profiler.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/codegen-tester.h"
+
+#if V8_TURBOFAN_TARGET
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+typedef RawMachineAssembler::Label MLabel;
+
+class BasicBlockProfilerTest : public RawMachineAssemblerTester<int32_t> {
+ public:
+  BasicBlockProfilerTest() : RawMachineAssemblerTester<int32_t>(kMachInt32) {
+    FLAG_turbo_profiling = true;
+  }
+
+  void ResetCounts() { isolate()->basic_block_profiler()->ResetCounts(); }
+
+  void Expect(size_t size, uint32_t* expected) {
+    CHECK_NE(NULL, isolate()->basic_block_profiler());
+    const BasicBlockProfiler::DataList* l =
+        isolate()->basic_block_profiler()->data_list();
+    CHECK_NE(0, static_cast<int>(l->size()));
+    const BasicBlockProfiler::Data* data = l->back();
+    CHECK_EQ(static_cast<int>(size), static_cast<int>(data->n_blocks()));
+    const uint32_t* counts = data->counts();
+    for (size_t i = 0; i < size; ++i) {
+      CHECK_EQ(static_cast<int>(expected[i]), static_cast<int>(counts[i]));
+    }
+  }
+};
+
+
+TEST(ProfileDiamond) {
+  BasicBlockProfilerTest m;
+
+  MLabel blocka, blockb, end;
+  m.Branch(m.Parameter(0), &blocka, &blockb);
+  m.Bind(&blocka);
+  m.Goto(&end);
+  m.Bind(&blockb);
+  m.Goto(&end);
+  m.Bind(&end);
+  m.Return(m.Int32Constant(0));
+
+  m.GenerateCode();
+  {
+    uint32_t expected[] = {0, 0, 0, 0};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.Call(0);
+  {
+    uint32_t expected[] = {1, 1, 0, 1};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.ResetCounts();
+
+  m.Call(1);
+  {
+    uint32_t expected[] = {1, 0, 1, 1};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.Call(0);
+  {
+    uint32_t expected[] = {2, 1, 1, 2};
+    m.Expect(arraysize(expected), expected);
+  }
+}
+
+
+TEST(ProfileLoop) {
+  BasicBlockProfilerTest m;
+
+  MLabel header, body, end;
+  Node* one = m.Int32Constant(1);
+  m.Goto(&header);
+
+  m.Bind(&header);
+  Node* count = m.Phi(kMachInt32, m.Parameter(0), one);
+  m.Branch(count, &body, &end);
+
+  m.Bind(&body);
+  count->ReplaceInput(1, m.Int32Sub(count, one));
+  m.Goto(&header);
+
+  m.Bind(&end);
+  m.Return(one);
+
+  m.GenerateCode();
+  {
+    uint32_t expected[] = {0, 0, 0, 0};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  uint32_t runs[] = {0, 1, 500, 10000};
+  for (size_t i = 0; i < arraysize(runs); i++) {
+    m.ResetCounts();
+    CHECK_EQ(1, m.Call(static_cast<int>(runs[i])));
+    uint32_t expected[] = {1, runs[i] + 1, runs[i], 1};
+    m.Expect(arraysize(expected), expected);
+  }
+}
+
+#endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-changes-lowering.cc b/test/cctest/compiler/test-changes-lowering.cc
index 06308a0..5795754 100644
--- a/test/cctest/compiler/test-changes-lowering.cc
+++ b/test/cctest/compiler/test-changes-lowering.cc
@@ -6,10 +6,11 @@
 
 #include "src/compiler/change-lowering.h"
 #include "src/compiler/control-builders.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/pipeline.h"
+#include "src/compiler/select-lowering.h"
+#include "src/compiler/simplified-lowering.h"
 #include "src/compiler/typer.h"
 #include "src/compiler/verifier.h"
 #include "src/execution.h"
@@ -19,6 +20,7 @@
 #include "src/scopes.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/codegen-tester.h"
+#include "test/cctest/compiler/function-tester.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
 #include "test/cctest/compiler/value-helper.h"
 
@@ -30,13 +32,10 @@
  public:
   explicit ChangesLoweringTester(MachineType p0 = kMachNone)
       : GraphBuilderTester<ReturnType>(p0),
-        typer(this->zone()),
         javascript(this->zone()),
-        jsgraph(this->graph(), this->common(), &javascript, &typer,
-                this->machine()),
+        jsgraph(this->graph(), this->common(), &javascript, this->machine()),
         function(Handle<JSFunction>::null()) {}
 
-  Typer typer;
   JSOperatorBuilder javascript;
   JSGraph jsgraph;
   Handle<JSFunction> function;
@@ -45,29 +44,10 @@
 
   template <typename T>
   T* CallWithPotentialGC() {
-    // TODO(titzer): we need to wrap the code in a JSFunction and call it via
-    // Execution::Call() so that the GC knows about the frame, can walk it,
-    // relocate the code object if necessary, etc.
-    // This is pretty ugly and at the least should be moved up to helpers.
+    // TODO(titzer): we wrap the code in a JSFunction here to reuse the
+    // JSEntryStub; that could be done with a special prologue or other stub.
     if (function.is_null()) {
-      function =
-          v8::Utils::OpenHandle(*v8::Handle<v8::Function>::Cast(CompileRun(
-              "(function() { 'use strict'; return 2.7123; })")));
-      CompilationInfoWithZone info(function);
-      CHECK(Parser::Parse(&info));
-      info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-      CHECK(Rewriter::Rewrite(&info));
-      CHECK(Scope::Analyze(&info));
-      CHECK_NE(NULL, info.scope());
-      Handle<ScopeInfo> scope_info =
-          ScopeInfo::Create(info.scope(), info.zone());
-      info.shared_info()->set_scope_info(*scope_info);
-      Pipeline pipeline(&info);
-      Linkage linkage(&info);
-      Handle<Code> code =
-          pipeline.GenerateCodeForMachineGraph(&linkage, this->graph());
-      CHECK(!code.is_null());
-      function->ReplaceCode(*code);
+      function = FunctionTester::ForMachineGraph(this->graph());
     }
     Handle<Object>* args = NULL;
     MaybeHandle<Object> result =
@@ -132,9 +112,9 @@
                          void* location) {
     // We build a graph by hand here, because the raw machine assembler
     // does not add the correct control and effect nodes.
-    Node* load =
-        this->graph()->NewNode(load_op, this->PointerConstant(location),
-                               this->Int32Constant(0), this->start());
+    Node* load = this->graph()->NewNode(
+        load_op, this->PointerConstant(location), this->Int32Constant(0),
+        this->start(), this->start());
     Node* change = this->graph()->NewNode(op, load);
     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
                                        this->start(), this->start());
@@ -146,12 +126,16 @@
   void LowerChange(Node* change) {
     // Run the graph reducer with changes lowering on a single node.
     CompilationInfo info(this->isolate(), this->zone());
-    Linkage linkage(&info);
-    ChangeLowering lowering(&jsgraph, &linkage);
-    GraphReducer reducer(this->graph());
-    reducer.AddReducer(&lowering);
+    Linkage linkage(this->zone(), &info);
+    Typer typer(this->graph(), info.context());
+    typer.Run();
+    ChangeLowering change_lowering(&jsgraph, &linkage);
+    SelectLowering select_lowering(this->graph(), this->common());
+    GraphReducer reducer(this->graph(), this->zone());
+    reducer.AddReducer(&change_lowering);
+    reducer.AddReducer(&select_lowering);
     reducer.ReduceNode(change);
-    Verifier::Run(this->graph());
+    Verifier::Run(this->graph(), Verifier::UNTYPED);
   }
 
   Factory* factory() { return this->isolate()->factory(); }
diff --git a/test/cctest/compiler/test-codegen-deopt.cc b/test/cctest/compiler/test-codegen-deopt.cc
index 8217229..56afe7b 100644
--- a/test/cctest/compiler/test-codegen-deopt.cc
+++ b/test/cctest/compiler/test-codegen-deopt.cc
@@ -16,6 +16,7 @@
 #include "src/compiler/register-allocator.h"
 #include "src/compiler/schedule.h"
 
+#include "src/ast-numbering.h"
 #include "src/full-codegen.h"
 #include "src/parser.h"
 #include "src/rewriter.h"
@@ -30,6 +31,7 @@
 #if V8_TURBOFAN_TARGET
 
 typedef RawMachineAssembler::Label MLabel;
+typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
 
 static Handle<JSFunction> NewFunction(const char* source) {
   return v8::Utils::OpenHandle(
@@ -46,8 +48,7 @@
         bailout_id(-1) {
     CHECK(Parser::Parse(&info));
     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-    CHECK(Rewriter::Rewrite(&info));
-    CHECK(Scope::Analyze(&info));
+    CHECK(Compiler::Analyze(&info));
     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
 
     DCHECK(info.shared_info()->has_deoptimization_support());
@@ -55,38 +56,14 @@
     graph = new (scope_->main_zone()) Graph(scope_->main_zone());
   }
 
-  virtual ~DeoptCodegenTester() { delete code; }
+  virtual ~DeoptCodegenTester() {}
 
   void GenerateCodeFromSchedule(Schedule* schedule) {
     OFStream os(stdout);
     if (FLAG_trace_turbo) {
       os << *schedule;
     }
-
-    // Initialize the codegen and generate code.
-    Linkage* linkage = new (scope_->main_zone()) Linkage(&info);
-    code = new v8::internal::compiler::InstructionSequence(linkage, graph,
-                                                           schedule);
-    SourcePositionTable source_positions(graph);
-    InstructionSelector selector(code, &source_positions);
-    selector.SelectInstructions();
-
-    if (FLAG_trace_turbo) {
-      os << "----- Instruction sequence before register allocation -----\n"
-         << *code;
-    }
-
-    RegisterAllocator allocator(code);
-    CHECK(allocator.Allocate());
-
-    if (FLAG_trace_turbo) {
-      os << "----- Instruction sequence after register allocation -----\n"
-         << *code;
-    }
-
-    compiler::CodeGenerator generator(code);
-    result_code = generator.GenerateCode();
-
+    result_code = Pipeline::GenerateCodeForTesting(&info, graph, schedule);
 #ifdef OBJECT_PRINT
     if (FLAG_print_opt_code || FLAG_trace_turbo) {
       result_code->Print();
@@ -101,7 +78,7 @@
   CompilationInfo info;
   BailoutId bailout_id;
   Handle<Code> result_code;
-  v8::internal::compiler::InstructionSequence* code;
+  TestInstrSeq* code;
   Graph* graph;
 };
 
@@ -129,13 +106,13 @@
 
     Handle<JSFunction> deopt_function =
         NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
-    Unique<Object> deopt_fun_constant =
-        Unique<Object>::CreateUninitialized(deopt_function);
+    Unique<JSFunction> deopt_fun_constant =
+        Unique<JSFunction>::CreateUninitialized(deopt_function);
     Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant));
 
     Handle<Context> caller_context(function->context(), CcTest::i_isolate());
-    Unique<Object> caller_context_constant =
-        Unique<Object>::CreateUninitialized(caller_context);
+    Unique<Context> caller_context_constant =
+        Unique<Context>::CreateUninitialized(caller_context);
     Node* caller_context_node =
         m.NewNode(common.HeapConstant(caller_context_constant));
 
@@ -145,12 +122,13 @@
     Node* stack = m.NewNode(common.StateValues(0));
 
     Node* state_node = m.NewNode(
-        common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
-        locals, stack, caller_context_node, m.UndefinedConstant());
+        common.FrameState(JS_FRAME, bailout_id,
+                          OutputFrameStateCombine::Ignore()),
+        parameters, locals, stack, caller_context_node, m.UndefinedConstant());
 
     Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
-    Unique<Object> context_constant =
-        Unique<Object>::CreateUninitialized(context);
+    Unique<Context> context_constant =
+        Unique<Context>::CreateUninitialized(context);
     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
 
     m.CallJS0(deopt_fun_node, m.UndefinedConstant(), context_node, state_node);
@@ -244,13 +222,13 @@
     CSignature1<Object*, Object*> sig;
     RawMachineAssembler m(graph, &sig);
 
-    Unique<Object> this_fun_constant =
-        Unique<Object>::CreateUninitialized(function);
+    Unique<HeapObject> this_fun_constant =
+        Unique<HeapObject>::CreateUninitialized(function);
     Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
 
     Handle<Context> context(function->context(), CcTest::i_isolate());
-    Unique<Object> context_constant =
-        Unique<Object>::CreateUninitialized(context);
+    Unique<HeapObject> context_constant =
+        Unique<HeapObject>::CreateUninitialized(context);
     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
 
     bailout_id = GetCallBailoutId();
@@ -259,8 +237,9 @@
     Node* stack = m.NewNode(common.StateValues(0));
 
     Node* state_node = m.NewNode(
-        common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
-        locals, stack, context_node, m.UndefinedConstant());
+        common.FrameState(JS_FRAME, bailout_id,
+                          OutputFrameStateCombine::Ignore()),
+        parameters, locals, stack, context_node, m.UndefinedConstant());
 
     m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node,
                    state_node);
diff --git a/test/cctest/compiler/test-control-reducer.cc b/test/cctest/compiler/test-control-reducer.cc
new file mode 100644
index 0000000..03aa50b
--- /dev/null
+++ b/test/cctest/compiler/test-control-reducer.cc
@@ -0,0 +1,1678 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/base/bits.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/control-reducer.h"
+#include "src/compiler/graph-inl.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-properties-inl.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+static const size_t kNumLeafs = 4;
+
+// TODO(titzer): convert this whole file into unit tests.
+
+static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                       Node* i2 = NULL) {
+  int count = 3;
+  if (i2 == NULL) count = 2;
+  if (i1 == NULL) count = 1;
+  if (i0 == NULL) count = 0;
+  CHECK_EQ(count, node->InputCount());
+  if (i0 != NULL) CHECK_EQ(i0, node->InputAt(0));
+  if (i1 != NULL) CHECK_EQ(i1, node->InputAt(1));
+  if (i2 != NULL) CHECK_EQ(i2, node->InputAt(2));
+  return count;
+}
+
+
+static int CheckMerge(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                      Node* i2 = NULL) {
+  CHECK_EQ(IrOpcode::kMerge, node->opcode());
+  int count = CheckInputs(node, i0, i1, i2);
+  CHECK_EQ(count, node->op()->ControlInputCount());
+  return count;
+}
+
+
+static int CheckLoop(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                     Node* i2 = NULL) {
+  CHECK_EQ(IrOpcode::kLoop, node->opcode());
+  int count = CheckInputs(node, i0, i1, i2);
+  CHECK_EQ(count, node->op()->ControlInputCount());
+  return count;
+}
+
+
+bool IsUsedBy(Node* a, Node* b) {
+  for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) {
+    if (b == *i) return true;
+  }
+  return false;
+}
+
+
+// A helper for all tests dealing with ControlTester.
+class ControlReducerTester : HandleAndZoneScope {
+ public:
+  ControlReducerTester()
+      : isolate(main_isolate()),
+        common(main_zone()),
+        graph(main_zone()),
+        jsgraph(&graph, &common, NULL, NULL),
+        start(graph.NewNode(common.Start(1))),
+        end(graph.NewNode(common.End(), start)),
+        p0(graph.NewNode(common.Parameter(0), start)),
+        zero(jsgraph.Int32Constant(0)),
+        one(jsgraph.OneConstant()),
+        half(jsgraph.Constant(0.5)),
+        self(graph.NewNode(common.Int32Constant(0xaabbccdd))),
+        dead(graph.NewNode(common.Dead())) {
+    graph.SetEnd(end);
+    graph.SetStart(start);
+    leaf[0] = zero;
+    leaf[1] = one;
+    leaf[2] = half;
+    leaf[3] = p0;
+  }
+
+  Isolate* isolate;
+  CommonOperatorBuilder common;
+  Graph graph;
+  JSGraph jsgraph;
+  Node* start;
+  Node* end;
+  Node* p0;
+  Node* zero;
+  Node* one;
+  Node* half;
+  Node* self;
+  Node* dead;
+  Node* leaf[kNumLeafs];
+
+  Node* Phi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, false), a, start));
+  }
+
+  Node* Phi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, false), a, b, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start));
+  }
+
+  Node* EffectPhi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, true), a, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, true), a, b, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start));
+  }
+
+  Node* SetSelfReferences(Node* node) {
+    for (Edge edge : node->input_edges()) {
+      if (edge.to() == self) node->ReplaceInput(edge.index(), node);
+    }
+    return node;
+  }
+
+  const Operator* op(int count, bool effect) {
+    return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count);
+  }
+
+  void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); }
+
+  void ReduceGraph() {
+    ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common);
+  }
+
+  // Checks one-step reduction of a phi.
+  void ReducePhi(Node* expect, Node* phi) {
+    Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi);
+    CHECK_EQ(expect, result);
+    ReducePhiIterative(expect, phi);  // iterative should give the same result.
+  }
+
+  void ReducePhiIterative(Node* expect, Node* phi) {
+    p0->ReplaceInput(0, start);  // hack: parameters may be trimmed.
+    Node* ret = graph.NewNode(common.Return(), phi, start, start);
+    Node* end = graph.NewNode(common.End(), ret);
+    graph.SetEnd(end);
+    ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common);
+    CheckInputs(end, ret);
+    CheckInputs(ret, expect, start, start);
+  }
+
+  void ReduceMerge(Node* expect, Node* merge) {
+    Node* result =
+        ControlReducer::ReduceMergeForTesting(&jsgraph, &common, merge);
+    CHECK_EQ(expect, result);
+  }
+
+  void ReduceMergeIterative(Node* expect, Node* merge) {
+    p0->ReplaceInput(0, start);  // hack: parameters may be trimmed.
+    Node* end = graph.NewNode(common.End(), merge);
+    graph.SetEnd(end);
+    ReduceGraph();
+    CheckInputs(end, expect);
+  }
+
+  void ReduceBranch(Node* expect, Node* branch) {
+    Node* result =
+        ControlReducer::ReduceBranchForTesting(&jsgraph, &common, branch);
+    CHECK_EQ(expect, result);
+  }
+
+  Node* Return(Node* val, Node* effect, Node* control) {
+    Node* ret = graph.NewNode(common.Return(), val, effect, control);
+    end->ReplaceInput(0, ret);
+    return ret;
+  }
+};
+
+
+TEST(Trim1_live) {
+  ControlReducerTester T;
+  CHECK(IsUsedBy(T.start, T.p0));
+  T.graph.SetEnd(T.p0);
+  T.Trim();
+  CHECK(IsUsedBy(T.start, T.p0));
+  CheckInputs(T.p0, T.start);
+}
+
+
+TEST(Trim1_dead) {
+  ControlReducerTester T;
+  CHECK(IsUsedBy(T.start, T.p0));
+  T.Trim();
+  CHECK(!IsUsedBy(T.start, T.p0));
+  CHECK_EQ(NULL, T.p0->InputAt(0));
+}
+
+
+TEST(Trim2_live) {
+  ControlReducerTester T;
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  T.graph.SetEnd(phi);
+  T.Trim();
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  CheckInputs(phi, T.one, T.half, T.start);
+}
+
+
+TEST(Trim2_dead) {
+  ControlReducerTester T;
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  T.Trim();
+  CHECK(!IsUsedBy(T.one, phi));
+  CHECK(!IsUsedBy(T.half, phi));
+  CHECK(!IsUsedBy(T.start, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+  CHECK_EQ(NULL, phi->InputAt(2));
+}
+
+
+TEST(Trim_chain1) {
+  ControlReducerTester T;
+  const int kDepth = 15;
+  Node* live[kDepth];
+  Node* dead[kDepth];
+  Node* end = T.start;
+  for (int i = 0; i < kDepth; i++) {
+    live[i] = end = T.graph.NewNode(T.common.Merge(1), end);
+    dead[i] = T.graph.NewNode(T.common.Merge(1), end);
+  }
+  // end         -> live[last] ->  live[last-1] -> ... -> start
+  //     dead[last] ^ dead[last-1] ^ ...                  ^
+  T.graph.SetEnd(end);
+  T.Trim();
+  for (int i = 0; i < kDepth; i++) {
+    CHECK(!IsUsedBy(live[i], dead[i]));
+    CHECK_EQ(NULL, dead[i]->InputAt(0));
+    CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
+  }
+}
+
+
+TEST(Trim_chain2) {
+  ControlReducerTester T;
+  const int kDepth = 15;
+  Node* live[kDepth];
+  Node* dead[kDepth];
+  Node* l = T.start;
+  Node* d = T.start;
+  for (int i = 0; i < kDepth; i++) {
+    live[i] = l = T.graph.NewNode(T.common.Merge(1), l);
+    dead[i] = d = T.graph.NewNode(T.common.Merge(1), d);
+  }
+  // end -> live[last] -> live[last-1] -> ... -> start
+  //        dead[last] -> dead[last-1] -> ... -> start
+  T.graph.SetEnd(l);
+  T.Trim();
+  CHECK(!IsUsedBy(T.start, dead[0]));
+  for (int i = 0; i < kDepth; i++) {
+    CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0));
+    CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
+  }
+}
+
+
+TEST(Trim_cycle1) {
+  ControlReducerTester T;
+  Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start);
+  loop->ReplaceInput(1, loop);
+  Node* end = T.graph.NewNode(T.common.End(), loop);
+  T.graph.SetEnd(end);
+
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+
+  T.Trim();
+
+  // nothing should have happened to the loop itself.
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CheckInputs(loop, T.start, loop);
+  CheckInputs(end, loop);
+}
+
+
+TEST(Trim_cycle2) {
+  ControlReducerTester T;
+  Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start);
+  loop->ReplaceInput(1, loop);
+  Node* end = T.graph.NewNode(T.common.End(), loop);
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop);
+  T.graph.SetEnd(end);
+
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CHECK(IsUsedBy(loop, phi));
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+
+  T.Trim();
+
+  // nothing should have happened to the loop itself.
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CheckInputs(loop, T.start, loop);
+  CheckInputs(end, loop);
+
+  // phi should have been trimmed away.
+  CHECK(!IsUsedBy(loop, phi));
+  CHECK(!IsUsedBy(T.one, phi));
+  CHECK(!IsUsedBy(T.half, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+  CHECK_EQ(NULL, phi->InputAt(2));
+}
+
+
+void CheckTrimConstant(ControlReducerTester* T, Node* k) {
+  Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start);
+  CHECK(IsUsedBy(k, phi));
+  T->Trim();
+  CHECK(!IsUsedBy(k, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+}
+
+
+TEST(Trim_constants) {
+  ControlReducerTester T;
+  int32_t int32_constants[] = {
+      0, -1,  -2,  2,  2,  3,  3,  4,  4,  5,  5,  4,  5,  6, 6, 7, 8, 7, 8, 9,
+      0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9};
+
+  for (size_t i = 0; i < arraysize(int32_constants); i++) {
+    CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i]));
+    CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i]));
+    CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i]));
+  }
+
+  Node* other_constants[] = {
+      T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(),
+      T.jsgraph.TrueConstant(),      T.jsgraph.FalseConstant(),
+      T.jsgraph.NullConstant(),      T.jsgraph.ZeroConstant(),
+      T.jsgraph.OneConstant(),       T.jsgraph.NaNConstant(),
+      T.jsgraph.Constant(21),        T.jsgraph.Constant(22.2)};
+
+  for (size_t i = 0; i < arraysize(other_constants); i++) {
+    CheckTrimConstant(&T, other_constants[i]);
+  }
+}
+
+
+TEST(CReducePhi1) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3]));
+}
+
+
+TEST(CReducePhi1_dead) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1], R.dead));
+  R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2], R.dead));
+  R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3], R.dead));
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.Phi(R.dead, R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.Phi(R.dead, R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.Phi(R.dead, R.leaf[3]));
+}
+
+
+TEST(CReducePhi1_dead2) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead, R.dead));
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.dead, R.leaf[0]));
+}
+
+
+TEST(CReducePhi2a) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a));
+  }
+}
+
+
+TEST(CReducePhi2b) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a));
+    R.ReducePhi(a, R.Phi(a, R.self));
+  }
+}
+
+
+TEST(CReducePhi2c) {
+  ControlReducerTester R;
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b);
+    R.ReducePhi(phi2, phi2);
+  }
+}
+
+
+TEST(CReducePhi2_dead) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, R.dead));
+    R.ReducePhi(a, R.Phi(a, R.dead, a));
+    R.ReducePhi(a, R.Phi(R.dead, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a));
+    R.ReducePhi(a, R.Phi(a, R.self));
+    R.ReducePhi(a, R.Phi(R.self, a, R.dead));
+    R.ReducePhi(a, R.Phi(a, R.self, R.dead));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, R.dead);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, R.dead);
+    R.ReducePhi(phi2, phi2);
+  }
+}
+
+
+TEST(CReducePhi3) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, a);
+    R.ReducePhi(phi2, phi2);
+
+    Node* phi3 = R.Phi(a, a, b);
+    R.ReducePhi(phi3, phi3);
+  }
+}
+
+
+TEST(CReducePhi4) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, a, R.self));
+
+    R.ReducePhi(a, R.Phi(R.self, R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self, R.self));
+    R.ReducePhi(a, R.Phi(R.self, a, a, R.self));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, a, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, a, a);
+    R.ReducePhi(phi2, phi2);
+
+    Node* phi3 = R.Phi(a, a, b, a);
+    R.ReducePhi(phi3, phi3);
+
+    Node* phi4 = R.Phi(a, a, a, b);
+    R.ReducePhi(phi4, phi4);
+  }
+}
+
+
+TEST(CReducePhi_iterative1) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0])));
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative2) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.Phi(R.leaf[0])));
+}
+
+
+TEST(CReducePhi_iterative3) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0],
+                       R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.leaf[0])));
+  R.ReducePhiIterative(R.leaf[0],
+                       R.Phi(R.Phi(R.leaf[0], R.leaf[0]), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative4) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.leaf[0]),
+                                        R.Phi(R.leaf[0], R.leaf[0])));
+
+  Node* p1 = R.Phi(R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1));
+
+  Node* p2 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2, p2));
+
+  Node* p3 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p3, p3, R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative_self1) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.self)));
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative_self2) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(
+      R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.Phi(R.leaf[0], R.self)));
+  R.ReducePhiIterative(
+      R.leaf[0], R.Phi(R.Phi(R.self, R.leaf[0]), R.Phi(R.self, R.leaf[0])));
+
+  Node* p1 = R.Phi(R.leaf[0], R.self);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1));
+
+  Node* p2 = R.Phi(R.self, R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2));
+}
+
+
+TEST(EReducePhi1) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3]));
+}
+
+
+TEST(EReducePhi1_dead) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1], R.dead));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2], R.dead));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3], R.dead));
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.dead, R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.dead, R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.dead, R.leaf[3]));
+}
+
+
+TEST(EReducePhi1_dead2) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead, R.dead));
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.dead, R.leaf[0]));
+}
+
+
+TEST(CMergeReduce_simple1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+  R.ReduceMerge(R.start, merge);
+}
+
+
+TEST(CMergeReduce_simple2) {
+  ControlReducerTester R;
+
+  Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start);
+  Node* merge2 = R.graph.NewNode(R.common.Merge(1), merge1);
+  R.ReduceMerge(merge1, merge2);
+  R.ReduceMergeIterative(R.start, merge2);
+}
+
+
+TEST(CMergeReduce_none1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.start);
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_none2) {
+  ControlReducerTester R;
+
+  Node* t = R.graph.NewNode(R.common.IfTrue(), R.start);
+  Node* f = R.graph.NewNode(R.common.IfFalse(), R.start);
+  Node* merge = R.graph.NewNode(R.common.Merge(2), t, f);
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_self3) {
+  ControlReducerTester R;
+
+  Node* merge =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Merge(2), R.start, R.self));
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_dead1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.dead);
+  R.ReduceMerge(R.start, merge);
+}
+
+
+TEST(CMergeReduce_dead2) {
+  ControlReducerTester R;
+
+  Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start);
+  Node* merge2 = R.graph.NewNode(R.common.Merge(2), merge1, R.dead);
+  R.ReduceMerge(merge1, merge2);
+  R.ReduceMergeIterative(R.start, merge2);
+}
+
+
+TEST(CMergeReduce_dead_rm1a) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    R.ReduceMerge(merge, merge);
+    CheckMerge(merge, R.start, R.start);
+  }
+}
+
+
+TEST(CMergeReduce_dead_rm1b) {
+  ControlReducerTester R;
+
+  Node* t = R.graph.NewNode(R.common.IfTrue(), R.start);
+  Node* f = R.graph.NewNode(R.common.IfFalse(), R.start);
+  for (int i = 0; i < 2; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead);
+    for (int j = i + 1; j < 3; j++) {
+      merge->ReplaceInput(i, t);
+      merge->ReplaceInput(j, f);
+      R.ReduceMerge(merge, merge);
+      CheckMerge(merge, t, f);
+    }
+  }
+}
+
+
+TEST(CMergeReduce_dead_rm2) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead);
+    merge->ReplaceInput(i, R.start);
+    R.ReduceMerge(R.start, merge);
+  }
+}
+
+
+TEST(CLoopReduce_dead_rm1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* loop = R.graph.NewNode(R.common.Loop(3), R.dead, R.start, R.start);
+    R.ReduceMerge(loop, loop);
+    CheckLoop(loop, R.start, R.start);
+  }
+}
+
+
+TEST(CMergeReduce_edit_phi1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0],
+                                R.leaf[1], R.leaf[2], merge);
+    R.ReduceMerge(merge, merge);
+    CHECK_EQ(IrOpcode::kPhi, phi->opcode());
+    CHECK_EQ(2, phi->op()->ValueInputCount());
+    CHECK_EQ(3, phi->InputCount());
+    CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+    CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+    CHECK_EQ(merge, phi->InputAt(2));
+  }
+}
+
+
+TEST(CMergeReduce_edit_effect_phi1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    Node* phi = R.graph.NewNode(R.common.EffectPhi(3), R.leaf[0], R.leaf[1],
+                                R.leaf[2], merge);
+    R.ReduceMerge(merge, merge);
+    CHECK_EQ(IrOpcode::kEffectPhi, phi->opcode());
+    CHECK_EQ(0, phi->op()->ValueInputCount());
+    CHECK_EQ(2, phi->op()->EffectInputCount());
+    CHECK_EQ(3, phi->InputCount());
+    CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+    CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+    CHECK_EQ(merge, phi->InputAt(2));
+  }
+}
+
+
+static const int kSelectorSize = 4;
+
+// Helper to select K of N nodes according to a mask, useful for the test below.
+struct Selector {
+  int mask;
+  int count;
+  explicit Selector(int m) {
+    mask = m;
+    count = v8::base::bits::CountPopulation32(m);
+  }
+  bool is_selected(int i) { return (mask & (1 << i)) != 0; }
+  void CheckNode(Node* node, IrOpcode::Value opcode, Node** inputs,
+                 Node* control) {
+    CHECK_EQ(opcode, node->opcode());
+    CHECK_EQ(count + (control != NULL ? 1 : 0), node->InputCount());
+    int index = 0;
+    for (int i = 0; i < kSelectorSize; i++) {
+      if (mask & (1 << i)) {
+        CHECK_EQ(inputs[i], node->InputAt(index++));
+      }
+    }
+    CHECK_EQ(count, index);
+    if (control != NULL) CHECK_EQ(control, node->InputAt(index++));
+  }
+  int single_index() {
+    CHECK_EQ(1, count);
+    return WhichPowerOf2(mask);
+  }
+};
+
+
+TEST(CMergeReduce_exhaustive_4) {
+  ControlReducerTester R;
+  Node* controls[] = {
+      R.graph.NewNode(R.common.Start(1)), R.graph.NewNode(R.common.Start(2)),
+      R.graph.NewNode(R.common.Start(3)), R.graph.NewNode(R.common.Start(4))};
+  Node* values[] = {R.jsgraph.Int32Constant(11), R.jsgraph.Int32Constant(22),
+                    R.jsgraph.Int32Constant(33), R.jsgraph.Int32Constant(44)};
+  Node* effects[] = {
+      R.jsgraph.Float64Constant(123.4), R.jsgraph.Float64Constant(223.4),
+      R.jsgraph.Float64Constant(323.4), R.jsgraph.Float64Constant(423.4)};
+
+  for (int mask = 0; mask < (1 << (kSelectorSize - 1)); mask++) {
+    // Reduce a single merge with a given mask.
+    Node* merge = R.graph.NewNode(R.common.Merge(4), controls[0], controls[1],
+                                  controls[2], controls[3]);
+    Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 4), values[0],
+                                values[1], values[2], values[3], merge);
+    Node* ephi = R.graph.NewNode(R.common.EffectPhi(4), effects[0], effects[1],
+                                 effects[2], effects[3], merge);
+
+    Node* phi_use =
+        R.graph.NewNode(R.common.Phi(kMachAnyTagged, 1), phi, R.start);
+    Node* ephi_use = R.graph.NewNode(R.common.EffectPhi(1), ephi, R.start);
+
+    Selector selector(mask);
+
+    for (int i = 0; i < kSelectorSize; i++) {  // set up dead merge inputs.
+      if (!selector.is_selected(i)) merge->ReplaceInput(i, R.dead);
+    }
+
+    Node* result =
+        ControlReducer::ReduceMergeForTesting(&R.jsgraph, &R.common, merge);
+
+    int count = selector.count;
+    if (count == 0) {
+      // result should be dead.
+      CHECK_EQ(IrOpcode::kDead, result->opcode());
+    } else if (count == 1) {
+      // merge should be replaced with one of the controls.
+      CHECK_EQ(controls[selector.single_index()], result);
+      // Phis should have been directly replaced.
+      CHECK_EQ(values[selector.single_index()], phi_use->InputAt(0));
+      CHECK_EQ(effects[selector.single_index()], ephi_use->InputAt(0));
+    } else {
+      // Otherwise, nodes should be edited in place.
+      CHECK_EQ(merge, result);
+      selector.CheckNode(merge, IrOpcode::kMerge, controls, NULL);
+      selector.CheckNode(phi, IrOpcode::kPhi, values, merge);
+      selector.CheckNode(ephi, IrOpcode::kEffectPhi, effects, merge);
+      CHECK_EQ(phi, phi_use->InputAt(0));
+      CHECK_EQ(ephi, ephi_use->InputAt(0));
+      CHECK_EQ(count, phi->op()->ValueInputCount());
+      CHECK_EQ(count + 1, phi->InputCount());
+      CHECK_EQ(count, ephi->op()->EffectInputCount());
+      CHECK_EQ(count + 1, ephi->InputCount());
+    }
+  }
+}
+
+
+TEST(CMergeReduce_edit_many_phis1) {
+  ControlReducerTester R;
+
+  const int kPhiCount = 10;
+  Node* phis[kPhiCount];
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    for (int j = 0; j < kPhiCount; j++) {
+      phis[j] = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0],
+                                R.leaf[1], R.leaf[2], merge);
+    }
+    R.ReduceMerge(merge, merge);
+    for (int j = 0; j < kPhiCount; j++) {
+      Node* phi = phis[j];
+      CHECK_EQ(IrOpcode::kPhi, phi->opcode());
+      CHECK_EQ(2, phi->op()->ValueInputCount());
+      CHECK_EQ(3, phi->InputCount());
+      CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+      CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+      CHECK_EQ(merge, phi->InputAt(2));
+    }
+  }
+}
+
+
+TEST(CMergeReduce_simple_chain1) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(1), merge);
+    }
+    R.ReduceMergeIterative(R.start, merge);
+  }
+}
+
+
+TEST(CMergeReduce_dead_chain1) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.dead);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(1), merge);
+    }
+    Node* end = R.graph.NewNode(R.common.End(), merge);
+    R.graph.SetEnd(end);
+    R.ReduceGraph();
+    CHECK(merge->IsDead());
+    CHECK_EQ(NULL, end->InputAt(0));  // end dies.
+  }
+}
+
+
+TEST(CMergeReduce_dead_chain2) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(2), merge, R.dead);
+    }
+    R.ReduceMergeIterative(R.start, merge);
+  }
+}
+
+
+struct Branch {
+  Node* branch;
+  Node* if_true;
+  Node* if_false;
+
+  Branch(ControlReducerTester& R, Node* cond, Node* control = NULL) {
+    if (control == NULL) control = R.start;
+    branch = R.graph.NewNode(R.common.Branch(), cond, control);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+  }
+};
+
+
+// TODO(titzer): use the diamonds from src/compiler/diamond.h here.
+struct Diamond {
+  Node* branch;
+  Node* if_true;
+  Node* if_false;
+  Node* merge;
+  Node* phi;
+
+  Diamond(ControlReducerTester& R, Node* cond) {
+    branch = R.graph.NewNode(R.common.Branch(), cond, R.start);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+    merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
+    phi = NULL;
+  }
+
+  Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) {
+    branch = R.graph.NewNode(R.common.Branch(), cond, R.start);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+    merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
+    phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge);
+  }
+
+  void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); }
+
+  // Nest {this} into either the if_true or if_false branch of {that}.
+  void nest(Diamond& that, bool if_true) {
+    if (if_true) {
+      branch->ReplaceInput(1, that.if_true);
+      that.merge->ReplaceInput(0, merge);
+    } else {
+      branch->ReplaceInput(1, that.if_false);
+      that.merge->ReplaceInput(1, merge);
+    }
+  }
+};
+
+
+struct While {
+  Node* branch;
+  Node* if_true;
+  Node* exit;
+  Node* loop;
+
+  While(ControlReducerTester& R, Node* cond) {
+    loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+    branch = R.graph.NewNode(R.common.Branch(), cond, loop);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    exit = R.graph.NewNode(R.common.IfFalse(), branch);
+    loop->ReplaceInput(1, if_true);
+  }
+
+  void chain(Node* control) { loop->ReplaceInput(0, control); }
+};
+
+
+TEST(CBranchReduce_none1) {
+  ControlReducerTester R;
+  Diamond d(R, R.p0);
+  R.ReduceBranch(d.branch, d.branch);
+}
+
+
+TEST(CBranchReduce_none2) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0);
+  Diamond d2(R, R.p0);
+  d2.chain(d1);
+  R.ReduceBranch(d2.branch, d2.branch);
+}
+
+
+TEST(CBranchReduce_true) {
+  ControlReducerTester R;
+  Node* true_values[] = {
+      R.one,                               R.jsgraph.Int32Constant(2),
+      R.jsgraph.Int32Constant(0x7fffffff), R.jsgraph.Constant(1.0),
+      R.jsgraph.Constant(22.1),            R.jsgraph.TrueConstant()};
+
+  for (size_t i = 0; i < arraysize(true_values); i++) {
+    Diamond d(R, true_values[i]);
+    Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true);
+    Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false);
+    R.ReduceBranch(R.start, d.branch);
+    CHECK_EQ(R.start, true_use->InputAt(0));
+    CHECK_EQ(IrOpcode::kDead, false_use->InputAt(0)->opcode());
+    CHECK(d.if_true->IsDead());   // replaced
+    CHECK(d.if_false->IsDead());  // replaced
+  }
+}
+
+
+TEST(CBranchReduce_false) {
+  ControlReducerTester R;
+  Node* false_values[] = {R.zero, R.jsgraph.Constant(0.0),
+                          R.jsgraph.Constant(-0.0), R.jsgraph.FalseConstant()};
+
+  for (size_t i = 0; i < arraysize(false_values); i++) {
+    Diamond d(R, false_values[i]);
+    Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true);
+    Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false);
+    R.ReduceBranch(R.start, d.branch);
+    CHECK_EQ(R.start, false_use->InputAt(0));
+    CHECK_EQ(IrOpcode::kDead, true_use->InputAt(0)->opcode());
+    CHECK(d.if_true->IsDead());   // replaced
+    CHECK(d.if_false->IsDead());  // replaced
+  }
+}
+
+
+TEST(CDiamondReduce_true) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CDiamondReduce_false) {
+  ControlReducerTester R;
+  Diamond d2(R, R.zero);
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_x_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0);
+  Diamond d2(R, R.zero);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d1.merge, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_false_x) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero);
+  Diamond d2(R, R.p0);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d2.merge, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+}
+
+
+TEST(CChainedDiamondsReduce_phi1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero, R.one, R.zero);  // foldable branch, phi.
+  Diamond d2(R, d1.phi);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_phi2) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0, R.one, R.one);  // redundant phi.
+  Diamond d2(R, d1.phi);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d1.merge, d2.merge);
+}
+
+
+TEST(CNestedDiamondsReduce_true_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.nest(d1, true);
+
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CNestedDiamondsReduce_false_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.nest(d1, false);
+
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CNestedDiamonds_xyz) {
+  ControlReducerTester R;
+
+  for (int a = 0; a < 2; a++) {
+    for (int b = 0; b < 2; b++) {
+      for (int c = 0; c < 2; c++) {
+        Diamond d1(R, R.jsgraph.Int32Constant(a));
+        Diamond d2(R, R.jsgraph.Int32Constant(b));
+        d2.nest(d1, c);
+
+        R.ReduceMergeIterative(R.start, d1.merge);
+      }
+    }
+  }
+}
+
+
+TEST(CDeadLoop1) {
+  ControlReducerTester R;
+
+  Node* loop = R.graph.NewNode(R.common.Loop(1), R.start);
+  Branch b(R, R.p0, loop);
+  loop->ReplaceInput(0, b.if_true);  // loop is not connected to start.
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, b.if_false);
+  R.ReduceMergeIterative(R.start, merge);
+  CHECK(b.if_true->IsDead());
+  CHECK(b.if_false->IsDead());
+}
+
+
+TEST(CDeadLoop2) {
+  ControlReducerTester R;
+
+  While w(R, R.p0);
+  Diamond d(R, R.zero);
+  // if (0) { while (p0) ; } else { }
+  w.branch->ReplaceInput(1, d.if_true);
+  d.merge->ReplaceInput(0, w.exit);
+
+  R.ReduceMergeIterative(R.start, d.merge);
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+}
+
+
+TEST(CNonTermLoop1) {
+  ControlReducerTester R;
+  Node* loop =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Loop(2), R.start, R.self));
+  R.ReduceGraph();
+  Node* end = R.graph.end();
+  CheckLoop(loop, R.start, loop);
+  Node* merge = end->InputAt(0);
+  CheckMerge(merge, R.start, loop);
+}
+
+
+TEST(CNonTermLoop2) {
+  ControlReducerTester R;
+  Diamond d(R, R.p0);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), d.if_false, R.self));
+  d.merge->ReplaceInput(1, R.dead);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, d.merge);
+  R.ReduceGraph();
+  CHECK_EQ(end, R.graph.end());
+  CheckLoop(loop, d.if_false, loop);
+  Node* merge = end->InputAt(0);
+  CheckMerge(merge, d.if_true, loop);
+}
+
+
+TEST(NonTermLoop3) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CHECK_EQ(end, R.graph.end());
+  CheckInputs(end, loop);
+  CheckInputs(loop, R.start, loop);
+}
+
+
+TEST(CNonTermLoop_terminate1) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Node* effect = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CHECK_EQ(end, R.graph.end());
+  CheckLoop(loop, R.start, loop);
+  Node* terminate = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(2, terminate->InputCount());
+  CHECK_EQ(1, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  CheckInputs(terminate, effect, loop);
+}
+
+
+TEST(CNonTermLoop_terminate2) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Node* effect1 = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Node* effect2 = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CheckLoop(loop, R.start, loop);
+  CHECK_EQ(end, R.graph.end());
+  Node* terminate = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(3, terminate->InputCount());
+  CHECK_EQ(2, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  Node* e0 = terminate->InputAt(0);
+  Node* e1 = terminate->InputAt(1);
+  CHECK(e0 == effect1 || e1 == effect1);
+  CHECK(e0 == effect2 || e1 == effect2);
+  CHECK_EQ(loop, terminate->InputAt(2));
+}
+
+
+TEST(CNonTermLoop_terminate_m1) {
+  ControlReducerTester R;
+  Node* loop =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Loop(2), R.start, R.self));
+  Node* effect = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  R.ReduceGraph();
+  Node* end = R.graph.end();
+  CHECK_EQ(R.start, loop->InputAt(0));
+  CHECK_EQ(loop, loop->InputAt(1));
+  Node* merge = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kMerge, merge->opcode());
+  CHECK_EQ(2, merge->InputCount());
+  CHECK_EQ(2, merge->op()->ControlInputCount());
+  CHECK_EQ(R.start, merge->InputAt(0));
+
+  Node* terminate = merge->InputAt(1);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(2, terminate->InputCount());
+  CHECK_EQ(1, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  CHECK_EQ(effect, terminate->InputAt(0));
+  CHECK_EQ(loop, terminate->InputAt(1));
+}
+
+
+TEST(CNonTermLoop_big1) {
+  ControlReducerTester R;
+  Branch b1(R, R.p0);
+  Node* rt = R.graph.NewNode(R.common.Return(), R.one, R.start, b1.if_true);
+
+  Branch b2(R, R.p0, b1.if_false);
+  Node* rf = R.graph.NewNode(R.common.Return(), R.zero, R.start, b2.if_true);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), b2.if_false, R.self));
+  Node* merge = R.graph.NewNode(R.common.Merge(2), rt, rf);
+  R.end->ReplaceInput(0, merge);
+
+  R.ReduceGraph();
+
+  CheckInputs(R.end, merge);
+  CheckInputs(merge, rt, rf, loop);
+  CheckInputs(loop, b2.if_false, loop);
+}
+
+
+TEST(CNonTermLoop_big2) {
+  ControlReducerTester R;
+  Branch b1(R, R.p0);
+  Node* rt = R.graph.NewNode(R.common.Return(), R.one, R.start, b1.if_true);
+
+  Branch b2(R, R.zero, b1.if_false);
+  Node* rf = R.graph.NewNode(R.common.Return(), R.zero, R.start, b2.if_true);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), b2.if_false, R.self));
+  Node* merge = R.graph.NewNode(R.common.Merge(2), rt, rf);
+  R.end->ReplaceInput(0, merge);
+
+  R.ReduceGraph();
+
+  Node* new_merge = R.end->InputAt(0);  // old merge was reduced.
+  CHECK_NE(merge, new_merge);
+  CheckInputs(new_merge, rt, loop);
+  CheckInputs(loop, b1.if_false, loop);
+  CHECK(merge->IsDead());
+  CHECK(rf->IsDead());
+  CHECK(b2.if_true->IsDead());
+}
+
+
+TEST(Return1) {
+  ControlReducerTester R;
+  Node* ret = R.Return(R.one, R.start, R.start);
+  R.ReduceGraph();
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.one, R.start, R.start);
+}
+
+
+TEST(Return2) {
+  ControlReducerTester R;
+  Diamond d(R, R.one);
+  Node* ret = R.Return(R.half, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+TEST(Return_true1) {
+  ControlReducerTester R;
+  Diamond d(R, R.one, R.half, R.zero);
+  Node* ret = R.Return(d.phi, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  CHECK(d.phi->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+TEST(Return_false1) {
+  ControlReducerTester R;
+  Diamond d(R, R.zero, R.one, R.half);
+  Node* ret = R.Return(d.phi, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  CHECK(d.phi->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+void CheckDeadDiamond(Diamond& d) {
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  if (d.phi != NULL) CHECK(d.phi->IsDead());
+}
+
+
+void CheckLiveDiamond(Diamond& d, bool live_phi = true) {
+  CheckInputs(d.merge, d.if_true, d.if_false);
+  CheckInputs(d.if_true, d.branch);
+  CheckInputs(d.if_false, d.branch);
+  if (d.phi != NULL) {
+    if (live_phi) {
+      CHECK_EQ(3, d.phi->InputCount());
+      CHECK_EQ(d.merge, d.phi->InputAt(2));
+    } else {
+      CHECK(d.phi->IsDead());
+    }
+  }
+}
+
+
+TEST(Return_effect1) {
+  ControlReducerTester R;
+  Diamond d(R, R.one);
+  Node* e1 = R.jsgraph.Float64Constant(-100.1);
+  Node* e2 = R.jsgraph.Float64Constant(+100.1);
+  Node* effect = R.graph.NewNode(R.common.EffectPhi(2), e1, e2, d.merge);
+  Node* ret = R.Return(R.p0, effect, d.merge);
+  R.ReduceGraph();
+  CheckDeadDiamond(d);
+  CHECK(effect->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.p0, e1, R.start);
+}
+
+
+TEST(Return_nested_diamonds1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // nothing should happen.
+
+  CheckInputs(ret, d1.phi, R.start, d1.merge);
+  CheckInputs(d1.phi, R.one, R.zero, d1.merge);
+  CheckInputs(d1.merge, d2.merge, d3.merge);
+  CheckLiveDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, R.one, R.start, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckLiveDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_false1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded false.
+
+  CheckInputs(ret, R.zero, R.start, d3.merge);
+  CheckInputs(d3.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_true1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.one);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 and d2 both get folded true.
+
+  CheckInputs(ret, R.one, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_false1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.zero);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true and d2 gets folded false.
+
+  CheckInputs(ret, R.one, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.p0, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.p0, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // nothing should happen.
+
+  CheckInputs(ret, d1.phi, R.start, d1.merge);
+  CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge);
+  CheckInputs(d1.merge, d2.merge, d3.merge);
+  CheckLiveDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.p0, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, d2.phi, R.start, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckLiveDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_true2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.one, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, x2, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_false2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.zero, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, y2, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
diff --git a/test/cctest/compiler/test-gap-resolver.cc b/test/cctest/compiler/test-gap-resolver.cc
index 6239f2a..ea6f4ee 100644
--- a/test/cctest/compiler/test-gap-resolver.cc
+++ b/test/cctest/compiler/test-gap-resolver.cc
@@ -58,13 +58,16 @@
     return Value(op->kind(), op->index());
   }
 
-  friend OStream& operator<<(OStream& os, const InterpreterState& is) {
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const InterpreterState& is) {
     for (OperandMap::const_iterator it = is.values_.begin();
          it != is.values_.end(); ++it) {
       if (it != is.values_.begin()) os << " ";
       InstructionOperand source(it->first.first, it->first.second);
       InstructionOperand destination(it->second.first, it->second.second);
-      os << MoveOperands(&source, &destination);
+      MoveOperands mo(&source, &destination);
+      PrintableMoveOperands pmo = {RegisterConfiguration::ArchDefault(), &mo};
+      os << pmo;
     }
     return os;
   }
diff --git a/test/cctest/compiler/test-graph-reducer.cc b/test/cctest/compiler/test-graph-reducer.cc
index eabfd22..70b57b9 100644
--- a/test/cctest/compiler/test-graph-reducer.cc
+++ b/test/cctest/compiler/test-graph-reducer.cc
@@ -5,7 +5,6 @@
 #include "src/v8.h"
 
 #include "graph-tester.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph-reducer.h"
 
 using namespace v8::internal;
@@ -21,15 +20,15 @@
 const uint8_t OPCODE_C1 = 31;
 const uint8_t OPCODE_C2 = 32;
 
-static SimpleOperator OPA0(OPCODE_A0, Operator::kNoWrite, 0, 0, "opa0");
-static SimpleOperator OPA1(OPCODE_A1, Operator::kNoWrite, 1, 0, "opa1");
-static SimpleOperator OPA2(OPCODE_A2, Operator::kNoWrite, 2, 0, "opa2");
-static SimpleOperator OPB0(OPCODE_B0, Operator::kNoWrite, 0, 0, "opa0");
-static SimpleOperator OPB1(OPCODE_B1, Operator::kNoWrite, 1, 0, "opa1");
-static SimpleOperator OPB2(OPCODE_B2, Operator::kNoWrite, 2, 0, "opa2");
-static SimpleOperator OPC0(OPCODE_C0, Operator::kNoWrite, 0, 0, "opc0");
-static SimpleOperator OPC1(OPCODE_C1, Operator::kNoWrite, 1, 0, "opc1");
-static SimpleOperator OPC2(OPCODE_C2, Operator::kNoWrite, 2, 0, "opc2");
+static Operator OPA0(OPCODE_A0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0);
+static Operator OPA1(OPCODE_A1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0);
+static Operator OPA2(OPCODE_A2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0);
+static Operator OPB0(OPCODE_B0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0);
+static Operator OPB1(OPCODE_B1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0);
+static Operator OPB2(OPCODE_B2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0);
+static Operator OPC0(OPCODE_C0, Operator::kNoWrite, "opc0", 0, 0, 0, 0, 0, 0);
+static Operator OPC1(OPCODE_C1, Operator::kNoWrite, "opc1", 1, 0, 0, 0, 0, 0);
+static Operator OPC2(OPCODE_C2, Operator::kNoWrite, "opc2", 2, 0, 0, 0, 0, 0);
 
 
 // Replaces all "A" operators with "B" operators without creating new nodes.
@@ -202,7 +201,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   ReducerRecorder recorder(graph.zone());
   reducer.AddReducer(&recorder);
   reducer.ReduceGraph();
@@ -220,7 +219,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   ReducerRecorder recorder(graph.zone());
   reducer.AddReducer(&recorder);
   reducer.ReduceGraph();
@@ -238,7 +237,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   reducer.AddReducer(&r);
 
@@ -263,7 +262,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   reducer.AddReducer(&r);
 
@@ -293,7 +292,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   NewABReducer r(&graph);
   reducer.AddReducer(&r);
 
@@ -330,7 +329,7 @@
   graph.SetEnd(end);
   CHECK_EQ(1, graph.NodeCount());
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A0Wrapper r(&graph);
   reducer.AddReducer(&r);
 
@@ -352,7 +351,7 @@
   graph.SetEnd(end);
   CHECK_EQ(1, graph.NodeCount());
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   B0Wrapper r(&graph);
   reducer.AddReducer(&r);
 
@@ -379,7 +378,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A1Forwarder r;
   reducer.AddReducer(&r);
 
@@ -403,7 +402,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A1Forwarder r;
   reducer.AddReducer(&r);
 
@@ -434,7 +433,7 @@
     }
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     A1Forwarder r;
     reducer.AddReducer(&r);
 
@@ -458,7 +457,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   B1Forwarder f;
   reducer.AddReducer(&r);
@@ -501,7 +500,7 @@
 
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     reducer.AddReducer(&r);
 
     int before = graph.NodeCount();
@@ -560,7 +559,7 @@
 
         GenDAG(&graph, p3, p2, p1);
 
-        GraphReducer reducer(&graph);
+        GraphReducer reducer(&graph, graph.zone());
         AB2Sorter r1;
         A1Forwarder r2;
         InPlaceABReducer r3;
@@ -599,7 +598,7 @@
     Node* end = graph.NewNode(&OPA1, n1);
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     InPlaceABReducer abr;
     InPlaceBCReducer bcr;
     if (i == 0) {
@@ -621,41 +620,3 @@
     }
   }
 }
-
-
-// Tests that a reducer is only applied once.
-class OneTimeReducer : public Reducer {
- public:
-  OneTimeReducer(Reducer* reducer, Zone* zone)
-      : reducer_(reducer),
-        nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)) {}
-  virtual Reduction Reduce(Node* node) {
-    CHECK_EQ(0, static_cast<int>(nodes_.count(node)));
-    nodes_.insert(node);
-    return reducer_->Reduce(node);
-  }
-  Reducer* reducer_;
-  NodeSet nodes_;
-};
-
-
-TEST(OneTimeReduce1) {
-  GraphTester graph;
-
-  Node* n1 = graph.NewNode(&OPA0);
-  Node* end = graph.NewNode(&OPA1, n1);
-  graph.SetEnd(end);
-
-  GraphReducer reducer(&graph);
-  InPlaceABReducer r;
-  OneTimeReducer once(&r, graph.zone());
-  reducer.AddReducer(&once);
-
-  // Tests A* => B* with in-place updates. Should only be applied once.
-  int before = graph.NodeCount();
-  reducer.ReduceGraph();
-  CHECK_EQ(before, graph.NodeCount());
-  CHECK_EQ(&OPB0, n1->op());
-  CHECK_EQ(&OPB1, end->op());
-  CHECK_EQ(n1, end->InputAt(0));
-}
diff --git a/test/cctest/compiler/test-graph-visualizer.cc b/test/cctest/compiler/test-graph-visualizer.cc
new file mode 100644
index 0000000..ce3e6b7
--- /dev/null
+++ b/test/cctest/compiler/test-graph-visualizer.cc
@@ -0,0 +1,90 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/schedule.h"
+#include "src/compiler/scheduler.h"
+#include "src/compiler/verifier.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+TEST(NodeWithNullInputReachableFromEnd) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(0, NULL);
+  graph.SetEnd(phi);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullControlReachableFromEnd) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(1, NULL);
+  graph.SetEnd(phi);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullInputReachableFromStart) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(0, NULL);
+  graph.SetEnd(start);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullControlReachableFromStart) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* merge = graph.NewNode(common.Merge(2), start, start);
+  merge->ReplaceInput(1, NULL);
+  graph.SetEnd(merge);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
diff --git a/test/cctest/compiler/test-instruction.cc b/test/cctest/compiler/test-instruction.cc
index a9feaac..294812f 100644
--- a/test/cctest/compiler/test-instruction.cc
+++ b/test/cctest/compiler/test-instruction.cc
@@ -31,12 +31,11 @@
         graph(zone()),
         schedule(zone()),
         info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()),
-        linkage(&info),
+        linkage(zone(), &info),
         common(zone()),
+        machine(zone()),
         code(NULL) {}
 
-  ~InstructionTester() { delete code; }
-
   Isolate* isolate;
   Graph graph;
   Schedule schedule;
@@ -51,10 +50,12 @@
   void allocCode() {
     if (schedule.rpo_order()->size() == 0) {
       // Compute the RPO order.
-      Scheduler::ComputeSpecialRPO(&schedule);
+      Scheduler::ComputeSpecialRPO(main_zone(), &schedule);
       DCHECK(schedule.rpo_order()->size() > 0);
     }
-    code = new TestInstrSeq(&linkage, &graph, &schedule);
+    InstructionBlocks* instruction_blocks =
+        TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
+    code = new (main_zone()) TestInstrSeq(main_zone(), instruction_blocks);
   }
 
   Node* Int32Constant(int32_t val) {
@@ -81,10 +82,10 @@
     return node;
   }
 
-  int NewInstr(BasicBlock* block) {
+  int NewInstr() {
     InstructionCode opcode = static_cast<InstructionCode>(110);
     TestInstr* instr = TestInstr::New(zone(), opcode);
-    return code->AddInstruction(instr, block);
+    return code->AddInstruction(instr);
   }
 
   UnallocatedOperand* NewUnallocated(int vreg) {
@@ -93,6 +94,21 @@
     unallocated->set_virtual_register(vreg);
     return unallocated;
   }
+
+  InstructionBlock* BlockAt(BasicBlock* block) {
+    return code->InstructionBlockAt(block->GetRpoNumber());
+  }
+  BasicBlock* GetBasicBlock(int instruction_index) {
+    const InstructionBlock* block =
+        code->GetInstructionBlock(instruction_index);
+    return schedule.rpo_order()->at(block->rpo_number().ToSize());
+  }
+  int first_instruction_index(BasicBlock* block) {
+    return BlockAt(block)->first_instruction_index();
+  }
+  int last_instruction_index(BasicBlock* block) {
+    return BlockAt(block)->last_instruction_index();
+  }
 };
 
 
@@ -112,17 +128,16 @@
 
   R.allocCode();
 
-  CHECK_EQ(R.graph.NodeCount(), R.code->ValueCount());
-
   BasicBlockVector* blocks = R.schedule.rpo_order();
-  CHECK_EQ(static_cast<int>(blocks->size()), R.code->BasicBlockCount());
+  CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
 
   int index = 0;
   for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
        i++, index++) {
     BasicBlock* block = *i;
-    CHECK_EQ(block, R.code->BlockAt(index));
-    CHECK_EQ(-1, R.code->GetLoopEnd(block));
+    CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
+    CHECK_EQ(block->id().ToInt(), R.BlockAt(block)->id().ToInt());
+    CHECK_EQ(NULL, block->loop_end());
   }
 }
 
@@ -141,47 +156,47 @@
 
   R.allocCode();
 
-  R.code->StartBlock(b0);
-  int i0 = R.NewInstr(b0);
-  int i1 = R.NewInstr(b0);
-  R.code->EndBlock(b0);
-  R.code->StartBlock(b1);
-  int i2 = R.NewInstr(b1);
-  int i3 = R.NewInstr(b1);
-  int i4 = R.NewInstr(b1);
-  int i5 = R.NewInstr(b1);
-  R.code->EndBlock(b1);
-  R.code->StartBlock(b2);
-  int i6 = R.NewInstr(b2);
-  int i7 = R.NewInstr(b2);
-  int i8 = R.NewInstr(b2);
-  R.code->EndBlock(b2);
-  R.code->StartBlock(b3);
-  R.code->EndBlock(b3);
+  R.code->StartBlock(b0->GetRpoNumber());
+  int i0 = R.NewInstr();
+  int i1 = R.NewInstr();
+  R.code->EndBlock(b0->GetRpoNumber());
+  R.code->StartBlock(b1->GetRpoNumber());
+  int i2 = R.NewInstr();
+  int i3 = R.NewInstr();
+  int i4 = R.NewInstr();
+  int i5 = R.NewInstr();
+  R.code->EndBlock(b1->GetRpoNumber());
+  R.code->StartBlock(b2->GetRpoNumber());
+  int i6 = R.NewInstr();
+  int i7 = R.NewInstr();
+  int i8 = R.NewInstr();
+  R.code->EndBlock(b2->GetRpoNumber());
+  R.code->StartBlock(b3->GetRpoNumber());
+  R.code->EndBlock(b3->GetRpoNumber());
 
-  CHECK_EQ(b0, R.code->GetBasicBlock(i0));
-  CHECK_EQ(b0, R.code->GetBasicBlock(i1));
+  CHECK_EQ(b0, R.GetBasicBlock(i0));
+  CHECK_EQ(b0, R.GetBasicBlock(i1));
 
-  CHECK_EQ(b1, R.code->GetBasicBlock(i2));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i3));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i4));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i5));
+  CHECK_EQ(b1, R.GetBasicBlock(i2));
+  CHECK_EQ(b1, R.GetBasicBlock(i3));
+  CHECK_EQ(b1, R.GetBasicBlock(i4));
+  CHECK_EQ(b1, R.GetBasicBlock(i5));
 
-  CHECK_EQ(b2, R.code->GetBasicBlock(i6));
-  CHECK_EQ(b2, R.code->GetBasicBlock(i7));
-  CHECK_EQ(b2, R.code->GetBasicBlock(i8));
+  CHECK_EQ(b2, R.GetBasicBlock(i6));
+  CHECK_EQ(b2, R.GetBasicBlock(i7));
+  CHECK_EQ(b2, R.GetBasicBlock(i8));
 
-  CHECK_EQ(b0, R.code->GetBasicBlock(b0->first_instruction_index()));
-  CHECK_EQ(b0, R.code->GetBasicBlock(b0->last_instruction_index()));
+  CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
+  CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
 
-  CHECK_EQ(b1, R.code->GetBasicBlock(b1->first_instruction_index()));
-  CHECK_EQ(b1, R.code->GetBasicBlock(b1->last_instruction_index()));
+  CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
+  CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
 
-  CHECK_EQ(b2, R.code->GetBasicBlock(b2->first_instruction_index()));
-  CHECK_EQ(b2, R.code->GetBasicBlock(b2->last_instruction_index()));
+  CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
+  CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
 
-  CHECK_EQ(b3, R.code->GetBasicBlock(b3->first_instruction_index()));
-  CHECK_EQ(b3, R.code->GetBasicBlock(b3->last_instruction_index()));
+  CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
+  CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
 }
 
 
@@ -194,10 +209,10 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
@@ -221,17 +236,17 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   TestInstr* i1 = TestInstr::New(R.zone(), 102);
   TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
-  R.code->StartBlock(b1);
-  R.code->AddInstruction(i1, b1);
-  R.code->AddInstruction(g1, b1);
-  R.code->EndBlock(b1);
+  R.code->StartBlock(b1->GetRpoNumber());
+  R.code->AddInstruction(i1);
+  R.code->AddInstruction(g1);
+  R.code->EndBlock(b1->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
@@ -262,10 +277,10 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
diff --git a/test/cctest/compiler/test-js-constant-cache.cc b/test/cctest/compiler/test-js-constant-cache.cc
index eb0975e..8588f66 100644
--- a/test/cctest/compiler/test-js-constant-cache.cc
+++ b/test/cctest/compiler/test-js-constant-cache.cc
@@ -4,6 +4,7 @@
 
 #include "src/v8.h"
 
+#include "src/assembler.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/typer.h"
@@ -20,8 +21,8 @@
       : main_graph_(zone),
         main_common_(zone),
         main_javascript_(zone),
-        main_typer_(zone),
-        main_machine_() {}
+        main_typer_(&main_graph_, MaybeHandle<Context>()),
+        main_machine_(zone) {}
   Graph main_graph_;
   CommonOperatorBuilder main_common_;
   JSOperatorBuilder main_javascript_;
@@ -30,14 +31,19 @@
 };
 
 
+// TODO(dcarney): JSConstantCacheTester inherits from JSGraph???
 class JSConstantCacheTester : public HandleAndZoneScope,
                               public JSCacheTesterHelper,
                               public JSGraph {
  public:
   JSConstantCacheTester()
       : JSCacheTesterHelper(main_zone()),
-        JSGraph(&main_graph_, &main_common_, &main_javascript_, &main_typer_,
-                &main_machine_) {}
+        JSGraph(&main_graph_, &main_common_, &main_javascript_,
+                &main_machine_) {
+    main_graph_.SetStart(main_graph_.NewNode(common()->Start(0)));
+    main_graph_.SetEnd(main_graph_.NewNode(common()->End()));
+    main_typer_.Run();
+  }
 
   Type* upper(Node* node) { return NodeProperties::GetBounds(node).upper; }
 
@@ -227,7 +233,7 @@
   FOR_FLOAT64_INPUTS(i) {
     double value = *i;
     Node* node = T.Constant(value);
-    CHECK(T.upper(node)->Equals(Type::Of(value, T.main_zone())));
+    CHECK(T.upper(node)->Is(Type::Of(value, T.main_zone())));
   }
 }
 
@@ -289,3 +295,180 @@
 TEST(ExternalReferences) {
   // TODO(titzer): test canonicalization of external references.
 }
+
+
+static bool Contains(NodeVector* nodes, Node* n) {
+  for (size_t i = 0; i < nodes->size(); i++) {
+    if (nodes->at(i) == n) return true;
+  }
+  return false;
+}
+
+
+static void CheckGetCachedNodesContains(JSConstantCacheTester* T, Node* n) {
+  NodeVector nodes(T->main_zone());
+  T->GetCachedNodes(&nodes);
+  CHECK(Contains(&nodes, n));
+}
+
+
+TEST(JSGraph_GetCachedNodes1) {
+  JSConstantCacheTester T;
+  CheckGetCachedNodesContains(&T, T.TrueConstant());
+  CheckGetCachedNodesContains(&T, T.UndefinedConstant());
+  CheckGetCachedNodesContains(&T, T.TheHoleConstant());
+  CheckGetCachedNodesContains(&T, T.TrueConstant());
+  CheckGetCachedNodesContains(&T, T.FalseConstant());
+  CheckGetCachedNodesContains(&T, T.NullConstant());
+  CheckGetCachedNodesContains(&T, T.ZeroConstant());
+  CheckGetCachedNodesContains(&T, T.OneConstant());
+  CheckGetCachedNodesContains(&T, T.NaNConstant());
+}
+
+
+TEST(JSGraph_GetCachedNodes_int32) {
+  JSConstantCacheTester T;
+
+  int32_t constants[] = {0,  1,  1,   1,   1,   2,   3,   4,  11, 12, 13,
+                         14, 55, -55, -44, -33, -22, -11, 16, 16, 17, 17,
+                         18, 18, 19,  19,  20,  20,  21,  21, 22, 23, 24,
+                         25, 15, 30,  31,  45,  46,  47,  48};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Int32Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_float64) {
+  JSConstantCacheTester T;
+
+  double constants[] = {0,   11.1, 12.2,  13,    14,   55.5, -55.5, -44.4,
+                        -33, -22,  -11,   0,     11.1, 11.1, 12.3,  12.3,
+                        11,  11,   -33.3, -33.3, -22,  -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Float64Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_int64) {
+  JSConstantCacheTester T;
+
+  int32_t constants[] = {0,   11,  12, 13, 14, 55, -55, -44, -33,
+                         -22, -11, 16, 16, 17, 17, 18,  18,  19,
+                         19,  20,  20, 21, 21, 22, 23,  24,  25};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Int64Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_number) {
+  JSConstantCacheTester T;
+
+  double constants[] = {0,   11.1, 12.2,  13,    14,   55.5, -55.5, -44.4,
+                        -33, -22,  -11,   0,     11.1, 11.1, 12.3,  12.3,
+                        11,  11,   -33.3, -33.3, -22,  -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_external) {
+  JSConstantCacheTester T;
+
+  ExternalReference constants[] = {ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_one_half(),
+                                   ExternalReference::address_of_one_half(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_the_hole_nan(),
+                                   ExternalReference::address_of_one_half()};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.ExternalConstant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_together) {
+  JSConstantCacheTester T;
+
+  Node* constants[] = {
+      T.TrueConstant(),
+      T.UndefinedConstant(),
+      T.TheHoleConstant(),
+      T.TrueConstant(),
+      T.FalseConstant(),
+      T.NullConstant(),
+      T.ZeroConstant(),
+      T.OneConstant(),
+      T.NaNConstant(),
+      T.Int32Constant(0),
+      T.Int32Constant(1),
+      T.Int64Constant(-2),
+      T.Int64Constant(-4),
+      T.Float64Constant(0.9),
+      T.Float64Constant(V8_INFINITY),
+      T.Constant(0.99),
+      T.Constant(1.11),
+      T.ExternalConstant(ExternalReference::address_of_one_half())};
+
+  NodeVector nodes(T.main_zone());
+  T.GetCachedNodes(&nodes);
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    CHECK(Contains(&nodes, constants[i]));
+  }
+}
diff --git a/test/cctest/compiler/test-js-context-specialization.cc b/test/cctest/compiler/test-js-context-specialization.cc
index 47c660a..fb7bd94 100644
--- a/test/cctest/compiler/test-js-context-specialization.cc
+++ b/test/cctest/compiler/test-js-context-specialization.cc
@@ -7,7 +7,6 @@
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/source-position.h"
-#include "src/compiler/typer.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/function-tester.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
@@ -22,10 +21,9 @@
       : DirectGraphBuilder(new (main_zone()) Graph(main_zone())),
         common_(main_zone()),
         javascript_(main_zone()),
-        machine_(),
+        machine_(main_zone()),
         simplified_(main_zone()),
-        typer_(main_zone()),
-        jsgraph_(graph(), common(), &javascript_, &typer_, &machine_),
+        jsgraph_(graph(), common(), &javascript_, &machine_),
         info_(main_isolate(), main_zone()) {}
 
   Factory* factory() { return main_isolate()->factory(); }
@@ -40,7 +38,6 @@
   JSOperatorBuilder javascript_;
   MachineOperatorBuilder machine_;
   SimplifiedOperatorBuilder simplified_;
-  Typer typer_;
   JSGraph jsgraph_;
   CompilationInfo info_;
 };
@@ -95,8 +92,8 @@
     HeapObjectMatcher<Context> match(new_context_input);
     CHECK_EQ(*native, *match.Value().handle());
     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
-    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
-    CHECK_EQ(0, access.depth());
+    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
+    CHECK_EQ(0, static_cast<int>(access.depth()));
     CHECK_EQ(false, access.immutable());
   }
 
@@ -175,8 +172,8 @@
     HeapObjectMatcher<Context> match(new_context_input);
     CHECK_EQ(*native, *match.Value().handle());
     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
-    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
-    CHECK_EQ(0, access.depth());
+    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
+    CHECK_EQ(0, static_cast<int>(access.depth()));
     CHECK_EQ(false, access.immutable());
   }
 }
@@ -206,7 +203,7 @@
   JSContextSpecializer spec(t.info(), t.jsgraph(), const_context);
 
   {
-    // Check that SpecializeToContext() replaces values and forwards effects
+    // Check that specialization replaces values and forwards effects
     // correctly, and folds values from constant and non-constant contexts
     Node* effect_in = start;
     Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true),
@@ -232,8 +229,10 @@
     CheckEffectInput(effect_in, load);
     CheckEffectInput(load, effect_use);
 
-    // Perform the substitution on the entire graph.
-    spec.SpecializeToContext();
+    // Perform the reduction on the entire graph.
+    GraphReducer graph_reducer(t.graph(), t.main_zone());
+    graph_reducer.AddReducer(&spec);
+    graph_reducer.ReduceGraph();
 
     // Effects should have been forwarded (not replaced with a value).
     CheckEffectInput(effect_in, effect_use);
diff --git a/test/cctest/compiler/test-js-typed-lowering.cc b/test/cctest/compiler/test-js-typed-lowering.cc
index cf126c2..3023837 100644
--- a/test/cctest/compiler/test-js-typed-lowering.cc
+++ b/test/cctest/compiler/test-js-typed-lowering.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
-#include "test/cctest/cctest.h"
-
 #include "src/compiler/graph-inl.h"
+#include "src/compiler/js-graph.h"
 #include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/machine-operator.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/typer.h"
+#include "test/cctest/cctest.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
@@ -21,14 +21,15 @@
         binop(NULL),
         unop(NULL),
         javascript(main_zone()),
+        machine(main_zone()),
         simplified(main_zone()),
         common(main_zone()),
         graph(main_zone()),
-        typer(main_zone()),
+        typer(&graph, MaybeHandle<Context>()),
         context_node(NULL) {
-    typer.DecorateGraph(&graph);
-    Node* s = graph.NewNode(common.Start(num_parameters));
-    graph.SetStart(s);
+    graph.SetStart(graph.NewNode(common.Start(num_parameters)));
+    graph.SetEnd(graph.NewNode(common.End()));
+    typer.Run();
   }
 
   Isolate* isolate;
@@ -49,13 +50,14 @@
   }
 
   Node* UndefinedConstant() {
-    Unique<Object> unique =
-        Unique<Object>::CreateImmovable(isolate->factory()->undefined_value());
+    Unique<HeapObject> unique = Unique<HeapObject>::CreateImmovable(
+        isolate->factory()->undefined_value());
     return graph.NewNode(common.HeapConstant(unique));
   }
 
-  Node* HeapConstant(Handle<Object> constant) {
-    Unique<Object> unique = Unique<Object>::CreateUninitialized(constant);
+  Node* HeapConstant(Handle<HeapObject> constant) {
+    Unique<HeapObject> unique =
+        Unique<HeapObject>::CreateUninitialized(constant);
     return graph.NewNode(common.HeapConstant(unique));
   }
 
@@ -65,15 +67,16 @@
     Node* stack = graph.NewNode(common.StateValues(0));
 
     Node* state_node =
-        graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0), kIgnoreOutput),
+        graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0),
+                                        OutputFrameStateCombine::Ignore()),
                       parameters, locals, stack, context, UndefinedConstant());
 
     return state_node;
   }
 
   Node* reduce(Node* node) {
-    JSGraph jsgraph(&graph, &common, &javascript, &typer, &machine);
-    JSTypedLowering reducer(&jsgraph);
+    JSGraph jsgraph(&graph, &common, &javascript, &machine);
+    JSTypedLowering reducer(&jsgraph, main_zone());
     Reduction reduction = reducer.Reduce(node);
     if (reduction.Changed()) return reduction.replacement();
     return node;
@@ -164,17 +167,19 @@
 
 
 static Type* kInt32Types[] = {
-    Type::UnsignedSmall(),   Type::OtherSignedSmall(), Type::OtherUnsigned31(),
-    Type::OtherUnsigned32(), Type::OtherSigned32(),    Type::SignedSmall(),
-    Type::Signed32(),        Type::Unsigned32(),       Type::Integral32()};
+    Type::UnsignedSmall(),       Type::NegativeSigned32(),
+    Type::NonNegativeSigned32(), Type::SignedSmall(),
+    Type::Signed32(),            Type::Unsigned32(),
+    Type::Integral32()};
 
 
 static Type* kNumberTypes[] = {
-    Type::UnsignedSmall(),   Type::OtherSignedSmall(), Type::OtherUnsigned31(),
-    Type::OtherUnsigned32(), Type::OtherSigned32(),    Type::SignedSmall(),
-    Type::Signed32(),        Type::Unsigned32(),       Type::Integral32(),
-    Type::MinusZero(),       Type::NaN(),              Type::OtherNumber(),
-    Type::OrderedNumber(),   Type::Number()};
+    Type::UnsignedSmall(),       Type::NegativeSigned32(),
+    Type::NonNegativeSigned32(), Type::SignedSmall(),
+    Type::Signed32(),            Type::Unsigned32(),
+    Type::Integral32(),          Type::MinusZero(),
+    Type::NaN(),                 Type::OrderedNumber(),
+    Type::PlainNumber(),         Type::Number()};
 
 
 static Type* kJSTypes[] = {Type::Undefined(), Type::Null(),   Type::Boolean(),
@@ -260,16 +265,15 @@
 
 static void CheckToI32(Node* old_input, Node* new_input, bool is_signed) {
   Type* old_type = NodeProperties::GetBounds(old_input).upper;
+  Type* new_type = NodeProperties::GetBounds(new_input).upper;
   Type* expected_type = I32Type(is_signed);
+  CHECK(new_type->Is(expected_type));
   if (old_type->Is(expected_type)) {
     CHECK_EQ(old_input, new_input);
   } else if (new_input->opcode() == IrOpcode::kNumberConstant) {
-    CHECK(NodeProperties::GetBounds(new_input).upper->Is(expected_type));
     double v = OpParameter<double>(new_input);
     double e = static_cast<double>(is_signed ? FastD2I(v) : FastD2UI(v));
     CHECK_EQ(e, v);
-  } else {
-    CHECK_EQ(NumberToI32(is_signed), new_input->opcode());
   }
 }
 
@@ -302,12 +306,13 @@
 TEST(Int32BitwiseShifts) {
   JSBitwiseShiftTypedLoweringTester R;
 
-  Type* types[] = {
-      Type::SignedSmall(), Type::UnsignedSmall(), Type::OtherSigned32(),
-      Type::Unsigned32(),  Type::Signed32(),      Type::MinusZero(),
-      Type::NaN(),         Type::OtherNumber(),   Type::Undefined(),
-      Type::Null(),        Type::Boolean(),       Type::Number(),
-      Type::String(),      Type::Object()};
+  Type* types[] = {Type::SignedSmall(),      Type::UnsignedSmall(),
+                   Type::NegativeSigned32(), Type::NonNegativeSigned32(),
+                   Type::Unsigned32(),       Type::Signed32(),
+                   Type::MinusZero(),        Type::NaN(),
+                   Type::Undefined(),        Type::Null(),
+                   Type::Boolean(),          Type::Number(),
+                   Type::PlainNumber(),      Type::String()};
 
   for (size_t i = 0; i < arraysize(types); ++i) {
     Node* p0 = R.Parameter(types[i], 0);
@@ -325,9 +330,13 @@
 
         CheckToI32(p0, r0, R.signedness[k]);
 
-        R.CheckPureBinop(IrOpcode::kWord32And, r1);
-        CheckToI32(p1, r1->InputAt(0), R.signedness[k + 1]);
-        R.CheckInt32Constant(0x1F, r1->InputAt(1));
+        if (r1->opcode() == IrOpcode::kWord32And) {
+          R.CheckPureBinop(IrOpcode::kWord32And, r1);
+          CheckToI32(p1, r1->InputAt(0), R.signedness[k + 1]);
+          R.CheckInt32Constant(0x1F, r1->InputAt(1));
+        } else {
+          CheckToI32(p1, r1, R.signedness[k]);
+        }
       }
     }
   }
@@ -363,11 +372,11 @@
   JSBitwiseTypedLoweringTester R;
 
   Type* types[] = {
-      Type::SignedSmall(), Type::UnsignedSmall(), Type::OtherSigned32(),
-      Type::Unsigned32(),  Type::Signed32(),      Type::MinusZero(),
-      Type::NaN(),         Type::OtherNumber(),   Type::Undefined(),
-      Type::Null(),        Type::Boolean(),       Type::Number(),
-      Type::String(),      Type::Object()};
+      Type::SignedSmall(),   Type::UnsignedSmall(), Type::Unsigned32(),
+      Type::Signed32(),      Type::MinusZero(),     Type::NaN(),
+      Type::OrderedNumber(), Type::PlainNumber(),   Type::Undefined(),
+      Type::Null(),          Type::Boolean(),       Type::Number(),
+      Type::String()};
 
   for (size_t i = 0; i < arraysize(types); ++i) {
     Node* p0 = R.Parameter(types[i], 0);
@@ -498,20 +507,6 @@
     CHECK_EQ(IrOpcode::kParameter, r->opcode());
   }
 
-  {  // ToBoolean(ordered-number)
-    Node* r = R.ReduceUnop(op, Type::OrderedNumber());
-    CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-    Node* i = r->InputAt(0);
-    CHECK_EQ(IrOpcode::kNumberEqual, i->opcode());
-    // ToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
-  }
-
-  {  // ToBoolean(string)
-    Node* r = R.ReduceUnop(op, Type::String());
-    // TODO(titzer): test will break with better js-typed-lowering
-    CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-  }
-
   {  // ToBoolean(object)
     Node* r = R.ReduceUnop(op, Type::DetectableObject());
     R.CheckTrue(r);
@@ -524,39 +519,7 @@
 
   {  // ToBoolean(object)
     Node* r = R.ReduceUnop(op, Type::Object());
-    CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-  }
-}
-
-
-TEST(JSToBoolean_replacement) {
-  JSTypedLoweringTester R;
-
-  Type* types[] = {Type::Null(),             Type::Undefined(),
-                   Type::Boolean(),          Type::OrderedNumber(),
-                   Type::DetectableObject(), Type::Undetectable()};
-
-  for (size_t i = 0; i < arraysize(types); i++) {
-    Node* n = R.Parameter(types[i]);
-    Node* c = R.graph.NewNode(R.javascript.ToBoolean(), n, R.context(),
-                              R.start(), R.start());
-    Node* effect_use = R.UseForEffect(c);
-    Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c);
-
-    R.CheckEffectInput(c, effect_use);
-    Node* r = R.reduce(c);
-
-    if (types[i]->Is(Type::Boolean())) {
-      CHECK_EQ(n, r);
-    } else if (types[i]->Is(Type::OrderedNumber())) {
-      CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-    } else {
-      CHECK_EQ(IrOpcode::kHeapConstant, r->opcode());
-    }
-
-    CHECK_EQ(n, add->InputAt(0));
-    CHECK_EQ(r, add->InputAt(1));
-    R.CheckEffectInput(R.start(), effect_use);
+    CHECK_EQ(IrOpcode::kAnyToBoolean, r->opcode());
   }
 }
 
@@ -690,33 +653,22 @@
       R.javascript.GreaterThan(),        R.simplified.NumberLessThan(),
       R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual()};
 
-  for (size_t i = 0; i < arraysize(kJSTypes); i++) {
-    Type* t0 = kJSTypes[i];
-    // Skip Type::String and Type::Receiver which might coerce into a string.
-    if (t0->Is(Type::String()) || t0->Is(Type::Receiver())) continue;
-    Node* p0 = R.Parameter(t0, 0);
+  Node* const p0 = R.Parameter(Type::Number(), 0);
+  Node* const p1 = R.Parameter(Type::Number(), 1);
 
-    for (size_t j = 0; j < arraysize(kJSTypes); j++) {
-      Type* t1 = kJSTypes[j];
-      // Skip Type::String and Type::Receiver which might coerce into a string.
-      if (t1->Is(Type::String()) || t0->Is(Type::Receiver())) continue;
-      Node* p1 = R.Parameter(t1, 1);
+  for (size_t k = 0; k < arraysize(ops); k += 2) {
+    Node* cmp = R.Binop(ops[k], p0, p1);
+    Node* r = R.reduce(cmp);
 
-      for (size_t k = 0; k < arraysize(ops); k += 2) {
-        Node* cmp = R.Binop(ops[k], p0, p1);
-        Node* r = R.reduce(cmp);
-
-        R.CheckPureBinop(ops[k + 1], r);
-        if (k >= 4) {
-          // GreaterThan and GreaterThanOrEqual commute the inputs
-          // and use the LessThan and LessThanOrEqual operators.
-          CheckIsConvertedToNumber(p1, r->InputAt(0));
-          CheckIsConvertedToNumber(p0, r->InputAt(1));
-        } else {
-          CheckIsConvertedToNumber(p0, r->InputAt(0));
-          CheckIsConvertedToNumber(p1, r->InputAt(1));
-        }
-      }
+    R.CheckPureBinop(ops[k + 1], r);
+    if (k >= 4) {
+      // GreaterThan and GreaterThanOrEqual commute the inputs
+      // and use the LessThan and LessThanOrEqual operators.
+      CheckIsConvertedToNumber(p1, r->InputAt(0));
+      CheckIsConvertedToNumber(p0, r->InputAt(1));
+    } else {
+      CheckIsConvertedToNumber(p0, r->InputAt(0));
+      CheckIsConvertedToNumber(p1, r->InputAt(1));
     }
   }
 }
@@ -753,51 +705,18 @@
 }
 
 
-TEST(ObjectComparison) {
-  JSTypedLoweringTester R;
-
-  Node* p0 = R.Parameter(Type::Number(), 0);
-  Node* p1 = R.Parameter(Type::Object(), 1);
-
-  Node* cmp = R.Binop(R.javascript.LessThan(), p0, p1);
-  Node* effect_use = R.UseForEffect(cmp);
-
-  R.CheckEffectInput(R.start(), cmp);
-  R.CheckEffectInput(cmp, effect_use);
-
-  Node* r = R.reduce(cmp);
-
-  R.CheckPureBinop(R.simplified.NumberLessThan(), r);
-
-  Node* i0 = r->InputAt(0);
-  Node* i1 = r->InputAt(1);
-
-  CHECK_EQ(p0, i0);
-  CHECK_NE(p1, i1);
-  CHECK_EQ(IrOpcode::kParameter, i0->opcode());
-  CHECK_EQ(IrOpcode::kJSToNumber, i1->opcode());
-
-  // Check effect chain is correct.
-  R.CheckEffectInput(R.start(), i1);
-  R.CheckEffectInput(i1, effect_use);
-}
-
-
 TEST(UnaryNot) {
   JSTypedLoweringTester R;
   const Operator* opnot = R.javascript.UnaryNot();
 
   for (size_t i = 0; i < arraysize(kJSTypes); i++) {
     Node* orig = R.Unop(opnot, R.Parameter(kJSTypes[i]));
-    Node* use = R.graph.NewNode(R.common.Return(), orig);
     Node* r = R.reduce(orig);
-    // TODO(titzer): test will break if/when js-typed-lowering constant folds.
-    CHECK_EQ(IrOpcode::kBooleanNot, use->InputAt(0)->opcode());
 
     if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) {
       // The original node was turned into a ToBoolean.
       CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-    } else {
+    } else if (r->opcode() != IrOpcode::kHeapConstant) {
       CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
     }
   }
@@ -852,7 +771,7 @@
     if (effect_use != NULL) {
       R.CheckEffectInput(R.start(), effect_use);
       // Check that value uses of ToNumber() do not go to start().
-      for (int i = 0; i < effect_use->op()->InputCount(); i++) {
+      for (int i = 0; i < effect_use->op()->ValueInputCount(); i++) {
         CHECK_NE(R.start(), effect_use->InputAt(i));
       }
     }
@@ -904,9 +823,9 @@
   Node* CheckConverted(IrOpcode::Value opcode, Node* node, bool effects) {
     CHECK_EQ(opcode, node->opcode());
     if (effects) {
-      CHECK_LT(0, OperatorProperties::GetEffectInputCount(node->op()));
+      CHECK_LT(0, node->op()->EffectInputCount());
     } else {
-      CHECK_EQ(0, OperatorProperties::GetEffectInputCount(node->op()));
+      CHECK_EQ(0, node->op()->EffectInputCount());
     }
     return node;
   }
@@ -1030,7 +949,7 @@
   };
 
   for (size_t j = 0; j < arraysize(ops); j += 2) {
-    BinopEffectsTester B(ops[j], Type::Object(), Type::String());
+    BinopEffectsTester B(ops[j], Type::Symbol(), Type::Symbol());
     CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
 
     Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
@@ -1103,8 +1022,8 @@
     CHECK_EQ(B.p1, i0->InputAt(0));
     CHECK_EQ(B.p0, i1->InputAt(0));
 
-    // But effects should be ordered start -> i1 -> i0 -> effect_use
-    B.CheckEffectOrdering(i1, i0);
+    // But effects should be ordered start -> i1 -> effect_use
+    B.CheckEffectOrdering(i1);
   }
 
   for (size_t j = 0; j < arraysize(ops); j += 2) {
@@ -1166,7 +1085,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Number(), Type::Object());
+    BinopEffectsTester B(R.ops[j], Type::Number(), Type::Primitive());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1183,7 +1102,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Object(), Type::Number());
+    BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Number());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1200,7 +1119,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Object(), Type::Object());
+    BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Primitive());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1218,33 +1137,6 @@
 }
 
 
-TEST(UnaryNotEffects) {
-  JSTypedLoweringTester R;
-  const Operator* opnot = R.javascript.UnaryNot();
-
-  for (size_t i = 0; i < arraysize(kJSTypes); i++) {
-    Node* p0 = R.Parameter(kJSTypes[i], 0);
-    Node* orig = R.Unop(opnot, p0);
-    Node* effect_use = R.UseForEffect(orig);
-    Node* value_use = R.graph.NewNode(R.common.Return(), orig);
-    Node* r = R.reduce(orig);
-    // TODO(titzer): test will break if/when js-typed-lowering constant folds.
-    CHECK_EQ(IrOpcode::kBooleanNot, value_use->InputAt(0)->opcode());
-
-    if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) {
-      // The original node was turned into a ToBoolean, which has an effect.
-      CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-      R.CheckEffectInput(R.start(), orig);
-      R.CheckEffectInput(orig, effect_use);
-    } else {
-      // effect should have been removed from this node.
-      CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-      R.CheckEffectInput(R.start(), effect_use);
-    }
-  }
-}
-
-
 TEST(Int32AddNarrowing) {
   {
     JSBitwiseTypedLoweringTester R;
@@ -1263,11 +1155,7 @@
             Node* r = R.reduce(or_node);
 
             CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-            CHECK_EQ(IrOpcode::kInt32Add, add_node->opcode());
-            bool is_signed = l ? R.signedness[o] : R.signedness[o + 1];
-
-            Type* add_type = NodeProperties::GetBounds(add_node).upper;
-            CHECK(add_type->Is(I32Type(is_signed)));
+            CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
           }
         }
       }
@@ -1290,40 +1178,33 @@
             Node* r = R.reduce(or_node);
 
             CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-            CHECK_EQ(IrOpcode::kInt32Add, add_node->opcode());
-            bool is_signed = l ? R.signedness[o] : R.signedness[o + 1];
-
-            Type* add_type = NodeProperties::GetBounds(add_node).upper;
-            CHECK(add_type->Is(I32Type(is_signed)));
+            CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
           }
         }
       }
     }
   }
-}
+  {
+    JSBitwiseTypedLoweringTester R;
 
+    for (int o = 0; o < R.kNumberOps; o += 2) {
+      Node* n0 = R.Parameter(I32Type(R.signedness[o]));
+      Node* n1 = R.Parameter(I32Type(R.signedness[o + 1]));
+      Node* one = R.graph.NewNode(R.common.NumberConstant(1));
 
-TEST(Int32AddNarrowingNotOwned) {
-  JSBitwiseTypedLoweringTester R;
-
-  for (int o = 0; o < R.kNumberOps; o += 2) {
-    Node* n0 = R.Parameter(I32Type(R.signedness[o]));
-    Node* n1 = R.Parameter(I32Type(R.signedness[o + 1]));
-    Node* one = R.graph.NewNode(R.common.NumberConstant(1));
-
-    Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
-    Node* or_node = R.Binop(R.ops[o], add_node, one);
-    Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one);
-    Node* r = R.reduce(or_node);
-    CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-    // Should not be reduced to Int32Add because of the other number add.
-    CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
-    // Conversion to int32 should be done.
-    CheckToI32(add_node, r->InputAt(0), R.signedness[o]);
-    CheckToI32(one, r->InputAt(1), R.signedness[o + 1]);
-    // The other use should also not be touched.
-    CHECK_EQ(add_node, other_use->InputAt(0));
-    CHECK_EQ(one, other_use->InputAt(1));
+      Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
+      Node* or_node = R.Binop(R.ops[o], add_node, one);
+      Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one);
+      Node* r = R.reduce(or_node);
+      CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
+      CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
+      // Conversion to int32 should be done.
+      CheckToI32(add_node, r->InputAt(0), R.signedness[o]);
+      CheckToI32(one, r->InputAt(1), R.signedness[o + 1]);
+      // The other use should also not be touched.
+      CHECK_EQ(add_node, other_use->InputAt(0));
+      CHECK_EQ(one, other_use->InputAt(1));
+    }
   }
 }
 
diff --git a/test/cctest/compiler/test-jump-threading.cc b/test/cctest/compiler/test-jump-threading.cc
new file mode 100644
index 0000000..74bf43d
--- /dev/null
+++ b/test/cctest/compiler/test-jump-threading.cc
@@ -0,0 +1,764 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/compiler/instruction.h"
+#include "src/compiler/instruction-codes.h"
+#include "src/compiler/jump-threading.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef BasicBlock::RpoNumber RpoNumber;
+
+class TestCode : public HandleAndZoneScope {
+ public:
+  TestCode()
+      : HandleAndZoneScope(),
+        blocks_(main_zone()),
+        sequence_(main_zone(), &blocks_),
+        rpo_number_(RpoNumber::FromInt(0)),
+        current_(NULL) {}
+
+  ZoneVector<InstructionBlock*> blocks_;
+  InstructionSequence sequence_;
+  RpoNumber rpo_number_;
+  InstructionBlock* current_;
+
+  int Jump(int target) {
+    Start();
+    InstructionOperand* ops[] = {UseRpo(target)};
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchJmp, 0, NULL, 1,
+                                              ops, 0, NULL)->MarkAsControl());
+    int pos = static_cast<int>(sequence_.instructions().size() - 1);
+    End();
+    return pos;
+  }
+  void Fallthru() {
+    Start();
+    End();
+  }
+  int Branch(int ttarget, int ftarget) {
+    Start();
+    InstructionOperand* ops[] = {UseRpo(ttarget), UseRpo(ftarget)};
+    InstructionCode code = 119 | FlagsModeField::encode(kFlags_branch) |
+                           FlagsConditionField::encode(kEqual);
+    sequence_.AddInstruction(Instruction::New(main_zone(), code, 0, NULL, 2,
+                                              ops, 0, NULL)->MarkAsControl());
+    int pos = static_cast<int>(sequence_.instructions().size() - 1);
+    End();
+    return pos;
+  }
+  void Nop() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+  }
+  void RedundantMoves() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+    int index = static_cast<int>(sequence_.instructions().size()) - 1;
+    sequence_.AddGapMove(index, RegisterOperand::Create(13, main_zone()),
+                         RegisterOperand::Create(13, main_zone()));
+  }
+  void NonRedundantMoves() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+    int index = static_cast<int>(sequence_.instructions().size()) - 1;
+    sequence_.AddGapMove(index, ImmediateOperand::Create(11, main_zone()),
+                         RegisterOperand::Create(11, main_zone()));
+  }
+  void Other() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), 155));
+  }
+  void End() {
+    Start();
+    sequence_.EndBlock(current_->rpo_number());
+    current_ = NULL;
+    rpo_number_ = RpoNumber::FromInt(rpo_number_.ToInt() + 1);
+  }
+  InstructionOperand* UseRpo(int num) {
+    int index = sequence_.AddImmediate(Constant(RpoNumber::FromInt(num)));
+    return ImmediateOperand::Create(index, main_zone());
+  }
+  void Start(bool deferred = false) {
+    if (current_ == NULL) {
+      current_ = new (main_zone()) InstructionBlock(
+          main_zone(), BasicBlock::Id::FromInt(rpo_number_.ToInt()),
+          rpo_number_, RpoNumber::Invalid(), RpoNumber::Invalid(), deferred);
+      blocks_.push_back(current_);
+      sequence_.StartBlock(rpo_number_);
+    }
+  }
+  void Defer() {
+    CHECK(current_ == NULL);
+    Start(true);
+  }
+};
+
+
+void VerifyForwarding(TestCode& code, int count, int* expected) {
+  Zone local_zone(code.main_isolate());
+  ZoneVector<RpoNumber> result(&local_zone);
+  JumpThreading::ComputeForwarding(&local_zone, result, &code.sequence_);
+
+  CHECK(count == static_cast<int>(result.size()));
+  for (int i = 0; i < count; i++) {
+    CHECK(expected[i] == result[i].ToInt());
+  }
+}
+
+
+TEST(FwEmpty1) {
+  TestCode code;
+
+  // B0
+  code.Jump(1);
+  // B1
+  code.Jump(2);
+  // B2
+  code.End();
+
+  static int expected[] = {2, 2, 2};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwEmptyN) {
+  for (int i = 0; i < 9; i++) {
+    TestCode code;
+
+    // B0
+    code.Jump(1);
+    // B1
+    for (int j = 0; j < i; j++) code.Nop();
+    code.Jump(2);
+    // B2
+    code.End();
+
+    static int expected[] = {2, 2, 2};
+    VerifyForwarding(code, 3, expected);
+  }
+}
+
+
+TEST(FwNone1) {
+  TestCode code;
+
+  // B0
+  code.End();
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwMoves1) {
+  TestCode code;
+
+  // B0
+  code.RedundantMoves();
+  code.End();
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwMoves2) {
+  TestCode code;
+
+  // B0
+  code.RedundantMoves();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwMoves2b) {
+  TestCode code;
+
+  // B0
+  code.NonRedundantMoves();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {0, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwOther2) {
+  TestCode code;
+
+  // B0
+  code.Other();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {0, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwNone2a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwNone2b) {
+  TestCode code;
+
+  // B0
+  code.Jump(1);
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop1) {
+  TestCode code;
+
+  // B0
+  code.Jump(0);
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwLoop2) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Jump(0);
+
+  static int expected[] = {0, 0};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop3) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(0);
+
+  static int expected[] = {0, 0, 0};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwLoop1b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Jump(1);
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop2b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwLoop3b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1};
+  VerifyForwarding(code, 4, expected);
+}
+
+
+TEST(FwLoop2_1a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(2);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(4);
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(2);
+
+  static int expected[] = {2, 2, 2, 2, 2};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1c) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(4);
+  // B3
+  code.Jump(2);
+  // B4
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1d) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(1);
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop3_1a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(2);
+  // B4
+  code.Jump(1);
+  // B5
+  code.Jump(0);
+
+  static int expected[] = {2, 2, 2, 2, 2, 2};
+  VerifyForwarding(code, 6, expected);
+}
+
+
+TEST(FwDiamonds) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      TestCode code;
+      // B0
+      code.Branch(1, 2);
+      // B1
+      if (i) code.Other();
+      code.Jump(3);
+      // B2
+      if (j) code.Other();
+      code.Jump(3);
+      // B3
+      code.End();
+
+      int expected[] = {0, i ? 1 : 3, j ? 2 : 3, 3};
+      VerifyForwarding(code, 4, expected);
+    }
+  }
+}
+
+
+TEST(FwDiamonds2) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      for (int k = 0; k < 2; k++) {
+        TestCode code;
+        // B0
+        code.Branch(1, 2);
+        // B1
+        if (i) code.Other();
+        code.Jump(3);
+        // B2
+        if (j) code.Other();
+        code.Jump(3);
+        // B3
+        if (k) code.NonRedundantMoves();
+        code.Jump(4);
+        // B4
+        code.End();
+
+        int merge = k ? 3 : 4;
+        int expected[] = {0, i ? 1 : merge, j ? 2 : merge, merge, 4};
+        VerifyForwarding(code, 5, expected);
+      }
+    }
+  }
+}
+
+
+TEST(FwDoubleDiamonds) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      for (int x = 0; x < 2; x++) {
+        for (int y = 0; y < 2; y++) {
+          TestCode code;
+          // B0
+          code.Branch(1, 2);
+          // B1
+          if (i) code.Other();
+          code.Jump(3);
+          // B2
+          if (j) code.Other();
+          code.Jump(3);
+          // B3
+          code.Branch(4, 5);
+          // B4
+          if (x) code.Other();
+          code.Jump(6);
+          // B5
+          if (y) code.Other();
+          code.Jump(6);
+          // B6
+          code.End();
+
+          int expected[] = {0,         i ? 1 : 3, j ? 2 : 3, 3,
+                            x ? 4 : 6, y ? 5 : 6, 6};
+          VerifyForwarding(code, 7, expected);
+        }
+      }
+    }
+  }
+}
+
+template <int kSize>
+void RunPermutationsRecursive(int outer[kSize], int start,
+                              void (*run)(int*, int)) {
+  int permutation[kSize];
+
+  for (int i = 0; i < kSize; i++) permutation[i] = outer[i];
+
+  int count = kSize - start;
+  if (count == 0) return run(permutation, kSize);
+  for (int i = start; i < kSize; i++) {
+    permutation[start] = outer[i];
+    permutation[i] = outer[start];
+    RunPermutationsRecursive<kSize>(permutation, start + 1, run);
+    permutation[i] = outer[i];
+    permutation[start] = outer[start];
+  }
+}
+
+
+template <int kSize>
+void RunAllPermutations(void (*run)(int*, int)) {
+  int permutation[kSize];
+  for (int i = 0; i < kSize; i++) permutation[i] = i;
+  RunPermutationsRecursive<kSize>(permutation, 0, run);
+}
+
+
+void PrintPermutation(int* permutation, int size) {
+  printf("{ ");
+  for (int i = 0; i < size; i++) {
+    if (i > 0) printf(", ");
+    printf("%d", permutation[i]);
+  }
+  printf(" }\n");
+}
+
+
+int find(int x, int* permutation, int size) {
+  for (int i = 0; i < size; i++) {
+    if (permutation[i] == x) return i;
+  }
+  return size;
+}
+
+
+void RunPermutedChain(int* permutation, int size) {
+  TestCode code;
+  int cur = -1;
+  for (int i = 0; i < size; i++) {
+    code.Jump(find(cur + 1, permutation, size) + 1);
+    cur = permutation[i];
+  }
+  code.Jump(find(cur + 1, permutation, size) + 1);
+  code.End();
+
+  int expected[] = {size + 1, size + 1, size + 1, size + 1,
+                    size + 1, size + 1, size + 1};
+  VerifyForwarding(code, size + 2, expected);
+}
+
+
+TEST(FwPermuted_chain) {
+  RunAllPermutations<3>(RunPermutedChain);
+  RunAllPermutations<4>(RunPermutedChain);
+  RunAllPermutations<5>(RunPermutedChain);
+}
+
+
+void RunPermutedDiamond(int* permutation, int size) {
+  TestCode code;
+  int br = 1 + find(0, permutation, size);
+  code.Jump(br);
+  for (int i = 0; i < size; i++) {
+    switch (permutation[i]) {
+      case 0:
+        code.Branch(1 + find(1, permutation, size),
+                    1 + find(2, permutation, size));
+        break;
+      case 1:
+        code.Jump(1 + find(3, permutation, size));
+        break;
+      case 2:
+        code.Jump(1 + find(3, permutation, size));
+        break;
+      case 3:
+        code.Jump(5);
+        break;
+    }
+  }
+  code.End();
+
+  int expected[] = {br, 5, 5, 5, 5, 5};
+  expected[br] = br;
+  VerifyForwarding(code, 6, expected);
+}
+
+
+TEST(FwPermuted_diamond) { RunAllPermutations<4>(RunPermutedDiamond); }
+
+
+void ApplyForwarding(TestCode& code, int size, int* forward) {
+  ZoneVector<RpoNumber> vector(code.main_zone());
+  for (int i = 0; i < size; i++) {
+    vector.push_back(RpoNumber::FromInt(forward[i]));
+  }
+  JumpThreading::ApplyForwarding(vector, &code.sequence_);
+}
+
+
+void CheckJump(TestCode& code, int pos, int target) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(kArchJmp, instr->arch_opcode());
+  CHECK_EQ(1, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+  CHECK_EQ(target, code.sequence_.InputRpo(instr, 0).ToInt());
+}
+
+
+void CheckNop(TestCode& code, int pos) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(kArchNop, instr->arch_opcode());
+  CHECK_EQ(0, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+}
+
+
+void CheckBranch(TestCode& code, int pos, int t1, int t2) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(2, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+  CHECK_EQ(t1, code.sequence_.InputRpo(instr, 0).ToInt());
+  CHECK_EQ(t2, code.sequence_.InputRpo(instr, 1).ToInt());
+}
+
+
+void CheckAssemblyOrder(TestCode& code, int size, int* expected) {
+  int i = 0;
+  for (auto const block : code.sequence_.instruction_blocks()) {
+    CHECK_EQ(expected[i++], block->ao_number().ToInt());
+  }
+}
+
+
+TEST(Rewire1) {
+  TestCode code;
+
+  // B0
+  int j1 = code.Jump(1);
+  // B1
+  int j2 = code.Jump(2);
+  // B2
+  code.End();
+
+  static int forward[] = {2, 2, 2};
+  ApplyForwarding(code, 3, forward);
+  CheckJump(code, j1, 2);
+  CheckNop(code, j2);
+
+  static int assembly[] = {0, 1, 1};
+  CheckAssemblyOrder(code, 3, assembly);
+}
+
+
+TEST(Rewire1_deferred) {
+  TestCode code;
+
+  // B0
+  int j1 = code.Jump(1);
+  // B1
+  int j2 = code.Jump(2);
+  // B2
+  code.Defer();
+  int j3 = code.Jump(3);
+  // B3
+  code.End();
+
+  static int forward[] = {3, 3, 3, 3};
+  ApplyForwarding(code, 4, forward);
+  CheckJump(code, j1, 3);
+  CheckNop(code, j2);
+  CheckNop(code, j3);
+
+  static int assembly[] = {0, 1, 2, 1};
+  CheckAssemblyOrder(code, 4, assembly);
+}
+
+
+TEST(Rewire2_deferred) {
+  TestCode code;
+
+  // B0
+  code.Other();
+  int j1 = code.Jump(1);
+  // B1
+  code.Defer();
+  code.Fallthru();
+  // B2
+  code.Defer();
+  int j2 = code.Jump(3);
+  // B3
+  code.End();
+
+  static int forward[] = {0, 1, 2, 3};
+  ApplyForwarding(code, 4, forward);
+  CheckJump(code, j1, 1);
+  CheckJump(code, j2, 3);
+
+  static int assembly[] = {0, 2, 3, 1};
+  CheckAssemblyOrder(code, 4, assembly);
+}
+
+
+TEST(Rewire_diamond) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      TestCode code;
+      // B0
+      int j1 = code.Jump(1);
+      // B1
+      int b1 = code.Branch(2, 3);
+      // B2
+      int j2 = code.Jump(4);
+      // B3
+      int j3 = code.Jump(4);
+      // B5
+      code.End();
+
+      int forward[] = {0, 1, i ? 4 : 2, j ? 4 : 3, 4};
+      ApplyForwarding(code, 5, forward);
+      CheckJump(code, j1, 1);
+      CheckBranch(code, b1, i ? 4 : 2, j ? 4 : 3);
+      if (i) {
+        CheckNop(code, j2);
+      } else {
+        CheckJump(code, j2, 4);
+      }
+      if (j) {
+        CheckNop(code, j3);
+      } else {
+        CheckJump(code, j3, 4);
+      }
+
+      int assembly[] = {0, 1, 2, 3, 4};
+      if (i) {
+        for (int k = 3; k < 5; k++) assembly[k]--;
+      }
+      if (j) {
+        for (int k = 4; k < 5; k++) assembly[k]--;
+      }
+      CheckAssemblyOrder(code, 5, assembly);
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/cctest/compiler/test-linkage.cc b/test/cctest/compiler/test-linkage.cc
index ff65d6e..117caf2 100644
--- a/test/cctest/compiler/test-linkage.cc
+++ b/test/cctest/compiler/test-linkage.cc
@@ -8,7 +8,6 @@
 #include "src/zone.h"
 
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/linkage.h"
 #include "src/compiler/machine-operator.h"
@@ -23,8 +22,8 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 0, 0, 0);
 
 // So we can get a real JS function.
 static Handle<JSFunction> Compile(const char* source) {
@@ -45,7 +44,7 @@
   InitializedHandleScope handles;
   Handle<JSFunction> function = Compile("a + b");
   CompilationInfoWithZone info(function);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
 }
 
 
@@ -60,13 +59,13 @@
     Handle<JSFunction> function = v8::Utils::OpenHandle(
         *v8::Handle<v8::Function>::Cast(CompileRun(sources[i])));
     CompilationInfoWithZone info(function);
-    Linkage linkage(&info);
+    Linkage linkage(info.zone(), &info);
 
     CallDescriptor* descriptor = linkage.GetIncomingDescriptor();
     CHECK_NE(NULL, descriptor);
 
-    CHECK_EQ(1 + i, descriptor->JSParameterCount());
-    CHECK_EQ(1, descriptor->ReturnCount());
+    CHECK_EQ(1 + i, static_cast<int>(descriptor->JSParameterCount()));
+    CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount()));
     CHECK_EQ(Operator::kNoProperties, descriptor->properties());
     CHECK_EQ(true, descriptor->IsJSFunctionCall());
   }
@@ -76,7 +75,7 @@
 TEST(TestLinkageCodeStubIncoming) {
   Isolate* isolate = CcTest::InitIsolateOnce();
   CompilationInfoWithZone info(static_cast<HydrogenCodeStub*>(NULL), isolate);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
   // TODO(titzer): test linkage creation with a bonafide code stub.
   // this just checks current behavior.
   CHECK_EQ(NULL, linkage.GetIncomingDescriptor());
@@ -87,13 +86,14 @@
   HandleAndZoneScope handles;
   Handle<JSFunction> function = Compile("a + c");
   CompilationInfoWithZone info(function);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
 
   for (int i = 0; i < 32; i++) {
-    CallDescriptor* descriptor = linkage.GetJSCallDescriptor(i);
+    CallDescriptor* descriptor =
+        linkage.GetJSCallDescriptor(i, CallDescriptor::kNoFlags);
     CHECK_NE(NULL, descriptor);
-    CHECK_EQ(i, descriptor->JSParameterCount());
-    CHECK_EQ(1, descriptor->ReturnCount());
+    CHECK_EQ(i, static_cast<int>(descriptor->JSParameterCount()));
+    CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount()));
     CHECK_EQ(Operator::kNoProperties, descriptor->properties());
     CHECK_EQ(true, descriptor->IsJSFunctionCall());
   }
diff --git a/test/cctest/compiler/test-loop-analysis.cc b/test/cctest/compiler/test-loop-analysis.cc
new file mode 100644
index 0000000..9c11268
--- /dev/null
+++ b/test/cctest/compiler/test-loop-analysis.cc
@@ -0,0 +1,862 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/loop-analysis.h"
+#include "src/compiler/node.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/schedule.h"
+#include "src/compiler/scheduler.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/compiler/verifier.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+static Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0,
+                        0, 1, 0, 0);
+static Operator kIntLt(IrOpcode::kInt32LessThan, Operator::kPure,
+                       "Int32LessThan", 2, 0, 0, 1, 0, 0);
+static Operator kStore(IrOpcode::kStore, Operator::kNoProperties, "Store", 0, 2,
+                       1, 0, 1, 0);
+
+static const int kNumLeafs = 4;
+
+// A helper for all tests dealing with LoopFinder.
+class LoopFinderTester : HandleAndZoneScope {
+ public:
+  LoopFinderTester()
+      : isolate(main_isolate()),
+        common(main_zone()),
+        graph(main_zone()),
+        jsgraph(&graph, &common, NULL, NULL),
+        start(graph.NewNode(common.Start(1))),
+        end(graph.NewNode(common.End(), start)),
+        p0(graph.NewNode(common.Parameter(0), start)),
+        zero(jsgraph.Int32Constant(0)),
+        one(jsgraph.OneConstant()),
+        half(jsgraph.Constant(0.5)),
+        self(graph.NewNode(common.Int32Constant(0xaabbccdd))),
+        dead(graph.NewNode(common.Dead())),
+        loop_tree(NULL) {
+    graph.SetEnd(end);
+    graph.SetStart(start);
+    leaf[0] = zero;
+    leaf[1] = one;
+    leaf[2] = half;
+    leaf[3] = p0;
+  }
+
+  Isolate* isolate;
+  CommonOperatorBuilder common;
+  Graph graph;
+  JSGraph jsgraph;
+  Node* start;
+  Node* end;
+  Node* p0;
+  Node* zero;
+  Node* one;
+  Node* half;
+  Node* self;
+  Node* dead;
+  Node* leaf[kNumLeafs];
+  LoopTree* loop_tree;
+
+  Node* Phi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, false), a, start));
+  }
+
+  Node* Phi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, false), a, b, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start));
+  }
+
+  Node* EffectPhi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, true), a, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, true), a, b, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start));
+  }
+
+  Node* SetSelfReferences(Node* node) {
+    for (Edge edge : node->input_edges()) {
+      if (edge.to() == self) node->ReplaceInput(edge.index(), node);
+    }
+    return node;
+  }
+
+  const Operator* op(int count, bool effect) {
+    return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count);
+  }
+
+  Node* Return(Node* val, Node* effect, Node* control) {
+    Node* ret = graph.NewNode(common.Return(), val, effect, control);
+    end->ReplaceInput(0, ret);
+    return ret;
+  }
+
+  LoopTree* GetLoopTree() {
+    if (loop_tree == NULL) {
+      if (FLAG_trace_turbo_graph) {
+        OFStream os(stdout);
+        os << AsRPO(graph);
+      }
+      Zone zone(isolate);
+      loop_tree = LoopFinder::BuildLoopTree(&graph, &zone);
+    }
+    return loop_tree;
+  }
+
+  void CheckLoop(Node** header, int header_count, Node** body, int body_count) {
+    LoopTree* tree = GetLoopTree();
+    LoopTree::Loop* loop = tree->ContainingLoop(header[0]);
+    CHECK_NE(NULL, loop);
+
+    CHECK(header_count == static_cast<int>(loop->HeaderSize()));
+    for (int i = 0; i < header_count; i++) {
+      // Each header node should be in the loop.
+      CHECK_EQ(loop, tree->ContainingLoop(header[i]));
+      CheckRangeContains(tree->HeaderNodes(loop), header[i]);
+    }
+
+    CHECK_EQ(body_count, static_cast<int>(loop->BodySize()));
+    for (int i = 0; i < body_count; i++) {
+      // Each body node should be contained in the loop.
+      CHECK(tree->Contains(loop, body[i]));
+      CheckRangeContains(tree->BodyNodes(loop), body[i]);
+    }
+  }
+
+  void CheckRangeContains(NodeRange range, Node* node) {
+    // O(n) ftw.
+    CHECK_NE(range.end(), std::find(range.begin(), range.end(), node));
+  }
+
+  void CheckNestedLoops(Node** chain, int chain_count) {
+    LoopTree* tree = GetLoopTree();
+    for (int i = 0; i < chain_count; i++) {
+      Node* header = chain[i];
+      // Each header should be in a loop.
+      LoopTree::Loop* loop = tree->ContainingLoop(header);
+      CHECK_NE(NULL, loop);
+      // Check parentage.
+      LoopTree::Loop* parent =
+          i == 0 ? NULL : tree->ContainingLoop(chain[i - 1]);
+      CHECK_EQ(parent, loop->parent());
+      for (int j = i - 1; j >= 0; j--) {
+        // This loop should be nested inside all the outer loops.
+        Node* outer_header = chain[j];
+        LoopTree::Loop* outer = tree->ContainingLoop(outer_header);
+        CHECK(tree->Contains(outer, header));
+        CHECK(!tree->Contains(loop, outer_header));
+      }
+    }
+  }
+};
+
+
+struct While {
+  LoopFinderTester& t;
+  Node* branch;
+  Node* if_true;
+  Node* exit;
+  Node* loop;
+
+  While(LoopFinderTester& R, Node* cond) : t(R) {
+    loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+    branch = t.graph.NewNode(t.common.Branch(), cond, loop);
+    if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+    exit = t.graph.NewNode(t.common.IfFalse(), branch);
+    loop->ReplaceInput(1, if_true);
+  }
+
+  void chain(Node* control) { loop->ReplaceInput(0, control); }
+  void nest(While& that) {
+    that.loop->ReplaceInput(1, exit);
+    this->loop->ReplaceInput(0, that.if_true);
+  }
+};
+
+
+struct Counter {
+  Node* base;
+  Node* inc;
+  Node* phi;
+  Node* add;
+
+  Counter(While& w, int32_t b, int32_t k)
+      : base(w.t.jsgraph.Int32Constant(b)), inc(w.t.jsgraph.Int32Constant(k)) {
+    Build(w);
+  }
+
+  Counter(While& w, Node* b, Node* k) : base(b), inc(k) { Build(w); }
+
+  void Build(While& w) {
+    phi = w.t.graph.NewNode(w.t.op(2, false), base, base, w.loop);
+    add = w.t.graph.NewNode(&kIntAdd, phi, inc);
+    phi->ReplaceInput(1, add);
+  }
+};
+
+
+struct StoreLoop {
+  Node* base;
+  Node* val;
+  Node* phi;
+  Node* store;
+
+  explicit StoreLoop(While& w)
+      : base(w.t.jsgraph.Int32Constant(12)),
+        val(w.t.jsgraph.Int32Constant(13)) {
+    Build(w);
+  }
+
+  StoreLoop(While& w, Node* b, Node* v) : base(b), val(v) { Build(w); }
+
+  void Build(While& w) {
+    phi = w.t.graph.NewNode(w.t.op(2, true), base, base, w.loop);
+    store = w.t.graph.NewNode(&kStore, phi, val, w.loop);
+    phi->ReplaceInput(1, store);
+  }
+};
+
+
+TEST(LaLoop1) {
+  // One loop.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  t.Return(t.p0, t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop};
+  Node* body[] = {w.branch, w.if_true};
+  t.CheckLoop(header, 1, body, 2);
+}
+
+
+TEST(LaLoop1c) {
+  // One loop with a counter.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  Counter c(w, 0, 1);
+  t.Return(c.phi, t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c.phi};
+  Node* body[] = {w.branch, w.if_true, c.add};
+  t.CheckLoop(header, 2, body, 3);
+}
+
+
+TEST(LaLoop1e) {
+  // One loop with an effect phi.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  StoreLoop c(w);
+  t.Return(t.p0, c.phi, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c.phi};
+  Node* body[] = {w.branch, w.if_true, c.store};
+  t.CheckLoop(header, 2, body, 3);
+}
+
+
+TEST(LaLoop1d) {
+  // One loop with two counters.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  Counter c1(w, 0, 1);
+  Counter c2(w, 1, 1);
+  t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c1.phi, c2.phi};
+  Node* body[] = {w.branch, w.if_true, c1.add, c2.add};
+  t.CheckLoop(header, 3, body, 4);
+}
+
+
+TEST(LaLoop2) {
+  // One loop following another.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  w2.chain(w1.exit);
+  t.Return(t.p0, t.start, w2.exit);
+
+  {
+    Node* chain[] = {w1.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w1.loop};
+    Node* body[] = {w1.branch, w1.if_true};
+    t.CheckLoop(header, 1, body, 2);
+  }
+
+  {
+    Node* chain[] = {w2.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w2.loop};
+    Node* body[] = {w2.branch, w2.if_true};
+    t.CheckLoop(header, 1, body, 2);
+  }
+}
+
+
+TEST(LaLoop2c) {
+  // One loop following another, each with counters.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  Counter c1(w1, 0, 1);
+  Counter c2(w2, 0, 1);
+  w2.chain(w1.exit);
+  t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w2.exit);
+
+  {
+    Node* chain[] = {w1.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w1.loop, c1.phi};
+    Node* body[] = {w1.branch, w1.if_true, c1.add};
+    t.CheckLoop(header, 2, body, 3);
+  }
+
+  {
+    Node* chain[] = {w2.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w2.loop, c2.phi};
+    Node* body[] = {w2.branch, w2.if_true, c2.add};
+    t.CheckLoop(header, 2, body, 3);
+  }
+}
+
+
+TEST(LaLoop2cc) {
+  // One loop following another; second loop uses phi from first.
+  for (int i = 0; i < 8; i++) {
+    LoopFinderTester t;
+    While w1(t, t.p0);
+    While w2(t, t.p0);
+    Counter c1(w1, 0, 1);
+
+    // various usage scenarios for the second loop.
+    Counter c2(w2, i & 1 ? t.p0 : c1.phi, i & 2 ? t.p0 : c1.phi);
+    if (i & 3) w2.branch->ReplaceInput(0, c1.phi);
+
+    w2.chain(w1.exit);
+    t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w2.exit);
+
+    {
+      Node* chain[] = {w1.loop};
+      t.CheckNestedLoops(chain, 1);
+
+      Node* header[] = {w1.loop, c1.phi};
+      Node* body[] = {w1.branch, w1.if_true, c1.add};
+      t.CheckLoop(header, 2, body, 3);
+    }
+
+    {
+      Node* chain[] = {w2.loop};
+      t.CheckNestedLoops(chain, 1);
+
+      Node* header[] = {w2.loop, c2.phi};
+      Node* body[] = {w2.branch, w2.if_true, c2.add};
+      t.CheckLoop(header, 2, body, 3);
+    }
+  }
+}
+
+
+TEST(LaNestedLoop1) {
+  // One loop nested in another.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  w2.nest(w1);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain, 2);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop, w2.branch, w2.if_true, w2.exit};
+  t.CheckLoop(h1, 1, b1, 6);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true};
+  t.CheckLoop(h2, 1, b2, 2);
+}
+
+
+TEST(LaNestedLoop1c) {
+  // One loop nested in another, each with a counter.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  Counter c1(w1, 0, 1);
+  Counter c2(w2, 0, 1);
+  w2.branch->ReplaceInput(0, c2.phi);
+  w2.nest(w1);
+  t.Return(c1.phi, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain, 2);
+
+  Node* h1[] = {w1.loop, c1.phi};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop, w2.branch, w2.if_true,
+                w2.exit,   c2.phi,     c1.add,  c2.add};
+  t.CheckLoop(h1, 2, b1, 9);
+
+  Node* h2[] = {w2.loop, c2.phi};
+  Node* b2[] = {w2.branch, w2.if_true, c2.add};
+  t.CheckLoop(h2, 2, b2, 3);
+}
+
+
+TEST(LaNestedLoop2) {
+  // Two loops nested in an outer loop.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  While w3(t, t.p0);
+  w2.nest(w1);
+  w3.nest(w1);
+  w3.chain(w2.exit);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain1[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain1, 2);
+
+  Node* chain2[] = {w1.loop, w3.loop};
+  t.CheckNestedLoops(chain2, 2);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 1, b1, 10);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true};
+  t.CheckLoop(h2, 1, b2, 2);
+
+  Node* h3[] = {w3.loop};
+  Node* b3[] = {w3.branch, w3.if_true};
+  t.CheckLoop(h3, 1, b3, 2);
+}
+
+
+TEST(LaNestedLoop3) {
+  // Three nested loops.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  While w3(t, t.p0);
+  w2.loop->ReplaceInput(0, w1.if_true);
+  w3.loop->ReplaceInput(0, w2.if_true);
+  w2.loop->ReplaceInput(1, w3.exit);
+  w1.loop->ReplaceInput(1, w2.exit);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop, w3.loop};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 1, b1, 10);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true, w3.loop, w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h2, 1, b2, 6);
+
+  Node* h3[] = {w3.loop};
+  Node* b3[] = {w3.branch, w3.if_true};
+  t.CheckLoop(h3, 1, b3, 2);
+}
+
+
+TEST(LaNestedLoop3c) {
+  // Three nested loops with counters.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  Counter c1(w1, 0, 1);
+  While w2(t, t.p0);
+  Counter c2(w2, 0, 1);
+  While w3(t, t.p0);
+  Counter c3(w3, 0, 1);
+  w2.loop->ReplaceInput(0, w1.if_true);
+  w3.loop->ReplaceInput(0, w2.if_true);
+  w2.loop->ReplaceInput(1, w3.exit);
+  w1.loop->ReplaceInput(1, w2.exit);
+  w1.branch->ReplaceInput(0, c1.phi);
+  w2.branch->ReplaceInput(0, c2.phi);
+  w3.branch->ReplaceInput(0, c3.phi);
+  t.Return(c1.phi, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop, w3.loop};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* h1[] = {w1.loop, c1.phi};
+  Node* b1[] = {w1.branch, w1.if_true, c1.add,    c2.add,     c2.add,
+                c2.phi,    c3.phi,     w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 2, b1, 15);
+
+  Node* h2[] = {w2.loop, c2.phi};
+  Node* b2[] = {w2.branch, w2.if_true, c2.add,     c3.add, c3.phi,
+                w3.loop,   w3.branch,  w3.if_true, w3.exit};
+  t.CheckLoop(h2, 2, b2, 9);
+
+  Node* h3[] = {w3.loop, c3.phi};
+  Node* b3[] = {w3.branch, w3.if_true, c3.add};
+  t.CheckLoop(h3, 2, b3, 3);
+}
+
+
+TEST(LaMultipleExit1) {
+  const int kMaxExits = 10;
+  Node* merge[1 + kMaxExits];
+  Node* body[2 * kMaxExits];
+
+  // A single loop with {i} exits.
+  for (int i = 1; i < kMaxExits; i++) {
+    LoopFinderTester t;
+    Node* cond = t.p0;
+
+    int merge_count = 0;
+    int body_count = 0;
+    Node* loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+    Node* last = loop;
+
+    for (int e = 0; e < i; e++) {
+      Node* branch = t.graph.NewNode(t.common.Branch(), cond, last);
+      Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+      Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
+      last = if_true;
+
+      body[body_count++] = branch;
+      body[body_count++] = if_true;
+      merge[merge_count++] = exit;
+    }
+
+    loop->ReplaceInput(1, last);  // form loop backedge.
+    Node* end = t.graph.NewNode(t.common.Merge(i), i, merge);  // form exit.
+    t.graph.SetEnd(end);
+
+    Node* h[] = {loop};
+    t.CheckLoop(h, 1, body, body_count);
+  }
+}
+
+
+TEST(LaMultipleBackedge1) {
+  const int kMaxBackedges = 10;
+  Node* loop_inputs[1 + kMaxBackedges];
+  Node* body[3 * kMaxBackedges];
+
+  // A single loop with {i} backedges.
+  for (int i = 1; i < kMaxBackedges; i++) {
+    LoopFinderTester t;
+
+    for (int j = 0; j <= i; j++) loop_inputs[j] = t.start;
+    Node* loop = t.graph.NewNode(t.common.Loop(1 + i), 1 + i, loop_inputs);
+
+    Node* cond = t.p0;
+    int body_count = 0;
+    Node* exit = loop;
+
+    for (int b = 0; b < i; b++) {
+      Node* branch = t.graph.NewNode(t.common.Branch(), cond, exit);
+      Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+      Node* if_false = t.graph.NewNode(t.common.IfFalse(), branch);
+      exit = if_false;
+
+      body[body_count++] = branch;
+      body[body_count++] = if_true;
+      if (b != (i - 1)) body[body_count++] = if_false;
+
+      loop->ReplaceInput(1 + b, if_true);
+    }
+
+    t.graph.SetEnd(exit);
+
+    Node* h[] = {loop};
+    t.CheckLoop(h, 1, body, body_count);
+  }
+}
+
+
+TEST(LaEdgeMatrix1) {
+  // Test various kinds of extra edges added to a simple loop.
+  for (int i = 0; i < 3; i++) {
+    for (int j = 0; j < 3; j++) {
+      for (int k = 0; k < 3; k++) {
+        LoopFinderTester t;
+
+        Node* p1 = t.jsgraph.Int32Constant(11);
+        Node* p2 = t.jsgraph.Int32Constant(22);
+        Node* p3 = t.jsgraph.Int32Constant(33);
+
+        Node* loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+        Node* phi =
+            t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p1, loop);
+        Node* cond = t.graph.NewNode(&kIntAdd, phi, p2);
+        Node* branch = t.graph.NewNode(t.common.Branch(), cond, loop);
+        Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+        Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
+        loop->ReplaceInput(1, if_true);
+        Node* ret = t.graph.NewNode(t.common.Return(), p3, t.start, exit);
+        t.graph.SetEnd(ret);
+
+        Node* choices[] = {p1, phi, cond};
+        p1->ReplaceUses(choices[i]);
+        p2->ReplaceUses(choices[j]);
+        p3->ReplaceUses(choices[k]);
+
+        Node* header[] = {loop, phi};
+        Node* body[] = {cond, branch, if_true};
+        t.CheckLoop(header, 2, body, 3);
+      }
+    }
+  }
+}
+
+
+void RunEdgeMatrix2(int i) {
+  DCHECK(i >= 0 && i < 5);
+  for (int j = 0; j < 5; j++) {
+    for (int k = 0; k < 5; k++) {
+      LoopFinderTester t;
+
+      Node* p1 = t.jsgraph.Int32Constant(11);
+      Node* p2 = t.jsgraph.Int32Constant(22);
+      Node* p3 = t.jsgraph.Int32Constant(33);
+
+      // outer loop.
+      Node* loop1 = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+      Node* phi1 =
+          t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p1, loop1);
+      Node* cond1 = t.graph.NewNode(&kIntAdd, phi1, t.one);
+      Node* branch1 = t.graph.NewNode(t.common.Branch(), cond1, loop1);
+      Node* if_true1 = t.graph.NewNode(t.common.IfTrue(), branch1);
+      Node* exit1 = t.graph.NewNode(t.common.IfFalse(), branch1);
+
+      // inner loop.
+      Node* loop2 = t.graph.NewNode(t.common.Loop(2), if_true1, t.start);
+      Node* phi2 =
+          t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p2, loop2);
+      Node* cond2 = t.graph.NewNode(&kIntAdd, phi2, p3);
+      Node* branch2 = t.graph.NewNode(t.common.Branch(), cond2, loop2);
+      Node* if_true2 = t.graph.NewNode(t.common.IfTrue(), branch2);
+      Node* exit2 = t.graph.NewNode(t.common.IfFalse(), branch2);
+      loop2->ReplaceInput(1, if_true2);
+      loop1->ReplaceInput(1, exit2);
+
+      Node* ret = t.graph.NewNode(t.common.Return(), phi1, t.start, exit1);
+      t.graph.SetEnd(ret);
+
+      Node* choices[] = {p1, phi1, cond1, phi2, cond2};
+      p1->ReplaceUses(choices[i]);
+      p2->ReplaceUses(choices[j]);
+      p3->ReplaceUses(choices[k]);
+
+      Node* header1[] = {loop1, phi1};
+      Node* body1[] = {cond1, branch1, if_true1, exit2,   loop2,
+                       phi2,  cond2,   branch2,  if_true2};
+      t.CheckLoop(header1, 2, body1, 9);
+
+      Node* header2[] = {loop2, phi2};
+      Node* body2[] = {cond2, branch2, if_true2};
+      t.CheckLoop(header2, 2, body2, 3);
+
+      Node* chain[] = {loop1, loop2};
+      t.CheckNestedLoops(chain, 2);
+    }
+  }
+}
+
+
+TEST(LaEdgeMatrix2_0) { RunEdgeMatrix2(0); }
+
+
+TEST(LaEdgeMatrix2_1) { RunEdgeMatrix2(1); }
+
+
+TEST(LaEdgeMatrix2_2) { RunEdgeMatrix2(2); }
+
+
+TEST(LaEdgeMatrix2_3) { RunEdgeMatrix2(3); }
+
+
+TEST(LaEdgeMatrix2_4) { RunEdgeMatrix2(4); }
+
+
+// Generates a triply-nested loop with extra edges between the phis and
+// conditions according to the edge choice parameters.
+void RunEdgeMatrix3(int c1a, int c1b, int c1c,    // line break
+                    int c2a, int c2b, int c2c,    // line break
+                    int c3a, int c3b, int c3c) {  // line break
+  LoopFinderTester t;
+
+  Node* p1a = t.jsgraph.Int32Constant(11);
+  Node* p1b = t.jsgraph.Int32Constant(22);
+  Node* p1c = t.jsgraph.Int32Constant(33);
+  Node* p2a = t.jsgraph.Int32Constant(44);
+  Node* p2b = t.jsgraph.Int32Constant(55);
+  Node* p2c = t.jsgraph.Int32Constant(66);
+  Node* p3a = t.jsgraph.Int32Constant(77);
+  Node* p3b = t.jsgraph.Int32Constant(88);
+  Node* p3c = t.jsgraph.Int32Constant(99);
+
+  // L1 depth = 0
+  Node* loop1 = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+  Node* phi1 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p1a, p1c, loop1);
+  Node* cond1 = t.graph.NewNode(&kIntAdd, phi1, p1b);
+  Node* branch1 = t.graph.NewNode(t.common.Branch(), cond1, loop1);
+  Node* if_true1 = t.graph.NewNode(t.common.IfTrue(), branch1);
+  Node* exit1 = t.graph.NewNode(t.common.IfFalse(), branch1);
+
+  // L2 depth = 1
+  Node* loop2 = t.graph.NewNode(t.common.Loop(2), if_true1, t.start);
+  Node* phi2 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p2a, p2c, loop2);
+  Node* cond2 = t.graph.NewNode(&kIntAdd, phi2, p2b);
+  Node* branch2 = t.graph.NewNode(t.common.Branch(), cond2, loop2);
+  Node* if_true2 = t.graph.NewNode(t.common.IfTrue(), branch2);
+  Node* exit2 = t.graph.NewNode(t.common.IfFalse(), branch2);
+
+  // L3 depth = 2
+  Node* loop3 = t.graph.NewNode(t.common.Loop(2), if_true2, t.start);
+  Node* phi3 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p3a, p3c, loop3);
+  Node* cond3 = t.graph.NewNode(&kIntAdd, phi3, p3b);
+  Node* branch3 = t.graph.NewNode(t.common.Branch(), cond3, loop3);
+  Node* if_true3 = t.graph.NewNode(t.common.IfTrue(), branch3);
+  Node* exit3 = t.graph.NewNode(t.common.IfFalse(), branch3);
+
+  loop3->ReplaceInput(1, if_true3);
+  loop2->ReplaceInput(1, exit3);
+  loop1->ReplaceInput(1, exit2);
+
+  Node* ret = t.graph.NewNode(t.common.Return(), phi1, t.start, exit1);
+  t.graph.SetEnd(ret);
+
+  // Mutate the graph according to the edge choices.
+
+  Node* o1[] = {t.one};
+  Node* o2[] = {t.one, phi1, cond1};
+  Node* o3[] = {t.one, phi1, cond1, phi2, cond2};
+
+  p1a->ReplaceUses(o1[c1a]);
+  p1b->ReplaceUses(o1[c1b]);
+
+  p2a->ReplaceUses(o2[c2a]);
+  p2b->ReplaceUses(o2[c2b]);
+
+  p3a->ReplaceUses(o3[c3a]);
+  p3b->ReplaceUses(o3[c3b]);
+
+  Node* l2[] = {phi1, cond1, phi2, cond2};
+  Node* l3[] = {phi1, cond1, phi2, cond2, phi3, cond3};
+
+  p1c->ReplaceUses(l2[c1c]);
+  p2c->ReplaceUses(l3[c2c]);
+  p3c->ReplaceUses(l3[c3c]);
+
+  // Run the tests and verify loop structure.
+
+  Node* chain[] = {loop1, loop2, loop3};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* header1[] = {loop1, phi1};
+  Node* body1[] = {cond1, branch1, if_true1, exit2,    loop2,
+                   phi2,  cond2,   branch2,  if_true2, exit3,
+                   loop3, phi3,    cond3,    branch3,  if_true3};
+  t.CheckLoop(header1, 2, body1, 15);
+
+  Node* header2[] = {loop2, phi2};
+  Node* body2[] = {cond2, branch2, if_true2, exit3,   loop3,
+                   phi3,  cond3,   branch3,  if_true3};
+  t.CheckLoop(header2, 2, body2, 9);
+
+  Node* header3[] = {loop3, phi3};
+  Node* body3[] = {cond3, branch3, if_true3};
+  t.CheckLoop(header3, 2, body3, 3);
+}
+
+
+// Runs all combinations with a fixed {i}.
+void RunEdgeMatrix3_i(int i) {
+  for (int a = 0; a < 1; a++) {
+    for (int b = 0; b < 1; b++) {
+      for (int c = 0; c < 4; c++) {
+        for (int d = 0; d < 3; d++) {
+          for (int e = 0; e < 3; e++) {
+            for (int f = 0; f < 6; f++) {
+              for (int g = 0; g < 5; g++) {
+                for (int h = 0; h < 5; h++) {
+                  RunEdgeMatrix3(a, b, c, d, e, f, g, h, i);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+
+// Test all possible legal triply-nested loops with conditions and phis.
+TEST(LaEdgeMatrix3_0) { RunEdgeMatrix3_i(0); }
+
+
+TEST(LaEdgeMatrix3_1) { RunEdgeMatrix3_i(1); }
+
+
+TEST(LaEdgeMatrix3_2) { RunEdgeMatrix3_i(2); }
+
+
+TEST(LaEdgeMatrix3_3) { RunEdgeMatrix3_i(3); }
+
+
+TEST(LaEdgeMatrix3_4) { RunEdgeMatrix3_i(4); }
+
+
+TEST(LaEdgeMatrix3_5) { RunEdgeMatrix3_i(5); }
diff --git a/test/cctest/compiler/test-loop-assignment-analysis.cc b/test/cctest/compiler/test-loop-assignment-analysis.cc
new file mode 100644
index 0000000..aabd95b
--- /dev/null
+++ b/test/cctest/compiler/test-loop-assignment-analysis.cc
@@ -0,0 +1,294 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/ast-loop-assignment-analyzer.h"
+#include "src/parser.h"
+#include "src/rewriter.h"
+#include "src/scopes.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+namespace {
+const int kBufferSize = 1024;
+
+struct TestHelper : public HandleAndZoneScope {
+  Handle<JSFunction> function;
+  LoopAssignmentAnalysis* result;
+
+  explicit TestHelper(const char* body)
+      : function(Handle<JSFunction>::null()), result(NULL) {
+    ScopedVector<char> program(kBufferSize);
+    SNPrintF(program, "function f(a,b,c) { %s; } f;", body);
+    v8::Local<v8::Value> v = CompileRun(program.start());
+    Handle<Object> obj = v8::Utils::OpenHandle(*v);
+    function = Handle<JSFunction>::cast(obj);
+  }
+
+  void CheckLoopAssignedCount(int expected, const char* var_name) {
+    // TODO(titzer): don't scope analyze every single time.
+    CompilationInfo info(function, main_zone());
+
+    CHECK(Parser::Parse(&info));
+    CHECK(Rewriter::Rewrite(&info));
+    CHECK(Scope::Analyze(&info));
+
+    Scope* scope = info.function()->scope();
+    AstValueFactory* factory = info.ast_value_factory();
+    CHECK_NE(NULL, scope);
+
+    if (result == NULL) {
+      AstLoopAssignmentAnalyzer analyzer(main_zone(), &info);
+      result = analyzer.Analyze();
+      CHECK_NE(NULL, result);
+    }
+
+    const i::AstRawString* name = factory->GetOneByteString(var_name);
+
+    i::Variable* var = scope->Lookup(name);
+    CHECK_NE(NULL, var);
+
+    if (var->location() == Variable::UNALLOCATED) {
+      CHECK_EQ(0, expected);
+    } else {
+      CHECK(var->IsStackAllocated());
+      CHECK_EQ(expected, result->GetAssignmentCountForTesting(scope, var));
+    }
+  }
+};
+}
+
+
+TEST(SimpleLoop1) {
+  TestHelper f("var x = 0; while (x) ;");
+
+  f.CheckLoopAssignedCount(0, "x");
+}
+
+
+TEST(SimpleLoop2) {
+  const char* loops[] = {
+      "while (x) { var x = 0; }",            "for(;;) { var x = 0; }",
+      "for(;x;) { var x = 0; }",             "for(;x;x) { var x = 0; }",
+      "for(var i = x; x; x) { var x = 0; }", "for(y in 0) { var x = 0; }",
+      "for(y of 0) { var x = 0; }",          "for(var x = 0; x; x++) { }",
+      "for(var x = 0; x++;) { }",            "var x; for(;x;x++) { }",
+      "var x; do { x = 1; } while (0);",     "do { var x = 1; } while (0);"};
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "x");
+  }
+}
+
+
+TEST(ForInOf1) {
+  const char* loops[] = {
+      "for(x in 0) { }", "for(x of 0) { }",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(0, "x");
+  }
+}
+
+
+TEST(Param1) {
+  TestHelper f("while (1) a = 0;");
+
+  f.CheckLoopAssignedCount(1, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param2) {
+  TestHelper f("for (;;) b = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(1, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param2b) {
+  TestHelper f("a; b; c; for (;;) b = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(1, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param3) {
+  TestHelper f("for(x in 0) c = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(1, "c");
+}
+
+
+TEST(Param3b) {
+  TestHelper f("a; b; c; for(x in 0) c = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(1, "c");
+}
+
+
+TEST(NestedLoop1) {
+  TestHelper f("while (x) { while (x) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+}
+
+
+TEST(NestedLoop2) {
+  TestHelper f("while (0) { while (0) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+}
+
+
+TEST(NestedLoop3) {
+  TestHelper f("while (0) { var y = 1; while (0) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+  f.CheckLoopAssignedCount(1, "y");
+}
+
+
+TEST(NestedInc1) {
+  const char* loops[] = {
+      "while (1) a(b++);",
+      "while (1) a(0, b++);",
+      "while (1) a(0, 0, b++);",
+      "while (1) a(b++, 1, 1);",
+      "while (1) a(++b);",
+      "while (1) a + (b++);",
+      "while (1) (b++) + a;",
+      "while (1) a + c(b++);",
+      "while (1) throw b++;",
+      "while (1) switch (b++) {} ;",
+      "while (1) switch (a) {case (b++): 0; } ;",
+      "while (1) switch (a) {case b: b++; } ;",
+      "while (1) a == (b++);",
+      "while (1) a === (b++);",
+      "while (1) +(b++);",
+      "while (1) ~(b++);",
+      "while (1) new a(b++);",
+      "while (1) (b++).f;",
+      "while (1) a[b++];",
+      "while (1) (b++)();",
+      "while (1) [b++];",
+      "while (1) [0,b++];",
+      "while (1) var y = [11,b++,12];",
+      "while (1) var y = {f:11,g:(b++),h:12};",
+      "while (1) try {b++;} finally {};",
+      "while (1) try {} finally {b++};",
+      "while (1) try {b++;} catch (e) {};",
+      "while (1) try {} catch (e) {b++};",
+      "while (1) return b++;",
+      "while (1) (b++) ? b : b;",
+      "while (1) b ? (b++) : b;",
+      "while (1) b ? b : (b++);",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "b");
+  }
+}
+
+
+TEST(NestedAssign1) {
+  const char* loops[] = {
+      "while (1) a(b=1);",
+      "while (1) a(0, b=1);",
+      "while (1) a(0, 0, b=1);",
+      "while (1) a(b=1, 1, 1);",
+      "while (1) a + (b=1);",
+      "while (1) (b=1) + a;",
+      "while (1) a + c(b=1);",
+      "while (1) throw b=1;",
+      "while (1) switch (b=1) {} ;",
+      "while (1) switch (a) {case b=1: 0; } ;",
+      "while (1) switch (a) {case b: b=1; } ;",
+      "while (1) a == (b=1);",
+      "while (1) a === (b=1);",
+      "while (1) +(b=1);",
+      "while (1) ~(b=1);",
+      "while (1) new a(b=1);",
+      "while (1) (b=1).f;",
+      "while (1) a[b=1];",
+      "while (1) (b=1)();",
+      "while (1) [b=1];",
+      "while (1) [0,b=1];",
+      "while (1) var z = [11,b=1,12];",
+      "while (1) var y = {f:11,g:(b=1),h:12};",
+      "while (1) try {b=1;} finally {};",
+      "while (1) try {} finally {b=1};",
+      "while (1) try {b=1;} catch (e) {};",
+      "while (1) try {} catch (e) {b=1};",
+      "while (1) return b=1;",
+      "while (1) (b=1) ? b : b;",
+      "while (1) b ? (b=1) : b;",
+      "while (1) b ? b : (b=1);",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "b");
+  }
+}
+
+
+TEST(NestedLoops3) {
+  TestHelper f("var x, y, z, w; while (x++) while (y++) while (z++) ; w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(2, "y");
+  f.CheckLoopAssignedCount(3, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
+
+
+TEST(NestedLoops3b) {
+  TestHelper f(
+      "var x, y, z, w;"
+      "while (1) { x=1; while (1) { y=1; while (1) z=1; } }"
+      "w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(2, "y");
+  f.CheckLoopAssignedCount(3, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
+
+
+TEST(NestedLoops3c) {
+  TestHelper f(
+      "var x, y, z, w;"
+      "while (1) {"
+      "  x++;"
+      "  while (1) {"
+      "    y++;"
+      "    while (1) z++;"
+      "  }"
+      "  while (1) {"
+      "    y++;"
+      "    while (1) z++;"
+      "  }"
+      "}"
+      "w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(3, "y");
+  f.CheckLoopAssignedCount(5, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
diff --git a/test/cctest/compiler/test-machine-operator-reducer.cc b/test/cctest/compiler/test-machine-operator-reducer.cc
index eca1f3c..648e1b9 100644
--- a/test/cctest/compiler/test-machine-operator-reducer.cc
+++ b/test/cctest/compiler/test-machine-operator-reducer.cc
@@ -5,9 +5,11 @@
 #include "test/cctest/cctest.h"
 
 #include "src/base/utils/random-number-generator.h"
+#include "src/codegen.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/machine-operator-reducer.h"
+#include "src/compiler/operator-properties.h"
 #include "src/compiler/typer.h"
 #include "test/cctest/compiler/value-helper.h"
 
@@ -49,15 +51,18 @@
 
 class ReducerTester : public HandleAndZoneScope {
  public:
-  explicit ReducerTester(int num_parameters = 0)
+  explicit ReducerTester(
+      int num_parameters = 0,
+      MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags)
       : isolate(main_isolate()),
         binop(NULL),
         unop(NULL),
+        machine(main_zone(), kMachPtr, flags),
         common(main_zone()),
         graph(main_zone()),
         javascript(main_zone()),
-        typer(main_zone()),
-        jsgraph(&graph, &common, &javascript, &typer, &machine),
+        typer(&graph, MaybeHandle<Context>()),
+        jsgraph(&graph, &common, &javascript, &machine),
         maxuint32(Constant<int32_t>(kMaxUInt32)) {
     Node* s = graph.NewNode(common.Start(num_parameters));
     graph.SetStart(s);
@@ -96,7 +101,7 @@
   template <typename T>
   void CheckFoldBinop(volatile T expect, Node* a, Node* b) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, a, b);
+    Node* n = CreateBinopNode(a, b);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -108,7 +113,7 @@
   // the {expect} node.
   void CheckBinop(Node* expect, Node* a, Node* b) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, a, b);
+    Node* n = CreateBinopNode(a, b);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -120,7 +125,7 @@
   void CheckFoldBinop(Node* left_expect, Node* right_expect, Node* left,
                       Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -135,7 +140,7 @@
   void CheckFoldBinop(volatile T left_expect, const Operator* op_expect,
                       Node* right_expect, Node* left, Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction r = reducer.Reduce(n);
     CHECK(r.Changed());
@@ -150,11 +155,13 @@
   void CheckFoldBinop(Node* left_expect, const Operator* op_expect,
                       volatile T right_expect, Node* left, Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction r = reducer.Reduce(n);
     CHECK(r.Changed());
     CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
+    CHECK_EQ(OperatorProperties::GetTotalInputCount(op_expect),
+             r.replacement()->InputCount());
     CHECK_EQ(left_expect, r.replacement()->InputAt(0));
     CHECK_EQ(right_expect, ValueOf<T>(r.replacement()->InputAt(1)->op()));
   }
@@ -167,7 +174,7 @@
     Node* p = Parameter();
     Node* k = Constant<T>(constant);
     {
-      Node* n = graph.NewNode(binop, k, p);
+      Node* n = CreateBinopNode(k, p);
       MachineOperatorReducer reducer(&jsgraph);
       Reduction reduction = reducer.Reduce(n);
       CHECK(!reduction.Changed() || reduction.replacement() == n);
@@ -175,7 +182,7 @@
       CHECK_EQ(k, n->InputAt(1));
     }
     {
-      Node* n = graph.NewNode(binop, p, k);
+      Node* n = CreateBinopNode(p, k);
       MachineOperatorReducer reducer(&jsgraph);
       Reduction reduction = reducer.Reduce(n);
       CHECK(!reduction.Changed());
@@ -191,7 +198,7 @@
     CHECK(!binop->HasProperty(Operator::kCommutative));
     Node* p = Parameter();
     Node* k = Constant<T>(constant);
-    Node* n = graph.NewNode(binop, k, p);
+    Node* n = CreateBinopNode(k, p);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(!reduction.Changed());
@@ -202,6 +209,15 @@
   Node* Parameter(int32_t index = 0) {
     return graph.NewNode(common.Parameter(index), graph.start());
   }
+
+ private:
+  Node* CreateBinopNode(Node* left, Node* right) {
+    if (binop->ControlInputCount() > 0) {
+      return graph.NewNode(binop, left, right, graph.start());
+    } else {
+      return graph.NewNode(binop, left, right);
+    }
+  }
 };
 
 
@@ -343,7 +359,36 @@
 }
 
 
-TEST(ReduceWord32Equal) {
+static void CheckJsShift(ReducerTester* R) {
+  DCHECK(R->machine.Word32ShiftIsSafe());
+
+  Node* x = R->Parameter(0);
+  Node* y = R->Parameter(1);
+  Node* thirty_one = R->Constant<int32_t>(0x1f);
+  Node* y_and_thirty_one =
+      R->graph.NewNode(R->machine.Word32And(), y, thirty_one);
+
+  // If the underlying machine shift instructions 'and' their right operand
+  // with 0x1f then:  x << (y & 0x1f) => x << y
+  R->CheckFoldBinop(x, y, x, y_and_thirty_one);
+}
+
+
+TEST(ReduceJsShifts) {
+  ReducerTester R(0, MachineOperatorBuilder::kWord32ShiftIsSafe);
+
+  R.binop = R.machine.Word32Shl();
+  CheckJsShift(&R);
+
+  R.binop = R.machine.Word32Shr();
+  CheckJsShift(&R);
+
+  R.binop = R.machine.Word32Sar();
+  CheckJsShift(&R);
+}
+
+
+TEST(Word32Equal) {
   ReducerTester R;
   R.binop = R.machine.Word32Equal();
 
@@ -476,9 +521,9 @@
 }
 
 
-TEST(ReduceInt32UDiv) {
+TEST(ReduceUint32Div) {
   ReducerTester R;
-  R.binop = R.machine.Int32UDiv();
+  R.binop = R.machine.Uint32Div();
 
   FOR_UINT32_INPUTS(pl) {
     FOR_UINT32_INPUTS(pr) {
@@ -529,9 +574,9 @@
 }
 
 
-TEST(ReduceInt32UMod) {
+TEST(ReduceUint32Mod) {
   ReducerTester R;
-  R.binop = R.machine.Int32UMod();
+  R.binop = R.machine.Uint32Mod();
 
   FOR_INT32_INPUTS(pl) {
     FOR_INT32_INPUTS(pr) {
@@ -687,9 +732,9 @@
          pr != nans.end(); ++pr) {
       Node* nan1 = R->Constant<double>(*pl);
       Node* nan2 = R->Constant<double>(*pr);
-      R->CheckBinop(nan1, x, nan1);     // x % NaN => NaN
-      R->CheckBinop(nan1, nan1, x);     // NaN % x => NaN
-      R->CheckBinop(nan1, nan2, nan1);  // NaN % NaN => NaN
+      R->CheckBinop(nan1, x, nan1);     // x op NaN => NaN
+      R->CheckBinop(nan1, nan1, x);     // NaN op x => NaN
+      R->CheckBinop(nan1, nan2, nan1);  // NaN op NaN => NaN
     }
   }
 }
@@ -706,8 +751,15 @@
     }
   }
 
-  FOR_FLOAT64_INPUTS(i) { R.CheckPutConstantOnRight(*i); }
-  // TODO(titzer): CheckNans(&R);
+  FOR_FLOAT64_INPUTS(i) {
+    Double tmp(*i);
+    if (!tmp.IsSpecial() || tmp.IsInfinite()) {
+      // Don't check NaNs as they are reduced more.
+      R.CheckPutConstantOnRight(*i);
+    }
+  }
+
+  CheckNans(&R);
 }
 
 
@@ -721,7 +773,13 @@
       R.CheckFoldBinop<double>(x - y, x, y);
     }
   }
-  // TODO(titzer): CheckNans(&R);
+
+  Node* zero = R.Constant<double>(0.0);
+  Node* x = R.Parameter();
+
+  R.CheckBinop(x, x, zero);  // x - 0.0 => x
+
+  CheckNans(&R);
 }
 
 
@@ -783,6 +841,11 @@
     }
   }
 
+  Node* x = R.Parameter();
+  Node* zero = R.Constant<double>(0.0);
+
+  R.CheckFoldBinop<double>(v8::base::OS::nan_value(), x, zero);
+
   CheckNans(&R);
 }
 
@@ -800,9 +863,9 @@
 // TODO(titzer): test MachineOperatorReducer for Int64Mul
 // TODO(titzer): test MachineOperatorReducer for Int64UMul
 // TODO(titzer): test MachineOperatorReducer for Int64Div
-// TODO(titzer): test MachineOperatorReducer for Int64UDiv
+// TODO(titzer): test MachineOperatorReducer for Uint64Div
 // TODO(titzer): test MachineOperatorReducer for Int64Mod
-// TODO(titzer): test MachineOperatorReducer for Int64UMod
+// TODO(titzer): test MachineOperatorReducer for Uint64Mod
 // TODO(titzer): test MachineOperatorReducer for Int64Neg
 // TODO(titzer): test MachineOperatorReducer for ChangeInt32ToFloat64
 // TODO(titzer): test MachineOperatorReducer for ChangeFloat64ToInt32
diff --git a/test/cctest/compiler/test-node-algorithm.cc b/test/cctest/compiler/test-node-algorithm.cc
index 10f98a6..842d182 100644
--- a/test/cctest/compiler/test-node-algorithm.cc
+++ b/test/cctest/compiler/test-node-algorithm.cc
@@ -8,25 +8,23 @@
 
 #include "graph-tester.h"
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/graph-visualizer.h"
+#include "src/compiler/node.h"
 #include "src/compiler/operator.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 1, 0, 0);
 
 class PreNodeVisitor : public NullNodeVisitor {
  public:
-  GenericGraphVisit::Control Pre(Node* node) {
+  void Pre(Node* node) {
     printf("NODE ID: %d\n", node->id());
     nodes_.push_back(node);
-    return GenericGraphVisit::CONTINUE;
   }
   std::vector<Node*> nodes_;
 };
@@ -34,45 +32,14 @@
 
 class PostNodeVisitor : public NullNodeVisitor {
  public:
-  GenericGraphVisit::Control Post(Node* node) {
+  void Post(Node* node) {
     printf("NODE ID: %d\n", node->id());
     nodes_.push_back(node);
-    return GenericGraphVisit::CONTINUE;
   }
   std::vector<Node*> nodes_;
 };
 
 
-TEST(TestUseNodeVisitEmpty) {
-  GraphWithStartNodeTester graph;
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(1, static_cast<int>(node_visitor.nodes_.size()));
-}
-
-
-TEST(TestUseNodePreOrderVisitSimple) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, n2);
-  Node* n4 = graph.NewNode(&dummy_operator, n2, n3);
-  Node* n5 = graph.NewNode(&dummy_operator, n4, n2);
-  graph.SetEnd(n5);
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(5, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.start()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n2->id() == node_visitor.nodes_[1]->id());
-  CHECK(n3->id() == node_visitor.nodes_[2]->id());
-  CHECK(n4->id() == node_visitor.nodes_[3]->id());
-  CHECK(n5->id() == node_visitor.nodes_[4]->id());
-}
-
-
 TEST(TestInputNodePreOrderVisitSimple) {
   GraphWithStartNodeTester graph;
   Node* n2 = graph.NewNode(&dummy_operator, graph.start());
@@ -92,223 +59,6 @@
 }
 
 
-TEST(TestUseNodePostOrderVisitSimple) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n4 = graph.NewNode(&dummy_operator, n2);
-  Node* n5 = graph.NewNode(&dummy_operator, n2);
-  Node* n6 = graph.NewNode(&dummy_operator, n2);
-  Node* n7 = graph.NewNode(&dummy_operator, n3);
-  Node* end_dependencies[4] = {n4, n5, n6, n7};
-  Node* n8 = graph.NewNode(&dummy_operator, 4, end_dependencies);
-  graph.SetEnd(n8);
-
-  PostNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(8, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.end()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n4->id() == node_visitor.nodes_[1]->id());
-  CHECK(n5->id() == node_visitor.nodes_[2]->id());
-  CHECK(n6->id() == node_visitor.nodes_[3]->id());
-  CHECK(n2->id() == node_visitor.nodes_[4]->id());
-  CHECK(n7->id() == node_visitor.nodes_[5]->id());
-  CHECK(n3->id() == node_visitor.nodes_[6]->id());
-  CHECK(graph.start()->id() == node_visitor.nodes_[7]->id());
-}
-
-
-TEST(TestUseNodePostOrderVisitLong) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n4 = graph.NewNode(&dummy_operator, n2);
-  Node* n5 = graph.NewNode(&dummy_operator, n2);
-  Node* n6 = graph.NewNode(&dummy_operator, n3);
-  Node* n7 = graph.NewNode(&dummy_operator, n3);
-  Node* n8 = graph.NewNode(&dummy_operator, n5);
-  Node* n9 = graph.NewNode(&dummy_operator, n5);
-  Node* n10 = graph.NewNode(&dummy_operator, n9);
-  Node* n11 = graph.NewNode(&dummy_operator, n9);
-  Node* end_dependencies[6] = {n4, n8, n10, n11, n6, n7};
-  Node* n12 = graph.NewNode(&dummy_operator, 6, end_dependencies);
-  graph.SetEnd(n12);
-
-  PostNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(12, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.end()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n4->id() == node_visitor.nodes_[1]->id());
-  CHECK(n8->id() == node_visitor.nodes_[2]->id());
-  CHECK(n10->id() == node_visitor.nodes_[3]->id());
-  CHECK(n11->id() == node_visitor.nodes_[4]->id());
-  CHECK(n9->id() == node_visitor.nodes_[5]->id());
-  CHECK(n5->id() == node_visitor.nodes_[6]->id());
-  CHECK(n2->id() == node_visitor.nodes_[7]->id());
-  CHECK(n6->id() == node_visitor.nodes_[8]->id());
-  CHECK(n7->id() == node_visitor.nodes_[9]->id());
-  CHECK(n3->id() == node_visitor.nodes_[10]->id());
-  CHECK(graph.start()->id() == node_visitor.nodes_[11]->id());
-}
-
-
-TEST(TestUseNodePreOrderVisitCycle) {
-  GraphWithStartNodeTester graph;
-  Node* n0 = graph.start_node();
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n2 = graph.NewNode(&dummy_operator, n1);
-  n0->AppendInput(graph.main_zone(), n2);
-  graph.SetStart(n0);
-  graph.SetEnd(n2);
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(3, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(n0->id() == node_visitor.nodes_[0]->id());
-  CHECK(n1->id() == node_visitor.nodes_[1]->id());
-  CHECK(n2->id() == node_visitor.nodes_[2]->id());
-}
-
-
-struct ReenterNodeVisitor : NullNodeVisitor {
-  GenericGraphVisit::Control Pre(Node* node) {
-    printf("[%d] PRE NODE: %d\n", static_cast<int>(nodes_.size()), node->id());
-    nodes_.push_back(node->id());
-    int size = static_cast<int>(nodes_.size());
-    switch (node->id()) {
-      case 0:
-        return size < 6 ? GenericGraphVisit::REENTER : GenericGraphVisit::SKIP;
-      case 1:
-        return size < 4 ? GenericGraphVisit::DEFER
-                        : GenericGraphVisit::CONTINUE;
-      default:
-        return GenericGraphVisit::REENTER;
-    }
-  }
-
-  GenericGraphVisit::Control Post(Node* node) {
-    printf("[%d] POST NODE: %d\n", static_cast<int>(nodes_.size()), node->id());
-    nodes_.push_back(-node->id());
-    return node->id() == 4 ? GenericGraphVisit::REENTER
-                           : GenericGraphVisit::CONTINUE;
-  }
-
-  void PreEdge(Node* from, int index, Node* to) {
-    printf("[%d] PRE EDGE: %d-%d\n", static_cast<int>(edges_.size()),
-           from->id(), to->id());
-    edges_.push_back(std::make_pair(from->id(), to->id()));
-  }
-
-  void PostEdge(Node* from, int index, Node* to) {
-    printf("[%d] POST EDGE: %d-%d\n", static_cast<int>(edges_.size()),
-           from->id(), to->id());
-    edges_.push_back(std::make_pair(-from->id(), -to->id()));
-  }
-
-  std::vector<int> nodes_;
-  std::vector<std::pair<int, int> > edges_;
-};
-
-
-TEST(TestUseNodeReenterVisit) {
-  GraphWithStartNodeTester graph;
-  Node* n0 = graph.start_node();
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n2 = graph.NewNode(&dummy_operator, n0);
-  Node* n3 = graph.NewNode(&dummy_operator, n2);
-  Node* n4 = graph.NewNode(&dummy_operator, n0);
-  Node* n5 = graph.NewNode(&dummy_operator, n4);
-  n0->AppendInput(graph.main_zone(), n3);
-  graph.SetStart(n0);
-  graph.SetEnd(n5);
-
-  ReenterNodeVisitor visitor;
-  graph.VisitNodeUsesFromStart(&visitor);
-
-  CHECK_EQ(22, static_cast<int>(visitor.nodes_.size()));
-  CHECK_EQ(24, static_cast<int>(visitor.edges_.size()));
-
-  CHECK(n0->id() == visitor.nodes_[0]);
-  CHECK(n0->id() == visitor.edges_[0].first);
-  CHECK(n1->id() == visitor.edges_[0].second);
-  CHECK(n1->id() == visitor.nodes_[1]);
-  // N1 is deferred.
-  CHECK(-n1->id() == visitor.edges_[1].second);
-  CHECK(-n0->id() == visitor.edges_[1].first);
-  CHECK(n0->id() == visitor.edges_[2].first);
-  CHECK(n2->id() == visitor.edges_[2].second);
-  CHECK(n2->id() == visitor.nodes_[2]);
-  CHECK(n2->id() == visitor.edges_[3].first);
-  CHECK(n3->id() == visitor.edges_[3].second);
-  CHECK(n3->id() == visitor.nodes_[3]);
-  // Circle back to N0, which we may reenter for now.
-  CHECK(n3->id() == visitor.edges_[4].first);
-  CHECK(n0->id() == visitor.edges_[4].second);
-  CHECK(n0->id() == visitor.nodes_[4]);
-  CHECK(n0->id() == visitor.edges_[5].first);
-  CHECK(n1->id() == visitor.edges_[5].second);
-  CHECK(n1->id() == visitor.nodes_[5]);
-  // This time N1 is no longer deferred.
-  CHECK(-n1->id() == visitor.nodes_[6]);
-  CHECK(-n1->id() == visitor.edges_[6].second);
-  CHECK(-n0->id() == visitor.edges_[6].first);
-  CHECK(n0->id() == visitor.edges_[7].first);
-  CHECK(n2->id() == visitor.edges_[7].second);
-  CHECK(n2->id() == visitor.nodes_[7]);
-  CHECK(n2->id() == visitor.edges_[8].first);
-  CHECK(n3->id() == visitor.edges_[8].second);
-  CHECK(n3->id() == visitor.nodes_[8]);
-  CHECK(n3->id() == visitor.edges_[9].first);
-  CHECK(n0->id() == visitor.edges_[9].second);
-  CHECK(n0->id() == visitor.nodes_[9]);
-  // This time we break at N0 and skip it.
-  CHECK(-n0->id() == visitor.edges_[10].second);
-  CHECK(-n3->id() == visitor.edges_[10].first);
-  CHECK(-n3->id() == visitor.nodes_[10]);
-  CHECK(-n3->id() == visitor.edges_[11].second);
-  CHECK(-n2->id() == visitor.edges_[11].first);
-  CHECK(-n2->id() == visitor.nodes_[11]);
-  CHECK(-n2->id() == visitor.edges_[12].second);
-  CHECK(-n0->id() == visitor.edges_[12].first);
-  CHECK(n0->id() == visitor.edges_[13].first);
-  CHECK(n4->id() == visitor.edges_[13].second);
-  CHECK(n4->id() == visitor.nodes_[12]);
-  CHECK(n4->id() == visitor.edges_[14].first);
-  CHECK(n5->id() == visitor.edges_[14].second);
-  CHECK(n5->id() == visitor.nodes_[13]);
-  CHECK(-n5->id() == visitor.nodes_[14]);
-  CHECK(-n5->id() == visitor.edges_[15].second);
-  CHECK(-n4->id() == visitor.edges_[15].first);
-  CHECK(-n4->id() == visitor.nodes_[15]);
-  CHECK(-n4->id() == visitor.edges_[16].second);
-  CHECK(-n0->id() == visitor.edges_[16].first);
-  CHECK(-n0->id() == visitor.nodes_[16]);
-  CHECK(-n0->id() == visitor.edges_[17].second);
-  CHECK(-n3->id() == visitor.edges_[17].first);
-  CHECK(-n3->id() == visitor.nodes_[17]);
-  CHECK(-n3->id() == visitor.edges_[18].second);
-  CHECK(-n2->id() == visitor.edges_[18].first);
-  CHECK(-n2->id() == visitor.nodes_[18]);
-  CHECK(-n2->id() == visitor.edges_[19].second);
-  CHECK(-n0->id() == visitor.edges_[19].first);
-  // N4 may be reentered.
-  CHECK(n0->id() == visitor.edges_[20].first);
-  CHECK(n4->id() == visitor.edges_[20].second);
-  CHECK(n4->id() == visitor.nodes_[19]);
-  CHECK(n4->id() == visitor.edges_[21].first);
-  CHECK(n5->id() == visitor.edges_[21].second);
-  CHECK(-n5->id() == visitor.edges_[22].second);
-  CHECK(-n4->id() == visitor.edges_[22].first);
-  CHECK(-n4->id() == visitor.nodes_[20]);
-  CHECK(-n4->id() == visitor.edges_[23].second);
-  CHECK(-n0->id() == visitor.edges_[23].first);
-  CHECK(-n0->id() == visitor.nodes_[21]);
-}
-
-
 TEST(TestPrintNodeGraphToNodeGraphviz) {
   GraphWithStartNodeTester graph;
   Node* n2 = graph.NewNode(&dummy_operator, graph.start());
diff --git a/test/cctest/compiler/test-node-cache.cc b/test/cctest/compiler/test-node-cache.cc
index 3569386..a48adb9 100644
--- a/test/cctest/compiler/test-node-cache.cc
+++ b/test/cctest/compiler/test-node-cache.cc
@@ -115,46 +115,61 @@
 }
 
 
-TEST(PtrConstant_back_to_back) {
-  GraphTester graph;
-  PtrNodeCache cache;
-  int32_t buffer[50];
+static bool Contains(NodeVector* nodes, Node* n) {
+  for (size_t i = 0; i < nodes->size(); i++) {
+    if (nodes->at(i) == n) return true;
+  }
+  return false;
+}
 
-  for (int32_t* p = buffer;
-       (p - buffer) < static_cast<ptrdiff_t>(arraysize(buffer)); p++) {
-    Node** pos = cache.Find(graph.zone(), p);
-    CHECK_NE(NULL, pos);
-    for (int j = 0; j < 3; j++) {
-      Node** npos = cache.Find(graph.zone(), p);
-      CHECK_EQ(pos, npos);
+
+TEST(NodeCache_GetCachedNodes_int32) {
+  GraphTester graph;
+  Int32NodeCache cache;
+  CommonOperatorBuilder common(graph.zone());
+
+  int32_t constants[] = {0, 311, 12,  13,  14,  555, -555, -44, -33, -22, -11,
+                         0, 311, 311, 412, 412, 11,  11,   -33, -33, -22, -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    Node** pos = cache.Find(graph.zone(), k);
+    if (*pos != NULL) {
+      NodeVector nodes(graph.zone());
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, *pos));
+    } else {
+      NodeVector nodes(graph.zone());
+      Node* n = graph.NewNode(common.Int32Constant(k));
+      *pos = n;
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, n));
     }
   }
 }
 
 
-TEST(PtrConstant_hits) {
+TEST(NodeCache_GetCachedNodes_int64) {
   GraphTester graph;
-  PtrNodeCache cache;
-  const int32_t kSize = 50;
-  int32_t buffer[kSize];
-  Node* nodes[kSize];
+  Int64NodeCache cache;
   CommonOperatorBuilder common(graph.zone());
 
-  for (size_t i = 0; i < arraysize(buffer); i++) {
-    int k = static_cast<int>(i);
-    int32_t* p = &buffer[i];
-    nodes[i] = graph.NewNode(common.Int32Constant(k));
-    *cache.Find(graph.zone(), p) = nodes[i];
-  }
+  int64_t constants[] = {0, 311, 12,  13,  14,  555, -555, -44, -33, -22, -11,
+                         0, 311, 311, 412, 412, 11,  11,   -33, -33, -22, -11};
 
-  int hits = 0;
-  for (size_t i = 0; i < arraysize(buffer); i++) {
-    int32_t* p = &buffer[i];
-    Node** pos = cache.Find(graph.zone(), p);
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int64_t k = constants[i];
+    Node** pos = cache.Find(graph.zone(), k);
     if (*pos != NULL) {
-      CHECK_EQ(nodes[i], *pos);
-      hits++;
+      NodeVector nodes(graph.zone());
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, *pos));
+    } else {
+      NodeVector nodes(graph.zone());
+      Node* n = graph.NewNode(common.Int64Constant(k));
+      *pos = n;
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, n));
     }
   }
-  CHECK_LT(4, hits);
 }
diff --git a/test/cctest/compiler/test-node.cc b/test/cctest/compiler/test-node.cc
index 28d807e..eafabd3 100644
--- a/test/cctest/compiler/test-node.cc
+++ b/test/cctest/compiler/test-node.cc
@@ -7,15 +7,14 @@
 #include "src/v8.h"
 
 #include "graph-tester.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/node.h"
 #include "src/compiler/operator.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 1, 0, 0);
 
 TEST(NodeAllocation) {
   GraphTester graph;
@@ -93,10 +92,8 @@
 TEST(NodeUseIteratorEmpty) {
   GraphTester graph;
   Node* n1 = graph.NewNode(&dummy_operator);
-  Node::Uses::iterator i(n1->uses().begin());
   int use_count = 0;
-  for (; i != n1->uses().end(); ++i) {
-    Node::Edge edge(i.edge());
+  for (Edge const edge : n1->use_edges()) {
     USE(edge);
     use_count++;
   }
@@ -366,31 +363,31 @@
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
 
-  Node::Inputs inputs(n2->inputs());
-  Node::Inputs::iterator current = inputs.begin();
+  Node::InputEdges inputs(n2->input_edges());
+  Node::InputEdges::iterator current = inputs.begin();
   CHECK(current != inputs.end());
-  CHECK(*current == n0);
+  CHECK((*current).to() == n0);
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n1);
+  CHECK((*current).to() == n1);
   ++current;
   CHECK(current == inputs.end());
 
   Node* n3 = graph.NewNode(&dummy_operator);
   n2->AppendInput(graph.zone(), n3);
-  inputs = n2->inputs();
+  inputs = n2->input_edges();
   current = inputs.begin();
   CHECK(current != inputs.end());
-  CHECK(*current == n0);
-  CHECK_EQ(0, current.index());
+  CHECK((*current).to() == n0);
+  CHECK_EQ(0, (*current).index());
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n1);
-  CHECK_EQ(1, current.index());
+  CHECK((*current).to() == n1);
+  CHECK_EQ(1, (*current).index());
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n3);
-  CHECK_EQ(2, current.index());
+  CHECK((*current).to() == n3);
+  CHECK_EQ(2, (*current).index());
   ++current;
   CHECK(current == inputs.end());
 }
diff --git a/test/cctest/compiler/test-operator.cc b/test/cctest/compiler/test-operator.cc
index af75d67..39f660f 100644
--- a/test/cctest/compiler/test-operator.cc
+++ b/test/cctest/compiler/test-operator.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #include "src/compiler/operator.h"
@@ -10,44 +12,45 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-#define NaN (v8::base::OS::nan_value())
-#define Infinity (std::numeric_limits<double>::infinity())
+#define NONE Operator::kNoProperties
+#define FOLD Operator::kFoldable
 
-TEST(TestOperatorMnemonic) {
-  SimpleOperator op1(10, Operator::kNoProperties, 0, 0, "ThisOne");
+
+TEST(TestOperator_Mnemonic) {
+  Operator op1(10, NONE, "ThisOne", 0, 0, 0, 0, 0, 0);
   CHECK_EQ(0, strcmp(op1.mnemonic(), "ThisOne"));
 
-  SimpleOperator op2(11, Operator::kNoProperties, 0, 0, "ThatOne");
+  Operator op2(11, NONE, "ThatOne", 0, 0, 0, 0, 0, 0);
   CHECK_EQ(0, strcmp(op2.mnemonic(), "ThatOne"));
 
-  Operator1<int> op3(12, Operator::kNoProperties, 0, 1, "Mnemonic1", 12333);
+  Operator1<int> op3(12, NONE, "Mnemonic1", 0, 0, 0, 1, 0, 0, 12333);
   CHECK_EQ(0, strcmp(op3.mnemonic(), "Mnemonic1"));
 
-  Operator1<double> op4(13, Operator::kNoProperties, 0, 1, "TheOther", 99.9);
+  Operator1<double> op4(13, NONE, "TheOther", 0, 0, 0, 1, 0, 0, 99.9);
   CHECK_EQ(0, strcmp(op4.mnemonic(), "TheOther"));
 }
 
 
-TEST(TestSimpleOperatorHash) {
-  SimpleOperator op1(17, Operator::kNoProperties, 0, 0, "Another");
-  CHECK_EQ(17, op1.HashCode());
+TEST(TestOperator_Hash) {
+  Operator op1(17, NONE, "Another", 0, 0, 0, 0, 0, 0);
+  CHECK_EQ(17, static_cast<int>(op1.HashCode()));
 
-  SimpleOperator op2(18, Operator::kNoProperties, 0, 0, "Falsch");
-  CHECK_EQ(18, op2.HashCode());
+  Operator op2(18, NONE, "Falsch", 0, 0, 0, 0, 0, 0);
+  CHECK_EQ(18, static_cast<int>(op2.HashCode()));
 }
 
 
-TEST(TestSimpleOperatorEquals) {
-  SimpleOperator op1a(19, Operator::kNoProperties, 0, 0, "Another1");
-  SimpleOperator op1b(19, Operator::kFoldable, 2, 2, "Another2");
+TEST(TestOperator_Equals) {
+  Operator op1a(19, NONE, "Another1", 0, 0, 0, 0, 0, 0);
+  Operator op1b(19, FOLD, "Another2", 2, 0, 0, 2, 0, 0);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  SimpleOperator op2a(20, Operator::kNoProperties, 0, 0, "Falsch1");
-  SimpleOperator op2b(20, Operator::kFoldable, 1, 1, "Falsch2");
+  Operator op2a(20, NONE, "Falsch1", 0, 0, 0, 0, 0, 0);
+  Operator op2b(20, FOLD, "Falsch2", 1, 0, 0, 1, 0, 0);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(op2a.Equals(&op2b));
@@ -67,52 +70,52 @@
 
 
 static SmartArrayPointer<const char> OperatorToString(Operator* op) {
-  OStringStream os;
+  std::ostringstream os;
   os << *op;
-  return SmartArrayPointer<const char>(StrDup(os.c_str()));
+  return SmartArrayPointer<const char>(StrDup(os.str().c_str()));
 }
 
 
-TEST(TestSimpleOperatorPrint) {
-  SimpleOperator op1a(19, Operator::kNoProperties, 0, 0, "Another1");
-  SimpleOperator op1b(19, Operator::kFoldable, 2, 2, "Another2");
+TEST(TestOperator_Print) {
+  Operator op1a(19, NONE, "Another1", 0, 0, 0, 0, 0, 0);
+  Operator op1b(19, FOLD, "Another2", 2, 0, 0, 2, 0, 0);
 
   CHECK_EQ("Another1", OperatorToString(&op1a).get());
   CHECK_EQ("Another2", OperatorToString(&op1b).get());
 
-  SimpleOperator op2a(20, Operator::kNoProperties, 0, 0, "Flog1");
-  SimpleOperator op2b(20, Operator::kFoldable, 1, 1, "Flog2");
+  Operator op2a(20, NONE, "Flog1", 0, 0, 0, 0, 0, 0);
+  Operator op2b(20, FOLD, "Flog2", 1, 0, 0, 1, 0, 0);
 
   CHECK_EQ("Flog1", OperatorToString(&op2a).get());
   CHECK_EQ("Flog2", OperatorToString(&op2b).get());
 }
 
 
-TEST(TestOperator1intHash) {
-  Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11);
-  Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11);
+TEST(TestOperator1int_Hash) {
+  Operator1<int> op1a(23, NONE, "Wolfie", 0, 0, 0, 0, 0, 0, 11);
+  Operator1<int> op1b(23, FOLD, "Doggie", 2, 0, 0, 2, 0, 0, 11);
 
-  CHECK_EQ(op1a.HashCode(), op1b.HashCode());
+  CHECK(op1a.HashCode() == op1b.HashCode());
 
-  Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", 3);
-  Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", 4);
+  Operator1<int> op2a(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, 3);
+  Operator1<int> op2b(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, 4);
 
-  CHECK_NE(op1a.HashCode(), op2a.HashCode());
-  CHECK_NE(op2a.HashCode(), op2b.HashCode());
+  CHECK(op1a.HashCode() != op2a.HashCode());
+  CHECK(op2a.HashCode() != op2b.HashCode());
 }
 
 
-TEST(TestOperator1intEquals) {
-  Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Scratchy", 11);
-  Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Scratchy", 11);
+TEST(TestOperator1int_Equals) {
+  Operator1<int> op1a(23, NONE, "Scratchy", 0, 0, 0, 0, 0, 0, 11);
+  Operator1<int> op1b(23, FOLD, "Scratchy", 2, 0, 0, 2, 0, 0, 11);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Im", 3);
-  Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Im", 4);
+  Operator1<int> op2a(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3);
+  Operator1<int> op2b(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 4);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(!op2a.Equals(&op2b));
@@ -129,7 +132,7 @@
   CHECK(!op2b.Equals(&op1a));
   CHECK(!op2b.Equals(&op1b));
 
-  SimpleOperator op3(25, Operator::kNoProperties, 0, 0, "Weepy");
+  Operator op3(25, NONE, "Weepy", 0, 0, 0, 0, 0, 0);
 
   CHECK(!op1a.Equals(&op3));
   CHECK(!op1b.Equals(&op3));
@@ -143,46 +146,55 @@
 }
 
 
-TEST(TestOperator1intPrint) {
-  Operator1<int> op1(12, Operator::kNoProperties, 0, 1, "Op1Test", 0);
+TEST(TestOperator1int_Print) {
+  Operator1<int> op1(12, NONE, "Op1Test", 0, 0, 0, 1, 0, 0, 0);
   CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
 
-  Operator1<int> op2(12, Operator::kNoProperties, 0, 1, "Op1Test", 66666666);
+  Operator1<int> op2(12, NONE, "Op1Test", 0, 0, 0, 1, 0, 0, 66666666);
   CHECK_EQ("Op1Test[66666666]", OperatorToString(&op2).get());
 
-  Operator1<int> op3(12, Operator::kNoProperties, 0, 1, "FooBar", 2347);
+  Operator1<int> op3(12, NONE, "FooBar", 0, 0, 0, 1, 0, 0, 2347);
   CHECK_EQ("FooBar[2347]", OperatorToString(&op3).get());
 
-  Operator1<int> op4(12, Operator::kNoProperties, 0, 1, "BarFoo", -879);
+  Operator1<int> op4(12, NONE, "BarFoo", 0, 0, 0, 1, 0, 0, -879);
   CHECK_EQ("BarFoo[-879]", OperatorToString(&op4).get());
 }
 
 
-TEST(TestOperator1doubleHash) {
-  Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11.77);
-  Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11.77);
+TEST(TestOperator1double_Hash) {
+  Operator1<double> op1a(23, NONE, "Wolfie", 0, 0, 0, 0, 0, 0, 11.77);
+  Operator1<double> op1b(23, FOLD, "Doggie", 2, 0, 0, 2, 0, 0, 11.77);
 
-  CHECK_EQ(op1a.HashCode(), op1b.HashCode());
+  CHECK(op1a.HashCode() == op1b.HashCode());
 
-  Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", -6.7);
-  Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", -6.8);
+  Operator1<double> op2a(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, -6.7);
+  Operator1<double> op2b(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, -6.8);
 
-  CHECK_NE(op1a.HashCode(), op2a.HashCode());
-  CHECK_NE(op2a.HashCode(), op2b.HashCode());
+  CHECK(op1a.HashCode() != op2a.HashCode());
+  CHECK(op2a.HashCode() != op2b.HashCode());
 }
 
 
-TEST(TestOperator1doubleEquals) {
-  Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Scratchy", 11.77);
-  Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Scratchy", 11.77);
+TEST(TestOperator1doublePrint) {
+  Operator1<double> op1a(23, NONE, "Canary", 0, 0, 0, 0, 0, 0, 0.5);
+  Operator1<double> op1b(23, FOLD, "Finch", 2, 0, 0, 2, 0, 0, -1.5);
+
+  CHECK_EQ("Canary[0.5]", OperatorToString(&op1a).get());
+  CHECK_EQ("Finch[-1.5]", OperatorToString(&op1b).get());
+}
+
+
+TEST(TestOperator1double_Equals) {
+  Operator1<double> op1a(23, NONE, "Scratchy", 0, 0, 0, 0, 0, 0, 11.77);
+  Operator1<double> op1b(23, FOLD, "Scratchy", 2, 0, 0, 2, 0, 0, 11.77);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Im", 3.1);
-  Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Im", 3.2);
+  Operator1<double> op2a(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3.1);
+  Operator1<double> op2b(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3.2);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(!op2a.Equals(&op2b));
@@ -199,7 +211,7 @@
   CHECK(!op2b.Equals(&op1a));
   CHECK(!op2b.Equals(&op1b));
 
-  SimpleOperator op3(25, Operator::kNoProperties, 0, 0, "Weepy");
+  Operator op3(25, NONE, "Weepy", 0, 0, 0, 0, 0, 0);
 
   CHECK(!op1a.Equals(&op3));
   CHECK(!op1b.Equals(&op3));
@@ -211,8 +223,8 @@
   CHECK(!op3.Equals(&op2a));
   CHECK(!op3.Equals(&op2b));
 
-  Operator1<double> op4a(24, Operator::kNoProperties, 0, 0, "Bashful", NaN);
-  Operator1<double> op4b(24, Operator::kNoProperties, 0, 0, "Bashful", NaN);
+  Operator1<double> op4a(24, NONE, "Bashful", 0, 0, 0, 0, 0, 0, 1.0);
+  Operator1<double> op4b(24, NONE, "Bashful", 0, 0, 0, 0, 0, 0, 1.0);
 
   CHECK(op4a.Equals(&op4a));
   CHECK(op4a.Equals(&op4b));
@@ -226,19 +238,46 @@
 }
 
 
-TEST(TestOperator1doublePrint) {
-  Operator1<double> op1(12, Operator::kNoProperties, 0, 1, "Op1Test", 0);
-  CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
+TEST(TestOpParameter_Operator1double) {
+  double values[] = {7777.5, -66, 0, 11, 0.1};
 
-  Operator1<double> op2(12, Operator::kNoProperties, 0, 1, "Op1Test", 7.3);
-  CHECK_EQ("Op1Test[7.3]", OperatorToString(&op2).get());
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<double> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<double>(&op));
+  }
+}
 
-  Operator1<double> op3(12, Operator::kNoProperties, 0, 1, "FooBar", 2e+123);
-  CHECK_EQ("FooBar[2e+123]", OperatorToString(&op3).get());
 
-  Operator1<double> op4(12, Operator::kNoProperties, 0, 1, "BarFoo", Infinity);
-  CHECK_EQ("BarFoo[inf]", OperatorToString(&op4).get());
+TEST(TestOpParameter_Operator1float) {
+  float values[] = {// thanks C++.
+                    static_cast<float>(7777.5), static_cast<float>(-66),
+                    static_cast<float>(0), static_cast<float>(11),
+                    static_cast<float>(0.1)};
 
-  Operator1<double> op5(12, Operator::kNoProperties, 0, 1, "BarFoo", NaN);
-  CHECK_EQ("BarFoo[nan]", OperatorToString(&op5).get());
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<float> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<float>(&op));
+  }
+}
+
+
+TEST(TestOpParameter_Operator1int) {
+  int values[] = {7777, -66, 0, 11, 1, 0x666aff};
+
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<int> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<int>(&op));
+  }
+}
+
+
+TEST(Operator_CountsOrder) {
+  Operator op(29, NONE, "Flashy", 11, 22, 33, 44, 55, 66);
+  CHECK_EQ(11, op.ValueInputCount());
+  CHECK_EQ(22, op.EffectInputCount());
+  CHECK_EQ(33, op.ControlInputCount());
+
+  CHECK_EQ(44, op.ValueOutputCount());
+  CHECK_EQ(55, op.EffectOutputCount());
+  CHECK_EQ(66, op.ControlOutputCount());
 }
diff --git a/test/cctest/compiler/test-phi-reducer.cc b/test/cctest/compiler/test-phi-reducer.cc
deleted file mode 100644
index 7d2fab6..0000000
--- a/test/cctest/compiler/test-phi-reducer.cc
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/v8.h"
-#include "test/cctest/cctest.h"
-
-#include "src/compiler/common-operator.h"
-#include "src/compiler/graph-inl.h"
-#include "src/compiler/phi-reducer.h"
-
-using namespace v8::internal;
-using namespace v8::internal::compiler;
-
-class PhiReducerTester : HandleAndZoneScope {
- public:
-  explicit PhiReducerTester(int num_parameters = 0)
-      : isolate(main_isolate()),
-        common(main_zone()),
-        graph(main_zone()),
-        self(graph.NewNode(common.Start(num_parameters))),
-        dead(graph.NewNode(common.Dead())) {
-    graph.SetStart(self);
-  }
-
-  Isolate* isolate;
-  CommonOperatorBuilder common;
-  Graph graph;
-  Node* self;
-  Node* dead;
-
-  void CheckReduce(Node* expect, Node* phi) {
-    PhiReducer reducer;
-    Reduction reduction = reducer.Reduce(phi);
-    if (expect == phi) {
-      CHECK(!reduction.Changed());
-    } else {
-      CHECK(reduction.Changed());
-      CHECK_EQ(expect, reduction.replacement());
-    }
-  }
-
-  Node* Int32Constant(int32_t val) {
-    return graph.NewNode(common.Int32Constant(val));
-  }
-
-  Node* Float64Constant(double val) {
-    return graph.NewNode(common.Float64Constant(val));
-  }
-
-  Node* Parameter(int32_t index = 0) {
-    return graph.NewNode(common.Parameter(index), graph.start());
-  }
-
-  Node* Phi(Node* a) {
-    return SetSelfReferences(graph.NewNode(common.Phi(kMachAnyTagged, 1), a));
-  }
-
-  Node* Phi(Node* a, Node* b) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 2), a, b));
-  }
-
-  Node* Phi(Node* a, Node* b, Node* c) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 3), a, b, c));
-  }
-
-  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 4), a, b, c, d));
-  }
-
-  Node* PhiWithControl(Node* a, Node* control) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 1), a, control));
-  }
-
-  Node* PhiWithControl(Node* a, Node* b, Node* control) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 2), a, b, control));
-  }
-
-  Node* SetSelfReferences(Node* node) {
-    Node::Inputs inputs = node->inputs();
-    for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
-         ++iter) {
-      Node* input = *iter;
-      if (input == self) node->ReplaceInput(iter.index(), node);
-    }
-    return node;
-  }
-};
-
-
-TEST(PhiReduce1) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    R.CheckReduce(singles[i], R.Phi(singles[i]));
-  }
-}
-
-
-TEST(PhiReduce2) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a));
-    R.CheckReduce(a, R.Phi(a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b);
-    R.CheckReduce(phi2, phi2);
-  }
-}
-
-
-TEST(PhiReduce3) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b, a);
-    R.CheckReduce(phi2, phi2);
-
-    Node* phi3 = R.Phi(a, a, b);
-    R.CheckReduce(phi3, phi3);
-  }
-}
-
-
-TEST(PhiReduce4) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a, a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, a, R.self));
-
-    R.CheckReduce(a, R.Phi(R.self, R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self, R.self));
-    R.CheckReduce(a, R.Phi(R.self, a, a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a, a, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b, a, a);
-    R.CheckReduce(phi2, phi2);
-
-    Node* phi3 = R.Phi(a, a, b, a);
-    R.CheckReduce(phi3, phi3);
-
-    Node* phi4 = R.Phi(a, a, a, b);
-    R.CheckReduce(phi4, phi4);
-  }
-}
-
-
-TEST(PhiReduceShouldIgnoreControlNodes) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); ++i) {
-    R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.dead));
-    R.CheckReduce(singles[i], R.PhiWithControl(R.self, singles[i], R.dead));
-    R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.self, R.dead));
-  }
-}
diff --git a/test/cctest/compiler/test-pipeline.cc b/test/cctest/compiler/test-pipeline.cc
index f0b750a..98b0bae 100644
--- a/test/cctest/compiler/test-pipeline.cc
+++ b/test/cctest/compiler/test-pipeline.cc
@@ -5,6 +5,7 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
+#include "src/ast-numbering.h"
 #include "src/compiler.h"
 #include "src/compiler/pipeline.h"
 #include "src/handles.h"
@@ -22,10 +23,7 @@
       *v8::Handle<v8::Function>::Cast(CompileRun(source)));
   CompilationInfoWithZone info(function);
 
-  CHECK(Parser::Parse(&info));
-  CHECK(Rewriter::Rewrite(&info));
-  CHECK(Scope::Analyze(&info));
-  CHECK_NE(NULL, info.scope());
+  CHECK(Compiler::ParseAndAnalyze(&info));
 
   Pipeline pipeline(&info);
 #if V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-representation-change.cc b/test/cctest/compiler/test-representation-change.cc
index 6c9026b..2dc3029 100644
--- a/test/cctest/compiler/test-representation-change.cc
+++ b/test/cctest/compiler/test-representation-change.cc
@@ -7,10 +7,10 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
+#include "test/cctest/compiler/value-helper.h"
 
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/representation-change.h"
-#include "src/compiler/typer.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
@@ -24,16 +24,13 @@
  public:
   explicit RepresentationChangerTester(int num_parameters = 0)
       : GraphAndBuilders(main_zone()),
-        typer_(main_zone()),
         javascript_(main_zone()),
-        jsgraph_(main_graph_, &main_common_, &javascript_, &typer_,
-                 &main_machine_),
+        jsgraph_(main_graph_, &main_common_, &javascript_, &main_machine_),
         changer_(&jsgraph_, &main_simplified_, main_isolate()) {
     Node* s = graph()->NewNode(common()->Start(num_parameters));
     graph()->SetStart(s);
   }
 
-  Typer typer_;
   JSOperatorBuilder javascript_;
   JSGraph jsgraph_;
   RepresentationChanger changer_;
@@ -51,6 +48,24 @@
     CHECK_EQ(expected, m.Value());
   }
 
+  void CheckUint32Constant(Node* n, uint32_t expected) {
+    Uint32Matcher m(n);
+    CHECK(m.HasValue());
+    CHECK_EQ(static_cast<int>(expected), static_cast<int>(m.Value()));
+  }
+
+  void CheckFloat64Constant(Node* n, double expected) {
+    Float64Matcher m(n);
+    CHECK(m.HasValue());
+    CHECK_EQ(expected, m.Value());
+  }
+
+  void CheckFloat32Constant(Node* n, float expected) {
+    CHECK_EQ(IrOpcode::kFloat32Constant, n->opcode());
+    float fval = OpParameter<float>(n->op());
+    CHECK_EQ(expected, fval);
+  }
+
   void CheckHeapConstant(Node* n, HeapObject* expected) {
     HeapObjectMatcher<HeapObject> m(n);
     CHECK(m.HasValue());
@@ -88,28 +103,8 @@
 }  // namespace v8::internal::compiler
 
 
-// TODO(titzer): add kRepFloat32 when fully supported.
-static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64,
-                                       kRepFloat64, kRepTagged};
-
-
-// TODO(titzer): lift this to ValueHelper
-static const double double_inputs[] = {
-    0.0,   -0.0,    1.0,    -1.0,        0.1,         1.4,    -1.7,
-    2,     5,       6,      982983,      888,         -999.8, 3.1e7,
-    -2e66, 2.3e124, -12e73, V8_INFINITY, -V8_INFINITY};
-
-
-static const int32_t int32_inputs[] = {
-    0,      1,                                -1,
-    2,      5,                                6,
-    982983, 888,                              -999,
-    65535,  static_cast<int32_t>(0xFFFFFFFF), static_cast<int32_t>(0x80000000)};
-
-
-static const uint32_t uint32_inputs[] = {
-    0,      1,   static_cast<uint32_t>(-1),   2,     5,          6,
-    982983, 888, static_cast<uint32_t>(-999), 65535, 0xFFFFFFFF, 0x80000000};
+static const MachineType all_reps[] = {kRepBit,     kRepWord32,  kRepWord64,
+                                       kRepFloat32, kRepFloat64, kRepTagged};
 
 
 TEST(BoolToBit_constant) {
@@ -142,24 +137,234 @@
 TEST(ToTagged_constant) {
   RepresentationChangerTester r;
 
-  for (size_t i = 0; i < arraysize(double_inputs); i++) {
-    Node* n = r.jsgraph()->Float64Constant(double_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
-    r.CheckNumberConstant(c, double_inputs[i]);
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
   }
 
-  for (size_t i = 0; i < arraysize(int32_inputs); i++) {
-    Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
-                                                kRepTagged);
-    r.CheckNumberConstant(c, static_cast<double>(int32_inputs[i]));
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
   }
 
-  for (size_t i = 0; i < arraysize(uint32_inputs); i++) {
-    Node* n = r.jsgraph()->Int32Constant(uint32_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
-                                                kRepTagged);
-    r.CheckNumberConstant(c, static_cast<double>(uint32_inputs[i]));
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+}
+
+
+TEST(ToFloat64_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat64);
+      CHECK_EQ(n, c);
+    }
+  }
+
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+}
+
+
+static bool IsFloat32Int32(int32_t val) {
+  return val >= -(1 << 23) && val <= (1 << 23);
+}
+
+
+static bool IsFloat32Uint32(uint32_t val) { return val <= (1 << 23); }
+
+
+TEST(ToFloat32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat32);
+      CHECK_EQ(n, c);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat32);
+      r.CheckFloat32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat32);
+      r.CheckFloat32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      if (!IsFloat32Int32(*i)) continue;
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepFloat32);
+      r.CheckFloat32Constant(c, static_cast<float>(*i));
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      if (!IsFloat32Uint32(*i)) continue;
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepFloat32);
+      r.CheckFloat32Constant(c, static_cast<float>(*i));
+    }
+  }
+}
+
+
+TEST(ToInt32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      if (!IsFloat32Int32(*i)) continue;
+      Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+}
+
+
+TEST(ToUint32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      if (!IsFloat32Uint32(*i)) continue;
+      Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(static_cast<double>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
   }
 }
 
@@ -177,6 +382,23 @@
 }
 
 
+static void CheckTwoChanges(IrOpcode::Value expected2,
+                            IrOpcode::Value expected1, MachineTypeUnion from,
+                            MachineTypeUnion to) {
+  RepresentationChangerTester r;
+
+  Node* n = r.Parameter();
+  Node* c1 = r.changer()->GetRepresentationFor(n, from, to);
+
+  CHECK_NE(c1, n);
+  CHECK_EQ(expected1, c1->opcode());
+  Node* c2 = c1->InputAt(0);
+  CHECK_NE(c2, n);
+  CHECK_EQ(expected2, c2->opcode());
+  CHECK_EQ(n, c2->InputAt(0));
+}
+
+
 TEST(SingleChanges) {
   CheckChange(IrOpcode::kChangeBoolToBit, kRepTagged, kRepBit);
   CheckChange(IrOpcode::kChangeBitToBool, kRepBit, kRepTagged);
@@ -202,6 +424,28 @@
               kRepWord32);
   CheckChange(IrOpcode::kChangeFloat64ToUint32, kRepFloat64 | kTypeUint32,
               kRepWord32);
+
+  CheckChange(IrOpcode::kTruncateFloat64ToFloat32, kRepFloat64, kRepFloat32);
+
+  // Int32,Uint32 <-> Float32 require two changes.
+  CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeInt32,
+                  kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeUint32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeUint32,
+                  kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToInt32, kRepFloat32 | kTypeInt32,
+                  kRepWord32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToUint32, kRepFloat32 | kTypeUint32,
+                  kRepWord32);
+
+  // Float32 <-> Tagged require two changes.
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToTagged, kRepFloat32, kRepTagged);
+  CheckTwoChanges(IrOpcode::kChangeTaggedToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepTagged, kRepFloat32);
 }
 
 
@@ -215,6 +459,11 @@
               kRepWord32 | kTypeUint32);
   CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64);
   CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32);
+
+  CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32, kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToInt32, kRepFloat32, kRepWord32);
 }
 
 
@@ -295,11 +544,4 @@
       r.CheckTypeError(all_reps[i] | all_reps[j], kRepTagged);
     }
   }
-
-  // TODO(titzer): Float32 representation changes trigger type errors now.
-  // Enforce current behavior to test all paths through representation changer.
-  for (size_t i = 0; i < arraysize(all_reps); i++) {
-    r.CheckTypeError(all_reps[i], kRepFloat32);
-    r.CheckTypeError(kRepFloat32, all_reps[i]);
-  }
 }
diff --git a/test/cctest/compiler/test-run-inlining.cc b/test/cctest/compiler/test-run-inlining.cc
index ad82fec..19b96ba 100644
--- a/test/cctest/compiler/test-run-inlining.cc
+++ b/test/cctest/compiler/test-run-inlining.cc
@@ -25,7 +25,8 @@
     frames_seen++;
     it.Advance();
   }
-  CHECK_EQ(args[0]->ToInt32()->Value(), topmost->GetInlineCount());
+  CHECK_EQ(args[0]->ToInt32(args.GetIsolate())->Value(),
+           topmost->GetInlineCount());
 }
 
 
@@ -37,16 +38,20 @@
 }
 
 
+static uint32_t kInlineFlags = CompilationInfo::kInliningEnabled |
+                               CompilationInfo::kContextSpecializing |
+                               CompilationInfo::kTypingEnabled;
+
+
 TEST(SimpleInlining) {
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function(){"
-      "function foo(s) { AssertInlineCount(2); return s; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "  function foo(s) { AssertInlineCount(2); return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
@@ -57,13 +62,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function(){"
-      "function foo(s) { %DeoptimizeFunction(bar); return "
-      "s; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "  function foo(s) { %DeoptimizeFunction(bar); return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
@@ -74,13 +77,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
@@ -91,16 +92,14 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { "
-      "  AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;"
-      "  return s + x;"
-      "};"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;"
+      "  function foo(s) {"
+      "    AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;"
+      "    return s + x;"
+      "  };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
@@ -111,14 +110,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "var f = (function () {"
-      "var x = 42;"
-      "function bar(s) { return x + s; };"
-      "return (function (s) { return bar(s); });"
+      "  var x = 42;"
+      "  function bar(s) { return x + s; };"
+      "  return (function (s) { return bar(s); });"
       "})();"
-      "(function (s) { return f(s)})",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "(function (s) { return f(s) })",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -132,12 +129,10 @@
   FunctionTester T(
       "var x = 42;"
       "(function () {"
-      "function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };"
-      "return bar;"
+      "  function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
@@ -148,13 +143,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
-      "return (function (s,t) { return bar(s); });"
+      "  var x = 42;"
+      "  function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
+      "  return (function (s,t) { return bar(s); });"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -165,16 +158,14 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s,t,u,v) { AssertInlineCount(2); %DeoptimizeFunction(bar); "
-      "return baz(); };"
-      "function bar() { return foo(11); };"
-      "function baz() { return foo.arguments.length == 1 && "
-      "                        foo.arguments[0] == 11 ; }"
-      "return bar;"
+      "  function foo(s,t,u,v) { AssertInlineCount(2);"
+      "                          %DeoptimizeFunction(bar); return baz(); };"
+      "  function bar() { return foo(11); };"
+      "  function baz() { return foo.arguments.length == 1 &&"
+      "                          foo.arguments[0] == 11; }"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
@@ -185,14 +176,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function foo(s) { AssertInlineCount(2); return x + s; };"
-      "function bar(s,t) { return foo(s,t,13); };"
-      "return bar;"
+      "  var x = 42;"
+      "  function foo(s) { AssertInlineCount(2); return x + s; };"
+      "  function bar(s,t) { return foo(s,t,13); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -203,18 +192,16 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar); "
-      "return baz(); };"
-      "function bar() { return foo(13, 14, 15); };"
-      "function baz() { return foo.arguments.length == 3 && "
-      "                        foo.arguments[0] == 13 && "
-      "                        foo.arguments[1] == 14 && "
-      "                        foo.arguments[2] == 15; }"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar);"
+      "                    return baz(); };"
+      "  function bar() { return foo(13, 14, 15); };"
+      "  function baz() { return foo.arguments.length == 3 &&"
+      "                          foo.arguments[0] == 13 &&"
+      "                          foo.arguments[1] == 14 &&"
+      "                          foo.arguments[2] == 15; }"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
@@ -225,13 +212,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function bar(s) { AssertInlineCount(2); return x + s; };"
-      "return (function (s,t) { return bar(s) + bar(t); });"
+      "  var x = 42;"
+      "  function bar(s) { AssertInlineCount(2); return x + s; };"
+      "  return (function (s,t) { return bar(s) + bar(t); });"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4));
@@ -242,14 +227,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function foo(s) { AssertInlineCount(2); return x + s; };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  var x = 42;"
+      "  function foo(s) { AssertInlineCount(2); return x + s; };"
+      "  function bar(s,t) { return foo(foo(s)); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4));
@@ -260,15 +243,13 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {"
-      "                  return x - s } else { return x + s; } };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  var x = 41;"
+      "  function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {"
+      "                    return x - s } else { return x + s; } };"
+      "  function bar(s,t) { return foo(foo(s)); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(-11), T.Val(11), T.Val(4));
@@ -279,34 +260,60 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {"
-      "                    return x - s * t } else { return x + s * t; } };"
-      "function bar(s,t) { return foo(foo(s, 3), 5); };"
-      "return bar;"
+      "  var x = 41;"
+      "  function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {"
+      "                      return x - s * t } else { return x + s * t; } };"
+      "  function bar(s,t) { return foo(foo(s, 3), 5); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(-329), T.Val(11), T.Val(4));
 }
 
 
-TEST(InlineLoop) {
+TEST(InlineLoopGuardedEmpty) {
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s) { AssertInlineCount(2); while (s > 0) {"
-      "                  s = s - 1; }; return s; };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); if (s) while (s); return s; };"
+      "  function bar(s,t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
+}
+
+
+TEST(InlineLoopGuardedOnce) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {"
+      "                      s = s - 1; }; return s; };"
+      "  function bar(s,t) { return foo(s,t); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
+}
+
+
+TEST(InlineLoopGuardedTwice) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {"
+      "                      s = s - 1; }; return s; };"
+      "  function bar(s,t) { return foo(foo(s,t),t); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
@@ -317,15 +324,13 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = Object.create({}, { y: { value:42, writable:false } });"
-      "function foo(s) { 'use strict';"
-      "                   x.y = 9; };"
-      "function bar(s,t) { return foo(s); };"
-      "return bar;"
+      "  var x = Object.create({}, { y: { value:42, writable:false } });"
+      "  function foo(s) { 'use strict';"
+      "                     x.y = 9; };"
+      "  function bar(s,t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckThrows(T.undefined(), T.undefined());
@@ -336,18 +341,100 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = Object.create({}, { y: { value:42, writable:false } });"
-      "function foo(s) { x.y = 9; return x.y; };"
-      "function bar(s,t) { \'use strict\'; return foo(s); };"
-      "return bar;"
+      "  var x = Object.create({}, { y: { value:42, writable:false } });"
+      "  function foo(s) { x.y = 9; return x.y; };"
+      "  function bar(s,t) { \'use strict\'; return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42), T.undefined(), T.undefined());
 }
 
 
+TEST(InlineIntrinsicIsSmi) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = 42;"
+      "  function bar(s,t) { return %_IsSmi(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineIntrinsicIsNonNegativeSmi) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = 42;"
+      "  function bar(s,t) { return %_IsNonNegativeSmi(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineIntrinsicIsArray) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = [1,2,3];"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+
+  FunctionTester T2(
+      "(function () {"
+      "  var x = 32;"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  T2.CheckCall(T.false_value(), T.Val(12), T.Val(4));
+
+  FunctionTester T3(
+      "(function () {"
+      "  var x = bar;"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  T3.CheckCall(T.false_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineWithArguments) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t,u) { AssertInlineCount(2);"
+      "    return foo.arguments.length == 3 &&"
+      "           foo.arguments[0] == 13 &&"
+      "           foo.arguments[1] == 14 &&"
+      "           foo.arguments[2] == 15;"
+      "  }"
+      "  function bar() { return foo(13, 14, 15); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
+}
+
 #endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-run-intrinsics.cc b/test/cctest/compiler/test-run-intrinsics.cc
index a1b5676..76cbb8f 100644
--- a/test/cctest/compiler/test-run-intrinsics.cc
+++ b/test/cctest/compiler/test-run-intrinsics.cc
@@ -8,10 +8,12 @@
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
-
+uint32_t flags = CompilationInfo::kInliningEnabled;
 
 TEST(IsSmi) {
-  FunctionTester T("(function(a) { return %_IsSmi(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
 
   T.CheckTrue(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -23,7 +25,9 @@
 
 
 TEST(IsNonNegativeSmi) {
-  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
 
   T.CheckTrue(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -35,7 +39,9 @@
 
 
 TEST(IsMinusZero) {
-  FunctionTester T("(function(a) { return %_IsMinusZero(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags);
 
   T.CheckFalse(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -47,7 +53,9 @@
 
 
 TEST(IsArray) {
-  FunctionTester T("(function(a) { return %_IsArray(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckTrue(T.NewObject("([1])"));
@@ -61,7 +69,9 @@
 
 
 TEST(IsObject) {
-  FunctionTester T("(function(a) { return %_IsObject(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckTrue(T.NewObject("([1])"));
@@ -75,7 +85,9 @@
 
 
 TEST(IsFunction) {
-  FunctionTester T("(function(a) { return %_IsFunction(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
 
   T.CheckTrue(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
@@ -89,7 +101,9 @@
 
 
 TEST(IsRegExp) {
-  FunctionTester T("(function(a) { return %_IsRegExp(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
@@ -103,7 +117,9 @@
 
 
 TEST(ClassOf) {
-  FunctionTester T("(function(a) { return %_ClassOf(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
 
   T.CheckCall(T.Val("Function"), T.NewObject("(function() {})"));
   T.CheckCall(T.Val("Array"), T.NewObject("([1])"));
@@ -117,7 +133,9 @@
 
 
 TEST(ObjectEquals) {
-  FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })", flags);
   CompileRun("var o = {}");
 
   T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)"));
@@ -130,7 +148,9 @@
 
 
 TEST(ValueOf) {
-  FunctionTester T("(function(a) { return %_ValueOf(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_ValueOf(a); })", flags);
 
   T.CheckCall(T.Val("a"), T.Val("a"));
   T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))"));
@@ -140,7 +160,9 @@
 
 
 TEST(SetValueOf) {
-  FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags);
 
   T.CheckCall(T.Val("a"), T.NewObject("(new String)"), T.Val("a"));
   T.CheckCall(T.Val(123), T.NewObject("(new Number)"), T.Val(123));
@@ -149,7 +171,9 @@
 
 
 TEST(StringCharFromCode) {
-  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
 
   T.CheckCall(T.Val("a"), T.Val(97));
   T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
@@ -158,7 +182,9 @@
 
 
 TEST(StringCharAt) {
-  FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })", flags);
 
   T.CheckCall(T.Val("e"), T.Val("huge fan!"), T.Val(3));
   T.CheckCall(T.Val("f"), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
@@ -167,7 +193,10 @@
 
 
 TEST(StringCharCodeAt) {
-  FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })",
+                   flags);
 
   T.CheckCall(T.Val('e'), T.Val("huge fan!"), T.Val(3));
   T.CheckCall(T.Val('f'), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
@@ -176,7 +205,9 @@
 
 
 TEST(StringAdd) {
-  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
 
   T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
   T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
@@ -185,7 +216,9 @@
 
 
 TEST(StringSubString) {
-  FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags);
 
   T.CheckCall(T.Val("aaa"), T.Val("aaabbb"), T.Val(0.0));
   T.CheckCall(T.Val("abb"), T.Val("aaabbb"), T.Val(2));
@@ -194,7 +227,9 @@
 
 
 TEST(StringCompare) {
-  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags);
 
   T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb"));
   T.CheckCall(T.Val(0.0), T.Val("bbb"), T.Val("bbb"));
@@ -203,7 +238,10 @@
 
 
 TEST(CallFunction) {
-  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })",
+                   flags);
   CompileRun("function f(a,b,c) { return a + b + c + this.d; }");
 
   T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f"));
diff --git a/test/cctest/compiler/test-run-jsbranches.cc b/test/cctest/compiler/test-run-jsbranches.cc
index df2fcdc..7a4a0b3 100644
--- a/test/cctest/compiler/test-run-jsbranches.cc
+++ b/test/cctest/compiler/test-run-jsbranches.cc
@@ -280,3 +280,78 @@
   T.CheckCall(T.Val(2), T.Val(2), T.false_value());
   T.CheckCall(T.undefined(), T.Val(1), T.null());
 }
+
+
+TEST(IfTrue) {
+  FunctionTester T("(function(a,b) { if (true) return a; return b; })");
+
+  T.CheckCall(T.Val(55), T.Val(55), T.Val(11));
+  T.CheckCall(T.Val(666), T.Val(666), T.Val(-444));
+}
+
+
+TEST(TernaryTrue) {
+  FunctionTester T("(function(a,b) { return true ? a : b; })");
+
+  T.CheckCall(T.Val(77), T.Val(77), T.Val(11));
+  T.CheckCall(T.Val(111), T.Val(111), T.Val(-444));
+}
+
+
+TEST(IfFalse) {
+  FunctionTester T("(function(a,b) { if (false) return a; return b; })");
+
+  T.CheckCall(T.Val(11), T.Val(22), T.Val(11));
+  T.CheckCall(T.Val(-555), T.Val(333), T.Val(-555));
+}
+
+
+TEST(TernaryFalse) {
+  FunctionTester T("(function(a,b) { return false ? a : b; })");
+
+  T.CheckCall(T.Val(99), T.Val(33), T.Val(99));
+  T.CheckCall(T.Val(-99), T.Val(-33), T.Val(-99));
+}
+
+
+TEST(WhileTrue) {
+  FunctionTester T("(function(a,b) { while (true) return a; return b; })");
+
+  T.CheckCall(T.Val(551), T.Val(551), T.Val(111));
+  T.CheckCall(T.Val(661), T.Val(661), T.Val(-444));
+}
+
+
+TEST(WhileFalse) {
+  FunctionTester T("(function(a,b) { while (false) return a; return b; })");
+
+  T.CheckCall(T.Val(115), T.Val(551), T.Val(115));
+  T.CheckCall(T.Val(-445), T.Val(661), T.Val(-445));
+}
+
+
+TEST(DoWhileTrue) {
+  FunctionTester T(
+      "(function(a,b) { do { return a; } while (true); return b; })");
+
+  T.CheckCall(T.Val(7551), T.Val(7551), T.Val(7111));
+  T.CheckCall(T.Val(7661), T.Val(7661), T.Val(-7444));
+}
+
+
+TEST(DoWhileFalse) {
+  FunctionTester T(
+      "(function(a,b) { do { "
+      "; } while (false); return b; })");
+
+  T.CheckCall(T.Val(8115), T.Val(8551), T.Val(8115));
+  T.CheckCall(T.Val(-8445), T.Val(8661), T.Val(-8445));
+}
+
+
+TEST(EmptyFor) {
+  FunctionTester T("(function(a,b) { if (a) for(;;) ; return b; })");
+
+  T.CheckCall(T.Val(8126.1), T.Val(0.0), T.Val(8126.1));
+  T.CheckCall(T.Val(1123.1), T.Val(0.0), T.Val(1123.1));
+}
diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc
index 985e0f8..974d4ce 100644
--- a/test/cctest/compiler/test-run-machops.cc
+++ b/test/cctest/compiler/test-run-machops.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <cmath>
 #include <functional>
 #include <limits>
 
 #include "src/base/bits.h"
-#include "src/compiler/generic-node-inl.h"
+#include "src/codegen.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/codegen-tester.h"
 #include "test/cctest/compiler/value-helper.h"
@@ -58,25 +59,25 @@
 TEST(CodeGenInt32Binop) {
   RawMachineAssemblerTester<void> m;
 
-  const Operator* ops[] = {
+  const Operator* kOps[] = {
       m.machine()->Word32And(),      m.machine()->Word32Or(),
       m.machine()->Word32Xor(),      m.machine()->Word32Shl(),
       m.machine()->Word32Shr(),      m.machine()->Word32Sar(),
       m.machine()->Word32Equal(),    m.machine()->Int32Add(),
       m.machine()->Int32Sub(),       m.machine()->Int32Mul(),
-      m.machine()->Int32Div(),       m.machine()->Int32UDiv(),
-      m.machine()->Int32Mod(),       m.machine()->Int32UMod(),
+      m.machine()->Int32MulHigh(),   m.machine()->Int32Div(),
+      m.machine()->Uint32Div(),      m.machine()->Int32Mod(),
+      m.machine()->Uint32Mod(),      m.machine()->Uint32MulHigh(),
       m.machine()->Int32LessThan(),  m.machine()->Int32LessThanOrEqual(),
-      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual(),
-      NULL};
+      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual()};
 
-  for (int i = 0; ops[i] != NULL; i++) {
+  for (size_t i = 0; i < arraysize(kOps); ++i) {
     for (int j = 0; j < 8; j++) {
       for (int k = 0; k < 8; k++) {
         RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
         Node* a = Int32Input(&m, j);
         Node* b = Int32Input(&m, k);
-        m.Return(m.NewNode(ops[i], a, b));
+        m.Return(m.NewNode(kOps[i], a, b));
         m.GenerateCode();
       }
     }
@@ -127,51 +128,6 @@
 }
 
 
-TEST(RunRedundantBranch1) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 944777;
-
-  MLabel blocka;
-  m.Branch(m.Int32Constant(0), &blocka, &blocka);
-  m.Bind(&blocka);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunRedundantBranch2) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 955777;
-
-  MLabel blocka, blockb;
-  m.Branch(m.Int32Constant(0), &blocka, &blocka);
-  m.Bind(&blockb);
-  m.Goto(&blocka);
-  m.Bind(&blocka);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunRedundantBranch3) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 966777;
-
-  MLabel blocka, blockb, blockc;
-  m.Branch(m.Int32Constant(0), &blocka, &blockc);
-  m.Bind(&blocka);
-  m.Branch(m.Int32Constant(0), &blockb, &blockb);
-  m.Bind(&blockc);
-  m.Goto(&blockb);
-  m.Bind(&blockb);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
 TEST(RunDiamond2) {
   RawMachineAssemblerTester<int32_t> m;
 
@@ -571,6 +527,142 @@
 }
 
 
+TEST(RunInt32AddAndWord32EqualP) {
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Parameter(0),
+                        m.Word32Equal(m.Parameter(1), m.Parameter(2))));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j == *k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32Equal(m.Parameter(0), m.Parameter(1)),
+                        m.Parameter(2)));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i == *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32EqualImm) {
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(*i),
+                          m.Word32Equal(m.Parameter(0), m.Parameter(1))));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j == *k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Word32Equal(m.Int32Constant(*i), m.Parameter(0)),
+                          m.Parameter(1)));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i == *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32NotEqualP) {
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Parameter(0),
+                        m.Word32NotEqual(m.Parameter(1), m.Parameter(2))));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j != *k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32NotEqual(m.Parameter(0), m.Parameter(1)),
+                        m.Parameter(2)));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i != *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32NotEqualImm) {
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(*i),
+                          m.Word32NotEqual(m.Parameter(0), m.Parameter(1))));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j != *k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Word32NotEqual(m.Int32Constant(*i), m.Parameter(0)),
+                          m.Parameter(1)));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i != *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+}
+
+
 TEST(RunInt32AddAndWord32SarP) {
   {
     RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32, kMachUint32);
@@ -1233,6 +1325,20 @@
 }
 
 
+TEST(RunInt32MulHighP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  bt.AddReturn(m.Int32MulHigh(bt.param0, bt.param1));
+  FOR_INT32_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      int32_t expected = static_cast<int32_t>(
+          (static_cast<int64_t>(*i) * static_cast<int64_t>(*j)) >> 32);
+      CHECK_EQ(expected, bt.call(*i, *j));
+    }
+  }
+}
+
+
 TEST(RunInt32MulImm) {
   {
     FOR_UINT32_INPUTS(i) {
@@ -1259,6 +1365,22 @@
 
 TEST(RunInt32MulAndInt32AddP) {
   {
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        RawMachineAssemblerTester<int32_t> m(kMachInt32);
+        int32_t p0 = *i;
+        int32_t p1 = *j;
+        m.Return(m.Int32Add(m.Int32Constant(p0),
+                            m.Int32Mul(m.Parameter(0), m.Int32Constant(p1))));
+        FOR_INT32_INPUTS(k) {
+          int32_t p2 = *k;
+          int expected = p0 + static_cast<int32_t>(p1 * p2);
+          CHECK_EQ(expected, m.Call(p2));
+        }
+      }
+    }
+  }
+  {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
     m.Return(
         m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
@@ -1347,6 +1469,20 @@
 }
 
 
+TEST(RunUint32MulHighP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  bt.AddReturn(m.Uint32MulHigh(bt.param0, bt.param1));
+  FOR_UINT32_INPUTS(i) {
+    FOR_UINT32_INPUTS(j) {
+      int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(
+          (static_cast<uint64_t>(*i) * static_cast<uint64_t>(*j)) >> 32));
+      CHECK_EQ(expected, bt.call(bit_cast<int32_t>(*i), bit_cast<int32_t>(*j)));
+    }
+  }
+}
+
+
 TEST(RunInt32DivP) {
   {
     RawMachineAssemblerTester<int32_t> m;
@@ -1381,11 +1517,11 @@
 }
 
 
-TEST(RunInt32UDivP) {
+TEST(RunUint32DivP) {
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32UDiv(bt.param0, bt.param1));
+    bt.AddReturn(m.Uint32Div(bt.param0, bt.param1));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1400,7 +1536,7 @@
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32Add(bt.param0, m.Int32UDiv(bt.param0, bt.param1)));
+    bt.AddReturn(m.Int32Add(bt.param0, m.Uint32Div(bt.param0, bt.param1)));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1449,11 +1585,11 @@
 }
 
 
-TEST(RunInt32UModP) {
+TEST(RunUint32ModP) {
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32UMod(bt.param0, bt.param1));
+    bt.AddReturn(m.Uint32Mod(bt.param0, bt.param1));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1468,7 +1604,7 @@
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32Add(bt.param0, m.Int32UMod(bt.param0, bt.param1)));
+    bt.AddReturn(m.Int32Add(bt.param0, m.Uint32Mod(bt.param0, bt.param1)));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -2658,22 +2794,23 @@
 TEST(RunDeadInt32Binops) {
   RawMachineAssemblerTester<int32_t> m;
 
-  const Operator* ops[] = {
-      m.machine()->Word32And(),             m.machine()->Word32Or(),
-      m.machine()->Word32Xor(),             m.machine()->Word32Shl(),
-      m.machine()->Word32Shr(),             m.machine()->Word32Sar(),
-      m.machine()->Word32Ror(),             m.machine()->Word32Equal(),
-      m.machine()->Int32Add(),              m.machine()->Int32Sub(),
-      m.machine()->Int32Mul(),              m.machine()->Int32Div(),
-      m.machine()->Int32UDiv(),             m.machine()->Int32Mod(),
-      m.machine()->Int32UMod(),             m.machine()->Int32LessThan(),
-      m.machine()->Int32LessThanOrEqual(),  m.machine()->Uint32LessThan(),
-      m.machine()->Uint32LessThanOrEqual(), NULL};
+  const Operator* kOps[] = {
+      m.machine()->Word32And(),            m.machine()->Word32Or(),
+      m.machine()->Word32Xor(),            m.machine()->Word32Shl(),
+      m.machine()->Word32Shr(),            m.machine()->Word32Sar(),
+      m.machine()->Word32Ror(),            m.machine()->Word32Equal(),
+      m.machine()->Int32Add(),             m.machine()->Int32Sub(),
+      m.machine()->Int32Mul(),             m.machine()->Int32MulHigh(),
+      m.machine()->Int32Div(),             m.machine()->Uint32Div(),
+      m.machine()->Int32Mod(),             m.machine()->Uint32Mod(),
+      m.machine()->Uint32MulHigh(),        m.machine()->Int32LessThan(),
+      m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32LessThan(),
+      m.machine()->Uint32LessThanOrEqual()};
 
-  for (int i = 0; ops[i] != NULL; i++) {
+  for (size_t i = 0; i < arraysize(kOps); ++i) {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
-    int constant = 0x55555 + i;
-    m.NewNode(ops[i], m.Parameter(0), m.Parameter(1));
+    int32_t constant = static_cast<int32_t>(0x55555 + i);
+    m.NewNode(kOps[i], m.Parameter(0), m.Parameter(1));
     m.Return(m.Int32Constant(constant));
 
     CHECK_EQ(constant, m.Call(1, 1));
@@ -3102,6 +3239,38 @@
 }
 
 
+TEST(RunChangeUint32ToFloat64_spilled) {
+  RawMachineAssemblerTester<int32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  uint32_t input[kNumInputs];
+  double result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachUint32, m.PointerConstant(&input), m.Int32Constant(i * 4));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat64, m.PointerConstant(&result), m.Int32Constant(i * 8),
+            m.ChangeUint32ToFloat64(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 100 + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], static_cast<double>(100 + i));
+  }
+}
+
+
 TEST(RunChangeFloat64ToInt32_A) {
   RawMachineAssemblerTester<int32_t> m;
   int32_t magic = 0x786234;
@@ -3272,6 +3441,38 @@
 }
 
 
+TEST(RunTruncateFloat64ToFloat32_spilled) {
+  RawMachineAssemblerTester<uint32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  double input[kNumInputs];
+  float result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachFloat64, m.PointerConstant(&input), m.Int32Constant(i * 8));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat32, m.PointerConstant(&result), m.Int32Constant(i * 4),
+            m.TruncateFloat64ToFloat32(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 0.1 + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], DoubleToFloat32(input[i]));
+  }
+}
+
+
 TEST(RunDeadChangeFloat64ToInt32) {
   RawMachineAssemblerTester<int32_t> m;
   const int magic = 0x88abcda4;
@@ -4242,4 +4443,249 @@
   }
 }
 
+
+TEST(RunChangeFloat32ToFloat64) {
+  double actual = 0.0f;
+  float expected = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.StoreToPointer(
+      &actual, kMachFloat64,
+      m.ChangeFloat32ToFloat64(m.LoadFromPointer(&expected, kMachFloat32)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT32_INPUTS(i) {
+    expected = *i;
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+TEST(RunChangeFloat32ToFloat64_spilled) {
+  RawMachineAssemblerTester<int32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  float input[kNumInputs];
+  double result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachFloat32, m.PointerConstant(&input), m.Int32Constant(i * 4));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat64, m.PointerConstant(&result), m.Int32Constant(i * 8),
+            m.ChangeFloat32ToFloat64(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 100.9f + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], static_cast<double>(input[i]));
+  }
+}
+
+
+TEST(RunTruncateFloat64ToFloat32) {
+  float actual = 0.0f;
+  double input = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.StoreToPointer(
+      &actual, kMachFloat32,
+      m.TruncateFloat64ToFloat32(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT64_INPUTS(i) {
+    input = *i;
+    volatile double expected = DoubleToFloat32(input);
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+TEST(RunFloat32Constant) {
+  FOR_FLOAT32_INPUTS(i) {
+    float expected = *i;
+    float actual = *i;
+    RawMachineAssemblerTester<int32_t> m;
+    m.StoreToPointer(&actual, kMachFloat32, m.Float32Constant(expected));
+    m.Return(m.Int32Constant(0));
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+static double two_30 = 1 << 30;             // 2^30 is a smi boundary.
+static double two_52 = two_30 * (1 << 22);  // 2^52 is a precision boundary.
+static double kValues[] = {0.1,
+                           0.2,
+                           0.49999999999999994,
+                           0.5,
+                           0.7,
+                           1.0 - std::numeric_limits<double>::epsilon(),
+                           -0.1,
+                           -0.49999999999999994,
+                           -0.5,
+                           -0.7,
+                           1.1,
+                           1.0 + std::numeric_limits<double>::epsilon(),
+                           1.5,
+                           1.7,
+                           -1,
+                           -1 + std::numeric_limits<double>::epsilon(),
+                           -1 - std::numeric_limits<double>::epsilon(),
+                           -1.1,
+                           -1.5,
+                           -1.7,
+                           std::numeric_limits<double>::min(),
+                           -std::numeric_limits<double>::min(),
+                           std::numeric_limits<double>::max(),
+                           -std::numeric_limits<double>::max(),
+                           std::numeric_limits<double>::infinity(),
+                           -std::numeric_limits<double>::infinity(),
+                           two_30,
+                           two_30 + 0.1,
+                           two_30 + 0.5,
+                           two_30 + 0.7,
+                           two_30 - 1,
+                           two_30 - 1 + 0.1,
+                           two_30 - 1 + 0.5,
+                           two_30 - 1 + 0.7,
+                           -two_30,
+                           -two_30 + 0.1,
+                           -two_30 + 0.5,
+                           -two_30 + 0.7,
+                           -two_30 + 1,
+                           -two_30 + 1 + 0.1,
+                           -two_30 + 1 + 0.5,
+                           -two_30 + 1 + 0.7,
+                           two_52,
+                           two_52 + 0.1,
+                           two_52 + 0.5,
+                           two_52 + 0.5,
+                           two_52 + 0.7,
+                           two_52 + 0.7,
+                           two_52 - 1,
+                           two_52 - 1 + 0.1,
+                           two_52 - 1 + 0.5,
+                           two_52 - 1 + 0.7,
+                           -two_52,
+                           -two_52 + 0.1,
+                           -two_52 + 0.5,
+                           -two_52 + 0.7,
+                           -two_52 + 1,
+                           -two_52 + 1 + 0.1,
+                           -two_52 + 1 + 0.5,
+                           -two_52 + 1 + 0.7,
+                           two_30,
+                           two_30 - 0.1,
+                           two_30 - 0.5,
+                           two_30 - 0.7,
+                           two_30 - 1,
+                           two_30 - 1 - 0.1,
+                           two_30 - 1 - 0.5,
+                           two_30 - 1 - 0.7,
+                           -two_30,
+                           -two_30 - 0.1,
+                           -two_30 - 0.5,
+                           -two_30 - 0.7,
+                           -two_30 + 1,
+                           -two_30 + 1 - 0.1,
+                           -two_30 + 1 - 0.5,
+                           -two_30 + 1 - 0.7,
+                           two_52,
+                           two_52 - 0.1,
+                           two_52 - 0.5,
+                           two_52 - 0.5,
+                           two_52 - 0.7,
+                           two_52 - 0.7,
+                           two_52 - 1,
+                           two_52 - 1 - 0.1,
+                           two_52 - 1 - 0.5,
+                           two_52 - 1 - 0.7,
+                           -two_52,
+                           -two_52 - 0.1,
+                           -two_52 - 0.5,
+                           -two_52 - 0.7,
+                           -two_52 + 1,
+                           -two_52 + 1 - 0.1,
+                           -two_52 + 1 - 0.5,
+                           -two_52 + 1 - 0.7};
+
+
+TEST(RunFloat64Floor) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Floor()) return;
+  m.StoreToPointer(&result, kMachFloat64,
+                   m.Float64Floor(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = std::floor(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64Ceil) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Ceil()) return;
+  m.StoreToPointer(&result, kMachFloat64,
+                   m.Float64Ceil(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = std::ceil(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64RoundTruncate) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Ceil()) return;
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64RoundTruncate(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = trunc(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64RoundTiesAway) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64RoundTiesAway()) return;
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64RoundTiesAway(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = round(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
 #endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-run-stackcheck.cc b/test/cctest/compiler/test-run-stackcheck.cc
new file mode 100644
index 0000000..8c1664b
--- /dev/null
+++ b/test/cctest/compiler/test-run-stackcheck.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "test/cctest/compiler/function-tester.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+TEST(TerminateAtMethodEntry) {
+  FunctionTester T("(function(a,b) { return 23; })");
+
+  T.CheckCall(T.Val(23));
+  T.isolate->stack_guard()->RequestTerminateExecution();
+  T.CheckThrows(T.undefined(), T.undefined());
+}
diff --git a/test/cctest/compiler/test-schedule.cc b/test/cctest/compiler/test-schedule.cc
index 6c05c05..1eb3547 100644
--- a/test/cctest/compiler/test-schedule.cc
+++ b/test/cctest/compiler/test-schedule.cc
@@ -5,7 +5,6 @@
 #include "src/v8.h"
 
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/machine-operator.h"
 #include "src/compiler/node.h"
@@ -16,26 +15,25 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 0, 0, 0);
 
 TEST(TestScheduleAllocation) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
 
   CHECK_NE(NULL, schedule.start());
-  CHECK_EQ(schedule.start(), *(schedule.all_blocks().begin()));
+  CHECK_EQ(schedule.start(), schedule.GetBlockById(BasicBlock::Id::FromInt(0)));
 }
 
 
 TEST(TestScheduleAddNode) {
   HandleAndZoneScope scope;
+  Schedule schedule(scope.main_zone());
   Graph graph(scope.main_zone());
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* n1 = graph.NewNode(&dummy_operator);
 
-  Schedule schedule(scope.main_zone());
-
   BasicBlock* entry = schedule.start();
   schedule.AddNode(entry, n0);
   schedule.AddNode(entry, n1);
@@ -51,50 +49,49 @@
 
 TEST(TestScheduleAddGoto) {
   HandleAndZoneScope scope;
-
   Schedule schedule(scope.main_zone());
+
   BasicBlock* entry = schedule.start();
   BasicBlock* next = schedule.NewBasicBlock();
 
   schedule.AddGoto(entry, next);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(next, entry->SuccessorAt(0));
 
-  CHECK_EQ(1, next->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(next->PredecessorCount()));
   CHECK_EQ(entry, next->PredecessorAt(0));
-  CHECK_EQ(0, next->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(next->SuccessorCount()));
 }
 
 
 TEST(TestScheduleAddBranch) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-
-  BasicBlock* entry = schedule.start();
-  BasicBlock* tblock = schedule.NewBasicBlock();
-  BasicBlock* fblock = schedule.NewBasicBlock();
-
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* b = graph.NewNode(common.Branch(), n0);
 
+  BasicBlock* entry = schedule.start();
+  BasicBlock* tblock = schedule.NewBasicBlock();
+  BasicBlock* fblock = schedule.NewBasicBlock();
+
   schedule.AddBranch(entry, b, tblock, fblock);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(2, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(2, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(tblock, entry->SuccessorAt(0));
   CHECK_EQ(fblock, entry->SuccessorAt(1));
 
-  CHECK_EQ(1, tblock->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(tblock->PredecessorCount()));
   CHECK_EQ(entry, tblock->PredecessorAt(0));
-  CHECK_EQ(0, tblock->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(tblock->SuccessorCount()));
 
-  CHECK_EQ(1, fblock->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(fblock->PredecessorCount()));
   CHECK_EQ(entry, fblock->PredecessorAt(0));
-  CHECK_EQ(0, fblock->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(fblock->SuccessorCount()));
 }
 
 
@@ -106,8 +103,8 @@
   BasicBlock* entry = schedule.start();
   schedule.AddReturn(entry, n0);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(schedule.end(), entry->SuccessorAt(0));
 }
 
@@ -120,18 +117,53 @@
   BasicBlock* entry = schedule.start();
   schedule.AddThrow(entry, n0);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(schedule.end(), entry->SuccessorAt(0));
 }
 
 
+TEST(TestScheduleInsertBranch) {
+  HandleAndZoneScope scope;
+  Schedule schedule(scope.main_zone());
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+  Node* n0 = graph.NewNode(&dummy_operator);
+  Node* n1 = graph.NewNode(&dummy_operator);
+  Node* b = graph.NewNode(common.Branch(), n1);
+
+  BasicBlock* entry = schedule.start();
+  BasicBlock* tblock = schedule.NewBasicBlock();
+  BasicBlock* fblock = schedule.NewBasicBlock();
+  BasicBlock* merge = schedule.NewBasicBlock();
+  schedule.AddReturn(entry, n0);
+  schedule.AddGoto(tblock, merge);
+  schedule.AddGoto(fblock, merge);
+
+  schedule.InsertBranch(entry, merge, b, tblock, fblock);
+
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(2, static_cast<int>(entry->SuccessorCount()));
+  CHECK_EQ(tblock, entry->SuccessorAt(0));
+  CHECK_EQ(fblock, entry->SuccessorAt(1));
+
+  CHECK_EQ(2, static_cast<int>(merge->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(merge->SuccessorCount()));
+  CHECK_EQ(schedule.end(), merge->SuccessorAt(0));
+
+  CHECK_EQ(1, static_cast<int>(schedule.end()->PredecessorCount()));
+  CHECK_EQ(0, static_cast<int>(schedule.end()->SuccessorCount()));
+  CHECK_EQ(merge, schedule.end()->PredecessorAt(0));
+}
+
+
 TEST(BuildMulNodeGraph) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
+  // TODO(titzer): use test operators.
+  MachineOperatorBuilder machine(scope.main_zone());
 
   Node* start = graph.NewNode(common.Start(0));
   graph.SetStart(start);
diff --git a/test/cctest/compiler/test-scheduler.cc b/test/cctest/compiler/test-scheduler.cc
index cf33123..1b79ed5 100644
--- a/test/cctest/compiler/test-scheduler.cc
+++ b/test/cctest/compiler/test-scheduler.cc
@@ -3,31 +3,71 @@
 // found in the LICENSE file.
 
 #include "src/v8.h"
-#include "test/cctest/cctest.h"
 
+#include "src/compiler/access-builder.h"
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
-#include "src/compiler/generic-node.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/js-operator.h"
-#include "src/compiler/machine-operator.h"
 #include "src/compiler/node.h"
+#include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
 #include "src/compiler/schedule.h"
 #include "src/compiler/scheduler.h"
+#include "src/compiler/simplified-operator.h"
 #include "src/compiler/verifier.h"
+#include "test/cctest/cctest.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
+Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0, 0, 1,
+                 0, 0);
+
 // TODO(titzer): pull RPO tests out to their own file.
+static void CheckRPONumbers(BasicBlockVector* order, size_t expected,
+                            bool loops_allowed) {
+  CHECK(expected == order->size());
+  for (int i = 0; i < static_cast<int>(order->size()); i++) {
+    CHECK(order->at(i)->rpo_number() == i);
+    if (!loops_allowed) {
+      CHECK_EQ(NULL, order->at(i)->loop_end());
+      CHECK_EQ(NULL, order->at(i)->loop_header());
+    }
+  }
+}
+
+
+static void CheckLoop(BasicBlockVector* order, BasicBlock** blocks,
+                      int body_size) {
+  BasicBlock* header = blocks[0];
+  BasicBlock* end = header->loop_end();
+  CHECK_NE(NULL, end);
+  CHECK_GT(end->rpo_number(), 0);
+  CHECK_EQ(body_size, end->rpo_number() - header->rpo_number());
+  for (int i = 0; i < body_size; i++) {
+    CHECK_GE(blocks[i]->rpo_number(), header->rpo_number());
+    CHECK_LT(blocks[i]->rpo_number(), end->rpo_number());
+    CHECK(header->LoopContains(blocks[i]));
+    CHECK(header->IsLoopHeader() || blocks[i]->loop_header() == header);
+  }
+  if (header->rpo_number() > 0) {
+    CHECK_NE(order->at(header->rpo_number() - 1)->loop_header(), header);
+  }
+  if (end->rpo_number() < static_cast<int>(order->size())) {
+    CHECK_NE(order->at(end->rpo_number())->loop_header(), header);
+  }
+}
+
+
 struct TestLoop {
   int count;
   BasicBlock** nodes;
   BasicBlock* header() { return nodes[0]; }
   BasicBlock* last() { return nodes[count - 1]; }
   ~TestLoop() { delete[] nodes; }
+
+  void Check(BasicBlockVector* order) { CheckLoop(order, nodes, count); }
 };
 
 
@@ -37,36 +77,15 @@
   loop->nodes = new BasicBlock* [count];
   for (int i = 0; i < count; i++) {
     loop->nodes[i] = schedule->NewBasicBlock();
-    if (i > 0) schedule->AddSuccessor(loop->nodes[i - 1], loop->nodes[i]);
+    if (i > 0) {
+      schedule->AddSuccessorForTesting(loop->nodes[i - 1], loop->nodes[i]);
+    }
   }
-  schedule->AddSuccessor(loop->nodes[count - 1], loop->nodes[0]);
+  schedule->AddSuccessorForTesting(loop->nodes[count - 1], loop->nodes[0]);
   return loop;
 }
 
 
-static void CheckRPONumbers(BasicBlockVector* order, int expected,
-                            bool loops_allowed) {
-  CHECK_EQ(expected, static_cast<int>(order->size()));
-  for (int i = 0; i < static_cast<int>(order->size()); i++) {
-    CHECK(order->at(i)->rpo_number_ == i);
-    if (!loops_allowed) CHECK_LT(order->at(i)->loop_end_, 0);
-  }
-}
-
-
-static void CheckLoopContains(BasicBlock** blocks, int body_size) {
-  BasicBlock* header = blocks[0];
-  CHECK_GT(header->loop_end_, 0);
-  CHECK_EQ(body_size, (header->loop_end_ - header->rpo_number_));
-  for (int i = 0; i < body_size; i++) {
-    int num = blocks[i]->rpo_number_;
-    CHECK(num >= header->rpo_number_ && num < header->loop_end_);
-    CHECK(header->LoopContains(blocks[i]));
-    CHECK(header->IsLoopHeader() || blocks[i]->loop_header_ == header);
-  }
-}
-
-
 static int GetScheduledNodeCount(Schedule* schedule) {
   int node_count = 0;
   for (BasicBlockVectorIter i = schedule->rpo_order()->begin();
@@ -76,7 +95,7 @@
          ++j) {
       ++node_count;
     }
-    BasicBlock::Control control = block->control_;
+    BasicBlock::Control control = block->control();
     if (control != BasicBlock::kNone) {
       ++node_count;
     }
@@ -91,11 +110,11 @@
     os << AsDOT(*graph);
   }
 
-  Schedule* schedule = Scheduler::ComputeSchedule(graph);
+  Schedule* schedule = Scheduler::ComputeSchedule(graph->zone(), graph);
 
   if (FLAG_trace_turbo_scheduler) {
     OFStream os(stdout);
-    os << *schedule << endl;
+    os << *schedule << std::endl;
   }
   ScheduleVerifier::Run(schedule);
   CHECK_EQ(expected, GetScheduledNodeCount(schedule));
@@ -107,7 +126,8 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 1, false);
   CHECK_EQ(schedule.start(), order->at(0));
 }
@@ -118,7 +138,8 @@
   Schedule schedule(scope.main_zone());
 
   schedule.AddGoto(schedule.start(), schedule.end());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 2, false);
   CHECK_EQ(schedule.start(), order->at(0));
   CHECK_EQ(schedule.end(), order->at(1));
@@ -134,18 +155,18 @@
     BasicBlock* last = schedule.start();
     for (int j = 0; j < i; j++) {
       BasicBlock* block = schedule.NewBasicBlock();
+      block->set_deferred(i & 1);
       schedule.AddGoto(last, block);
       last = block;
     }
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, 1 + i, false);
 
-    Schedule::BasicBlocks blocks(schedule.all_blocks());
-    for (Schedule::BasicBlocks::iterator iter = blocks.begin();
-         iter != blocks.end(); ++iter) {
-      BasicBlock* block = *iter;
-      if (block->rpo_number_ >= 0 && block->SuccessorCount() == 1) {
-        CHECK(block->rpo_number_ + 1 == block->SuccessorAt(0)->rpo_number_);
+    for (size_t i = 0; i < schedule.BasicBlockCount(); i++) {
+      BasicBlock* block = schedule.GetBlockById(BasicBlock::Id::FromSize(i));
+      if (block->rpo_number() >= 0 && block->SuccessorCount() == 1) {
+        CHECK(block->rpo_number() + 1 == block->SuccessorAt(0)->rpo_number());
       }
     }
   }
@@ -155,23 +176,26 @@
 TEST(RPOSelfLoop) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-  schedule.AddSuccessor(schedule.start(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 1, true);
   BasicBlock* loop[] = {schedule.start()};
-  CheckLoopContains(loop, 1);
+  CheckLoop(order, loop, 1);
 }
 
 
 TEST(RPOEntryLoop) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-  schedule.AddSuccessor(schedule.start(), schedule.end());
-  schedule.AddSuccessor(schedule.end(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlock* body = schedule.NewBasicBlock();
+  schedule.AddSuccessorForTesting(schedule.start(), body);
+  schedule.AddSuccessorForTesting(body, schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 2, true);
-  BasicBlock* loop[] = {schedule.start(), schedule.end()};
-  CheckLoopContains(loop, 2);
+  BasicBlock* loop[] = {schedule.start(), body};
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -179,10 +203,11 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
-  schedule.AddSuccessor(schedule.start(), loop1->header());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 3, true);
-  CheckLoopContains(loop1->nodes, loop1->count);
+  loop1->Check(order);
 }
 
 
@@ -190,11 +215,12 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
-  schedule.AddSuccessor(schedule.start(), loop1->header());
-  schedule.AddSuccessor(loop1->last(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
+  schedule.AddSuccessorForTesting(loop1->last(), schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 3, true);
-  CheckLoopContains(loop1->nodes, loop1->count);
+  loop1->Check(order);
 }
 
 
@@ -207,18 +233,19 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(A, C);
-  schedule.AddSuccessor(B, D);
-  schedule.AddSuccessor(C, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(A, C);
+  schedule.AddSuccessorForTesting(B, D);
+  schedule.AddSuccessorForTesting(C, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, false);
 
-  CHECK_EQ(0, A->rpo_number_);
-  CHECK((B->rpo_number_ == 1 && C->rpo_number_ == 2) ||
-        (B->rpo_number_ == 2 && C->rpo_number_ == 1));
-  CHECK_EQ(3, D->rpo_number_);
+  CHECK_EQ(0, A->rpo_number());
+  CHECK((B->rpo_number() == 1 && C->rpo_number() == 2) ||
+        (B->rpo_number() == 2 && C->rpo_number() == 1));
+  CHECK_EQ(3, D->rpo_number());
 }
 
 
@@ -231,15 +258,16 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(C, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(C, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, true);
   BasicBlock* loop[] = {B, C};
-  CheckLoopContains(loop, 2);
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -252,15 +280,16 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(B, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(B, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, true);
   BasicBlock* loop[] = {B, C};
-  CheckLoopContains(loop, 2);
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -277,32 +306,33 @@
     BasicBlock* F = schedule.NewBasicBlock();
     BasicBlock* G = schedule.end();
 
-    schedule.AddSuccessor(A, B);
-    schedule.AddSuccessor(B, C);
-    schedule.AddSuccessor(C, D);
-    schedule.AddSuccessor(D, E);
-    schedule.AddSuccessor(E, F);
-    schedule.AddSuccessor(F, B);
-    schedule.AddSuccessor(B, G);
+    schedule.AddSuccessorForTesting(A, B);
+    schedule.AddSuccessorForTesting(B, C);
+    schedule.AddSuccessorForTesting(C, D);
+    schedule.AddSuccessorForTesting(D, E);
+    schedule.AddSuccessorForTesting(E, F);
+    schedule.AddSuccessorForTesting(F, B);
+    schedule.AddSuccessorForTesting(B, G);
 
     // Throw in extra backedges from time to time.
-    if (i == 1) schedule.AddSuccessor(B, B);
-    if (i == 2) schedule.AddSuccessor(C, B);
-    if (i == 3) schedule.AddSuccessor(D, B);
-    if (i == 4) schedule.AddSuccessor(E, B);
-    if (i == 5) schedule.AddSuccessor(F, B);
+    if (i == 1) schedule.AddSuccessorForTesting(B, B);
+    if (i == 2) schedule.AddSuccessorForTesting(C, B);
+    if (i == 3) schedule.AddSuccessorForTesting(D, B);
+    if (i == 4) schedule.AddSuccessorForTesting(E, B);
+    if (i == 5) schedule.AddSuccessorForTesting(F, B);
 
     // Throw in extra loop exits from time to time.
-    if (i == 6) schedule.AddSuccessor(B, G);
-    if (i == 7) schedule.AddSuccessor(C, G);
-    if (i == 8) schedule.AddSuccessor(D, G);
-    if (i == 9) schedule.AddSuccessor(E, G);
-    if (i == 10) schedule.AddSuccessor(F, G);
+    if (i == 6) schedule.AddSuccessorForTesting(B, G);
+    if (i == 7) schedule.AddSuccessorForTesting(C, G);
+    if (i == 8) schedule.AddSuccessorForTesting(D, G);
+    if (i == 9) schedule.AddSuccessorForTesting(E, G);
+    if (i == 10) schedule.AddSuccessorForTesting(F, G);
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, 7, true);
     BasicBlock* loop[] = {B, C, D, E, F};
-    CheckLoopContains(loop, 5);
+    CheckLoop(order, loop, 5);
   }
 }
 
@@ -318,21 +348,22 @@
   BasicBlock* E = schedule.NewBasicBlock();
   BasicBlock* F = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, D);
-  schedule.AddSuccessor(D, C);
-  schedule.AddSuccessor(D, E);
-  schedule.AddSuccessor(E, B);
-  schedule.AddSuccessor(E, F);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, D);
+  schedule.AddSuccessorForTesting(D, C);
+  schedule.AddSuccessorForTesting(D, E);
+  schedule.AddSuccessorForTesting(E, B);
+  schedule.AddSuccessorForTesting(E, F);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 6, true);
   BasicBlock* loop1[] = {B, C, D, E};
-  CheckLoopContains(loop1, 4);
+  CheckLoop(order, loop1, 4);
 
   BasicBlock* loop2[] = {C, D};
-  CheckLoopContains(loop2, 2);
+  CheckLoop(order, loop2, 2);
 }
 
 
@@ -349,28 +380,29 @@
   BasicBlock* G = schedule.NewBasicBlock();
   BasicBlock* H = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, D);
-  schedule.AddSuccessor(D, E);
-  schedule.AddSuccessor(E, F);
-  schedule.AddSuccessor(F, G);
-  schedule.AddSuccessor(G, H);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, D);
+  schedule.AddSuccessorForTesting(D, E);
+  schedule.AddSuccessorForTesting(E, F);
+  schedule.AddSuccessorForTesting(F, G);
+  schedule.AddSuccessorForTesting(G, H);
 
-  schedule.AddSuccessor(E, D);
-  schedule.AddSuccessor(F, C);
-  schedule.AddSuccessor(G, B);
+  schedule.AddSuccessorForTesting(E, D);
+  schedule.AddSuccessorForTesting(F, C);
+  schedule.AddSuccessorForTesting(G, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 8, true);
   BasicBlock* loop1[] = {B, C, D, E, F, G};
-  CheckLoopContains(loop1, 6);
+  CheckLoop(order, loop1, 6);
 
   BasicBlock* loop2[] = {C, D, E, F};
-  CheckLoopContains(loop2, 4);
+  CheckLoop(order, loop2, 4);
 
   BasicBlock* loop3[] = {D, E};
-  CheckLoopContains(loop3, 2);
+  CheckLoop(order, loop3, 2);
 }
 
 
@@ -384,17 +416,18 @@
   BasicBlock* A = schedule.start();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, loop1->header());
-  schedule.AddSuccessor(loop1->header(), loop2->header());
-  schedule.AddSuccessor(loop2->last(), E);
+  schedule.AddSuccessorForTesting(A, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), E);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
 
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  loop1->Check(order);
+  loop2->Check(order);
 }
 
 
@@ -409,18 +442,18 @@
   BasicBlock* S = schedule.NewBasicBlock();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, loop1->header());
-  schedule.AddSuccessor(loop1->header(), S);
-  schedule.AddSuccessor(S, loop2->header());
-  schedule.AddSuccessor(loop2->last(), E);
+  schedule.AddSuccessorForTesting(A, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), S);
+  schedule.AddSuccessorForTesting(S, loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), E);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
-
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
+  loop1->Check(order);
+  loop2->Check(order);
 }
 
 
@@ -435,15 +468,16 @@
       BasicBlock* A = schedule.start();
       BasicBlock* E = schedule.end();
 
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->nodes[exit], loop2->header());
-      schedule.AddSuccessor(loop2->nodes[exit], E);
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[exit], loop2->header());
+      schedule.AddSuccessorForTesting(loop2->nodes[exit], E);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-      CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-      CheckLoopContains(loop1->nodes, loop1->count);
-      CheckLoopContains(loop2->nodes, loop2->count);
+      CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+               static_cast<int>(order->size()));
+      loop1->Check(order);
+      loop2->Check(order);
     }
   }
 }
@@ -461,23 +495,23 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, loop1->header());
-  schedule.AddSuccessor(loop1->header(), loop2->header());
-  schedule.AddSuccessor(loop2->last(), C);
-  schedule.AddSuccessor(C, E);
-  schedule.AddSuccessor(C, B);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), C);
+  schedule.AddSuccessorForTesting(C, E);
+  schedule.AddSuccessorForTesting(C, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
-
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
+  loop1->Check(order);
+  loop2->Check(order);
 
   BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C};
-  CheckLoopContains(loop3, 4);
+  CheckLoop(order, loop3, 4);
 }
 
 
@@ -492,15 +526,16 @@
       BasicBlock* E = schedule.end();
 
       SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->last(), E);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->last(), E);
 
-      schedule.AddSuccessor(loop1->nodes[i], loop1->header());
-      schedule.AddSuccessor(loop1->nodes[j], E);
+      schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[j], E);
 
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      loop1->Check(order);
     }
   }
 }
@@ -518,16 +553,17 @@
       BasicBlock* E = schedule.end();
 
       SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->last(), E);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->last(), E);
 
-      schedule.AddSuccessor(loop1->nodes[i], loop1->header());
-      schedule.AddSuccessor(loop1->nodes[j], D);
-      schedule.AddSuccessor(D, E);
+      schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[j], D);
+      schedule.AddSuccessorForTesting(D, E);
 
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      loop1->Check(order);
     }
   }
 }
@@ -543,18 +579,19 @@
     BasicBlock* E = schedule.end();
 
     SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-    schedule.AddSuccessor(A, loop1->header());
-    schedule.AddSuccessor(loop1->last(), E);
+    schedule.AddSuccessorForTesting(A, loop1->header());
+    schedule.AddSuccessorForTesting(loop1->last(), E);
 
     for (int j = 0; j < size; j++) {
       BasicBlock* O = schedule.NewBasicBlock();
-      schedule.AddSuccessor(loop1->nodes[j], O);
-      schedule.AddSuccessor(O, E);
+      schedule.AddSuccessorForTesting(loop1->nodes[j], O);
+      schedule.AddSuccessorForTesting(O, E);
     }
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-    CheckLoopContains(loop1->nodes, loop1->count);
+    loop1->Check(order);
   }
 }
 
@@ -568,22 +605,23 @@
     BasicBlock* A = schedule.start();
     BasicBlock* E = schedule.end();
     SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-    schedule.AddSuccessor(A, loop1->header());
-    schedule.AddSuccessor(loop1->last(), E);
+    schedule.AddSuccessorForTesting(A, loop1->header());
+    schedule.AddSuccessorForTesting(loop1->last(), E);
 
     TestLoop** loopN = new TestLoop* [size];
     for (int j = 0; j < size; j++) {
       loopN[j] = CreateLoop(&schedule, 2);
-      schedule.AddSuccessor(loop1->nodes[j], loopN[j]->header());
-      schedule.AddSuccessor(loopN[j]->last(), E);
+      schedule.AddSuccessorForTesting(loop1->nodes[j], loopN[j]->header());
+      schedule.AddSuccessorForTesting(loopN[j]->last(), E);
     }
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-    CheckLoopContains(loop1->nodes, loop1->count);
+    loop1->Check(order);
 
     for (int j = 0; j < size; j++) {
-      CheckLoopContains(loopN[j]->nodes, loopN[j]->count);
+      loopN[j]->Check(order);
       delete loopN[j];
     }
     delete[] loopN;
@@ -598,22 +636,23 @@
   BasicBlock* A = schedule.start();
   BasicBlock* B = schedule.NewBasicBlock();
   BasicBlock* C = schedule.NewBasicBlock();
-  BasicBlock* D = schedule.end();
+  BasicBlock* D = schedule.NewBasicBlock();
   BasicBlock* E = schedule.NewBasicBlock();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(B, D);
-  schedule.AddSuccessor(B, E);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(D, B);
-  schedule.AddSuccessor(E, B);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(B, D);
+  schedule.AddSuccessorForTesting(B, E);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(D, B);
+  schedule.AddSuccessorForTesting(E, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 5, true);
 
   BasicBlock* loop1[] = {B, C, D, E};
-  CheckLoopContains(loop1, 4);
+  CheckLoop(order, loop1, 4);
 }
 
 
@@ -624,7 +663,7 @@
   graph.SetStart(graph.NewNode(builder.Start(0)));
   graph.SetEnd(graph.NewNode(builder.End(), graph.start()));
 
-  USE(Scheduler::ComputeSchedule(&graph));
+  USE(Scheduler::ComputeSchedule(scope.main_zone(), &graph));
 }
 
 
@@ -639,7 +678,7 @@
 
   graph.SetEnd(graph.NewNode(builder.End(), ret));
 
-  USE(Scheduler::ComputeSchedule(&graph));
+  USE(Scheduler::ComputeSchedule(scope.main_zone(), &graph));
 }
 
 
@@ -678,9 +717,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c, y) {
@@ -823,9 +863,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b) {
@@ -935,9 +976,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1182,9 +1224,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1509,12 +1552,12 @@
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common_builder(scope.main_zone());
   JSOperatorBuilder js_builder(scope.main_zone());
-  MachineOperatorBuilder machine_builder;
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1544,7 +1587,7 @@
   Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil);
   USE(n20);
   n20->ReplaceInput(0, n9);
-  op = machine_builder.Int32Add();
+  op = &kIntAdd;
   Node* n19 = graph.NewNode(op, nil, nil);
   USE(n19);
   op = common_builder.Phi(kMachAnyTagged, 2);
@@ -1668,7 +1711,6 @@
   HandleAndZoneScope scope;
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1677,7 +1719,7 @@
   Node* p1 = graph.NewNode(common.Parameter(1), start);
   Node* d1 = CreateDiamond(&graph, &common, p0);
   Node* d2 = CreateDiamond(&graph, &common, p1);
-  Node* add = graph.NewNode(machine.Int32Add(), d1, d2);
+  Node* add = graph.NewNode(&kIntAdd, d1, d2);
   Node* ret = graph.NewNode(common.Return(), add, start, start);
   Node* end = graph.NewNode(common.End(), ret, start);
 
@@ -1691,7 +1733,6 @@
   HandleAndZoneScope scope;
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1700,7 +1741,7 @@
   Node* p1 = graph.NewNode(common.Parameter(1), start);
   Node* d1 = CreateDiamond(&graph, &common, p0);
   Node* d2 = CreateDiamond(&graph, &common, p1);
-  Node* add = graph.NewNode(machine.Int32Add(), d1, d2);
+  Node* add = graph.NewNode(&kIntAdd, d1, d2);
   Node* d3 = CreateDiamond(&graph, &common, add);
   Node* ret = graph.NewNode(common.Return(), d3, start, start);
   Node* end = graph.NewNode(common.End(), ret, start);
@@ -1710,4 +1751,374 @@
   ComputeAndVerifySchedule(33, &graph);
 }
 
+
+TEST(NestedFloatingDiamonds) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+  SimplifiedOperatorBuilder simplified(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* map = graph.NewNode(
+      simplified.LoadElement(AccessBuilder::ForFixedArrayElement()), p0, p0, p0,
+      start, f);
+  Node* br1 = graph.NewNode(common.Branch(), map, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* ttrue = graph.NewNode(common.Int32Constant(1));
+  Node* ffalse = graph.NewNode(common.Int32Constant(0));
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), ttrue, ffalse, m1);
+
+
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), fv, phi1, m);
+  Node* ephi1 = graph.NewNode(common.EffectPhi(2), start, map, m);
+
+  Node* ret = graph.NewNode(common.Return(), phi, ephi1, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(23, &graph);
+}
+
+
+TEST(NestedFloatingDiamondWithChain) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* p1 = graph.NewNode(common.Parameter(1), start);
+  Node* c = graph.NewNode(common.Int32Constant(7));
+
+  Node* brA1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* tA1 = graph.NewNode(common.IfTrue(), brA1);
+  Node* fA1 = graph.NewNode(common.IfFalse(), brA1);
+  Node* mA1 = graph.NewNode(common.Merge(2), tA1, fA1);
+  Node* phiA1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p1, mA1);
+
+  Node* brB1 = graph.NewNode(common.Branch(), p1, graph.start());
+  Node* tB1 = graph.NewNode(common.IfTrue(), brB1);
+  Node* fB1 = graph.NewNode(common.IfFalse(), brB1);
+  Node* mB1 = graph.NewNode(common.Merge(2), tB1, fB1);
+  Node* phiB1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p1, mB1);
+
+  Node* brA2 = graph.NewNode(common.Branch(), phiB1, mA1);
+  Node* tA2 = graph.NewNode(common.IfTrue(), brA2);
+  Node* fA2 = graph.NewNode(common.IfFalse(), brA2);
+  Node* mA2 = graph.NewNode(common.Merge(2), tA2, fA2);
+  Node* phiA2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phiB1, c, mA2);
+
+  Node* brB2 = graph.NewNode(common.Branch(), phiA1, mB1);
+  Node* tB2 = graph.NewNode(common.IfTrue(), brB2);
+  Node* fB2 = graph.NewNode(common.IfFalse(), brB2);
+  Node* mB2 = graph.NewNode(common.Merge(2), tB2, fB2);
+  Node* phiB2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phiA1, c, mB2);
+
+  Node* add = graph.NewNode(&kIntAdd, phiA2, phiB2);
+  Node* ret = graph.NewNode(common.Return(), add, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(35, &graph);
+}
+
+
+TEST(NestedFloatingDiamondWithLoop) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* loop = graph.NewNode(common.Loop(2), f, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, fv);
+  Node* br1 = graph.NewNode(common.Branch(), add, loop);
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+
+  loop->ReplaceInput(1, t1);  // close loop.
+  ind->ReplaceInput(1, ind);  // close induction variable.
+
+  Node* m = graph.NewNode(common.Merge(2), t, f1);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), fv, ind, m);
+
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond1) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+  Node* add = graph.NewNode(&kIntAdd, ind, c);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), add, p0, m1);
+
+  loop->ReplaceInput(1, t);    // close loop.
+  ind->ReplaceInput(1, phi1);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond2) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), c, ind, m1);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, phi1);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  loop->ReplaceInput(1, t);   // close loop.
+  ind->ReplaceInput(1, add);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond3) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+
+  Node* loop1 = graph.NewNode(common.Loop(2), t1, start);
+  Node* ind1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* add1 = graph.NewNode(&kIntAdd, ind1, c);
+  Node* br2 = graph.NewNode(common.Branch(), add1, loop1);
+  Node* t2 = graph.NewNode(common.IfTrue(), br2);
+  Node* f2 = graph.NewNode(common.IfFalse(), br2);
+
+  loop1->ReplaceInput(1, t2);   // close inner loop.
+  ind1->ReplaceInput(1, ind1);  // close inner induction variable.
+
+  Node* m1 = graph.NewNode(common.Merge(2), f1, f2);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), c, ind1, m1);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, phi1);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  loop->ReplaceInput(1, t);   // close loop.
+  ind->ReplaceInput(1, add);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(28, &graph);
+}
+
+
+TEST(PhisPushedDownToDifferentBranches) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* p1 = graph.NewNode(common.Parameter(1), start);
+
+  Node* v1 = graph.NewNode(common.Int32Constant(1));
+  Node* v2 = graph.NewNode(common.Int32Constant(2));
+  Node* v3 = graph.NewNode(common.Int32Constant(3));
+  Node* v4 = graph.NewNode(common.Int32Constant(4));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), v1, v2, m);
+  Node* phi2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), v3, v4, m);
+
+  Node* br2 = graph.NewNode(common.Branch(), p1, graph.start());
+  Node* t2 = graph.NewNode(common.IfTrue(), br2);
+  Node* f2 = graph.NewNode(common.IfFalse(), br2);
+  Node* m2 = graph.NewNode(common.Merge(2), t2, f2);
+  Node* phi3 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phi, phi2, m2);
+
+  Node* ret = graph.NewNode(common.Return(), phi3, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(24, &graph);
+}
+
+
+TEST(BranchHintTrue) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* tv = graph.NewNode(common.Int32Constant(6));
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(BranchHint::kTrue), p0, start);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), tv, fv, m);
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(13, &graph);
+  // Make sure the false block is marked as deferred.
+  CHECK(!schedule->block(t)->deferred());
+  CHECK(schedule->block(f)->deferred());
+}
+
+
+TEST(BranchHintFalse) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* tv = graph.NewNode(common.Int32Constant(6));
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(BranchHint::kFalse), p0, start);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), tv, fv, m);
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(13, &graph);
+  // Make sure the true block is marked as deferred.
+  CHECK(schedule->block(t)->deferred());
+  CHECK(!schedule->block(f)->deferred());
+}
+
+
+TEST(ScheduleTerminate) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  loop->ReplaceInput(1, loop);  // self loop, NTL.
+
+  Node* effect = graph.NewNode(common.EffectPhi(1), start, loop);
+  effect->ReplaceInput(0, effect);
+
+  Node* terminate = graph.NewNode(common.Terminate(1), effect, loop);
+  Node* end = graph.NewNode(common.End(), terminate);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(6, &graph);
+  BasicBlock* block = schedule->block(loop);
+  CHECK_NE(NULL, loop);
+  CHECK_EQ(block, schedule->block(effect));
+  CHECK_GE(block->rpo_number(), 0);
+}
+
 #endif
diff --git a/test/cctest/compiler/test-simplified-lowering.cc b/test/cctest/compiler/test-simplified-lowering.cc
index 96fb965..147aa32 100644
--- a/test/cctest/compiler/test-simplified-lowering.cc
+++ b/test/cctest/compiler/test-simplified-lowering.cc
@@ -5,8 +5,9 @@
 #include <limits>
 
 #include "src/compiler/access-builder.h"
+#include "src/compiler/change-lowering.h"
 #include "src/compiler/control-builders.h"
-#include "src/compiler/generic-node-inl.h"
+#include "src/compiler/graph-reducer.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/pipeline.h"
@@ -35,11 +36,10 @@
                            MachineType p3 = kMachNone,
                            MachineType p4 = kMachNone)
       : GraphBuilderTester<ReturnType>(p0, p1, p2, p3, p4),
-        typer(this->zone()),
+        typer(this->graph(), MaybeHandle<Context>()),
         javascript(this->zone()),
-        jsgraph(this->graph(), this->common(), &javascript, &typer,
-                this->machine()),
-        lowering(&jsgraph) {}
+        jsgraph(this->graph(), this->common(), &javascript, this->machine()),
+        lowering(&jsgraph, this->zone()) {}
 
   Typer typer;
   JSOperatorBuilder javascript;
@@ -48,16 +48,40 @@
 
   void LowerAllNodes() {
     this->End();
+    typer.Run();
     lowering.LowerAllNodes();
   }
 
+  void LowerAllNodesAndLowerChanges() {
+    this->End();
+    typer.Run();
+    lowering.LowerAllNodes();
+
+    Zone* zone = this->zone();
+    CompilationInfo info(zone->isolate(), zone);
+    Linkage linkage(
+        zone, Linkage::GetSimplifiedCDescriptor(zone, this->machine_sig_));
+    ChangeLowering lowering(&jsgraph, &linkage);
+    GraphReducer reducer(this->graph(), this->zone());
+    reducer.AddReducer(&lowering);
+    reducer.ReduceGraph();
+    Verifier::Run(this->graph());
+  }
+
+  void CheckNumberCall(double expected, double input) {
+    // TODO(titzer): make calls to NewNumber work in cctests.
+    if (expected <= Smi::kMinValue) return;
+    if (expected >= Smi::kMaxValue) return;
+    Handle<Object> num = factory()->NewNumber(input);
+    Object* result = this->Call(*num);
+    CHECK(factory()->NewNumber(expected)->SameValue(result));
+  }
+
   Factory* factory() { return this->isolate()->factory(); }
   Heap* heap() { return this->isolate()->heap(); }
 };
 
 
-#ifndef V8_TARGET_ARCH_ARM64
-// TODO(titzer): these result in a stub call that doesn't work on ARM64.
 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc.
 // TODO(titzer): test tagged representation for input to NumberToInt32.
 TEST(RunNumberToInt32_float64) {
@@ -68,6 +92,7 @@
   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
                       kMachFloat64};
   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
+  NodeProperties::SetBounds(loaded, Bounds(Type::Number()));
   Node* convert = t.NumberToInt32(loaded);
   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Signed32(),
                        kMachInt32};
@@ -96,6 +121,7 @@
   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
                       kMachFloat64};
   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
+  NodeProperties::SetBounds(loaded, Bounds(Type::Number()));
   Node* convert = t.NumberToUint32(loaded);
   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Unsigned32(),
                        kMachUint32};
@@ -113,7 +139,6 @@
     }
   }
 }
-#endif
 
 
 // Create a simple JSObject with a unique map.
@@ -207,10 +232,8 @@
 TEST(RunLoadStoreFixedArrayIndex) {
   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
   ElementAccess access = AccessBuilder::ForFixedArrayElement();
-  Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0),
-                             t.Int32Constant(2));
-  t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), t.Int32Constant(2),
-                 load);
+  Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
+  t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
   t.Return(load);
 
   t.LowerAllNodes();
@@ -235,14 +258,13 @@
   const int index = 12;
   const int array_length = 2 * index;
   ElementAccess buffer_access =
-      AccessBuilder::ForBackingStoreElement(kMachInt8);
+      AccessBuilder::ForTypedArrayElement(v8::kExternalInt8Array, true);
   Node* backing_store = t.LoadField(
       AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
   Node* load =
-      t.LoadElement(buffer_access, backing_store, t.Int32Constant(index),
-                    t.Int32Constant(array_length));
+      t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
   t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
-                 t.Int32Constant(array_length), load);
+                 load);
   t.Return(t.jsgraph.TrueConstant());
 
   t.LowerAllNodes();
@@ -329,9 +351,8 @@
                               kMachAnyTagged};
 
       SimplifiedLoweringTester<Object*> t;
-      Node* load = t.LoadElement(
-          access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)),
-          t.Int32Constant(static_cast<int>(arraysize(smis))));
+      Node* load = t.LoadElement(access, t.PointerConstant(smis),
+                                 t.Int32Constant(static_cast<int>(j)));
       t.Return(load);
       t.LowerAllNodes();
 
@@ -360,8 +381,7 @@
       SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
       Node* p0 = t.Parameter(0);
       t.StoreElement(access, t.PointerConstant(smis),
-                     t.Int32Constant(static_cast<int>(j)),
-                     t.Int32Constant(static_cast<int>(arraysize(smis))), p0);
+                     t.Int32Constant(static_cast<int>(j)), p0);
       t.Return(p0);
       t.LowerAllNodes();
 
@@ -427,10 +447,8 @@
 
     SimplifiedLoweringTester<Object*> t;
     Node* ptr = GetBaseNode(&t);
-    Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index),
-                               t.Int32Constant(static_cast<int>(num_elements)));
-    t.StoreElement(access, ptr, t.Int32Constant(to_index),
-                   t.Int32Constant(static_cast<int>(num_elements)), load);
+    Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index));
+    t.StoreElement(access, ptr, t.Int32Constant(to_index), load);
     t.Return(t.jsgraph.TrueConstant());
     t.LowerAllNodes();
     t.GenerateCode();
@@ -648,9 +666,9 @@
   explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
                         Type* p2_type = Type::None())
       : GraphAndBuilders(main_zone()),
-        typer(main_zone()),
+        typer(graph(), MaybeHandle<Context>()),
         javascript(main_zone()),
-        jsgraph(graph(), common(), &javascript, &typer, machine()) {
+        jsgraph(graph(), common(), &javascript, machine()) {
     start = graph()->NewNode(common()->Start(2));
     graph()->SetStart(start);
     ret =
@@ -660,6 +678,7 @@
     p0 = graph()->NewNode(common()->Parameter(0), start);
     p1 = graph()->NewNode(common()->Parameter(1), start);
     p2 = graph()->NewNode(common()->Parameter(2), start);
+    typer.Run();
     NodeProperties::SetBounds(p0, Bounds(p0_type));
     NodeProperties::SetBounds(p1, Bounds(p1_type));
     NodeProperties::SetBounds(p2, Bounds(p2_type));
@@ -679,10 +698,7 @@
     CHECK_EQ(expected, node->opcode());
   }
 
-  void Lower() {
-    SimplifiedLowering lowering(&jsgraph);
-    lowering.LowerAllNodes();
-  }
+  void Lower() { SimplifiedLowering(&jsgraph, jsgraph.zone()).LowerAllNodes(); }
 
   // Inserts the node as the return value of the graph.
   Node* Return(Node* node) {
@@ -718,6 +734,17 @@
     }
   }
 
+  Node* ExampleWithTypeAndRep(Type* type, MachineType mach_type) {
+    FieldAccess access = {kUntaggedBase, 0, Handle<Name>::null(), type,
+                          mach_type};
+    // TODO(titzer): using loads here just to force the representation is ugly.
+    Node* node = graph()->NewNode(simplified()->LoadField(access),
+                                  jsgraph.IntPtrConstant(0), graph()->start(),
+                                  graph()->start());
+    NodeProperties::SetBounds(node, Bounds(type));
+    return node;
+  }
+
   Node* Use(Node* node, MachineType type) {
     if (type & kTypeInt32) {
       return graph()->NewNode(machine()->Int32LessThan(), node,
@@ -731,6 +758,9 @@
     } else if (type & kRepWord64) {
       return graph()->NewNode(machine()->Int64LessThan(), node,
                               Int64Constant(1));
+    } else if (type & kRepWord32) {
+      return graph()->NewNode(machine()->Word32Equal(), node,
+                              jsgraph.Int32Constant(1));
     } else {
       return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node,
                               jsgraph.TrueConstant());
@@ -757,6 +787,50 @@
 };
 
 
+TEST(LowerAnyToBoolean_bit_bit) {
+  // AnyToBoolean(x: kRepBit) used as kRepBit
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Handle<Object> zero = f->NewNumber(0);
+  Handle<Object> one = f->NewNumber(1);
+  Type* singleton_zero = Type::Constant(zero, scope.main_zone());
+  Type* singleton_one = Type::Constant(one, scope.main_zone());
+  Type* zero_one_range = Type::Range(zero, one, scope.main_zone());
+  static Type* kTypes[] = {
+      singleton_zero, singleton_one, zero_one_range, Type::Boolean(),
+      Type::Union(Type::Boolean(), singleton_zero, scope.main_zone()),
+      Type::Union(Type::Boolean(), singleton_one, scope.main_zone()),
+      Type::Union(Type::Boolean(), zero_one_range, scope.main_zone())};
+  for (Type* type : kTypes) {
+    TestingGraph t(type);
+    Node* x = t.ExampleWithTypeAndRep(type, kRepBit);
+    Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
+    Node* use = t.Branch(cnv);
+    t.Lower();
+    CHECK_EQ(x, use->InputAt(0));
+  }
+}
+
+
+#if V8_TURBOFAN_TARGET
+
+TEST(LowerAnyToBoolean_tagged_tagged) {
+  // AnyToBoolean(x: kRepTagged) used as kRepTagged
+  TestingGraph t(Type::Any());
+  Node* x = t.p0;
+  Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
+  Node* use = t.Use(cnv, kRepTagged);
+  t.Return(use);
+  t.Lower();
+  CHECK_EQ(IrOpcode::kCall, cnv->opcode());
+  CHECK_EQ(IrOpcode::kHeapConstant, cnv->InputAt(0)->opcode());
+  CHECK_EQ(x, cnv->InputAt(1));
+  CHECK_EQ(t.jsgraph.NoContextConstant(), cnv->InputAt(2));
+}
+
+#endif
+
+
 TEST(LowerBooleanNot_bit_bit) {
   // BooleanNot(x: kRepBit) used as kRepBit
   TestingGraph t(Type::Boolean());
@@ -765,7 +839,7 @@
   Node* use = t.Branch(inv);
   t.Lower();
   Node* cmp = use->InputAt(0);
-  CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
+  CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
   Node* f = t.jsgraph.Int32Constant(0);
   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
@@ -782,7 +856,7 @@
   t.Lower();
   CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
   Node* cmp = use->InputAt(0)->InputAt(0);
-  CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
+  CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
   Node* f = t.jsgraph.Int32Constant(0);
   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
@@ -921,24 +995,50 @@
 
 
 TEST(LowerNumberAddSub_to_int32) {
-  TestingGraph t(Type::Signed32(), Type::Signed32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
-                                t.simplified()->NumberAdd(),
-                                t.simplified()->NumberToInt32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
-                                t.simplified()->NumberSubtract(),
-                                t.simplified()->NumberToInt32());
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Type* small_range =
+      Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
+  Type* large_range =
+      Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
+  static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
+                          large_range};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    for (size_t j = 0; j < arraysize(types); j++) {
+      TestingGraph t(types[i], types[j]);
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
+                                    t.simplified()->NumberAdd(),
+                                    t.simplified()->NumberToInt32());
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
+                                    t.simplified()->NumberSubtract(),
+                                    t.simplified()->NumberToInt32());
+    }
+  }
 }
 
 
 TEST(LowerNumberAddSub_to_uint32) {
-  TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
-                                t.simplified()->NumberAdd(),
-                                t.simplified()->NumberToUint32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
-                                t.simplified()->NumberSubtract(),
-                                t.simplified()->NumberToUint32());
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Type* small_range =
+      Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
+  Type* large_range =
+      Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
+  static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
+                          large_range};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    for (size_t j = 0; j < arraysize(types); j++) {
+      TestingGraph t(types[i], types[j]);
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
+                                    t.simplified()->NumberAdd(),
+                                    t.simplified()->NumberToUint32());
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
+                                    t.simplified()->NumberSubtract(),
+                                    t.simplified()->NumberToUint32());
+    }
+  }
 }
 
 
@@ -958,8 +1058,10 @@
     TestingGraph t(test_types[i], test_types[i]);
 
     t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide());
-    t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
-                         t.simplified()->NumberModulus());
+    if (!test_types[i]->Is(Type::Unsigned32())) {
+      t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
+                           t.simplified()->NumberModulus());
+    }
   }
 }
 
@@ -1006,7 +1108,7 @@
 TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) {
   // NumberToInt32(x: kRepFloat64) used as kMachInt32
   TestingGraph t(Type::Number());
-  Node* p0 = t.ExampleWithOutput(kMachFloat64);
+  Node* p0 = t.ExampleWithTypeAndRep(Type::Number(), kMachFloat64);
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0);
   Node* use = t.Use(trunc, kMachInt32);
   t.Return(use);
@@ -1030,17 +1132,6 @@
 }
 
 
-TEST(LowerNumberToInt32_to_ChangeFloat64ToTagged) {
-  // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepTagged
-}
-
-
-TEST(LowerNumberToInt32_to_ChangeFloat64ToInt32) {
-  // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepWord32
-  // | kTypeInt32
-}
-
-
 TEST(LowerNumberToUint32_to_nop) {
   // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepTagged
   TestingGraph t(Type::Unsigned32());
@@ -1078,6 +1169,8 @@
   // NumberToUint32(x: kRepFloat64) used as kMachUint32
   TestingGraph t(Type::Number());
   Node* p0 = t.ExampleWithOutput(kMachFloat64);
+  // TODO(titzer): run the typer here, or attach machine type to param.
+  NodeProperties::SetBounds(p0, Bounds(Type::Number()));
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), p0);
   Node* use = t.Use(trunc, kMachUint32);
   t.Return(use);
@@ -1101,20 +1194,67 @@
 }
 
 
-TEST(LowerNumberToUint32_to_ChangeFloat64ToTagged) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
-  // kRepTagged
+TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_uint32) {
+  // NumberToUint32(x: kRepFloat64) used as kRepWord32
+  TestingGraph t(Type::Unsigned32());
+  Node* input = t.ExampleWithTypeAndRep(Type::Number(), kMachFloat64);
+  Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), input);
+  Node* use = t.Use(trunc, kRepWord32);
+  t.Return(use);
+  t.Lower();
+  CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, input, use->InputAt(0));
 }
 
 
-TEST(LowerNumberToUint32_to_ChangeFloat64ToUint32) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
-  // kRepWord32
+TEST(LowerNumberToUI32_of_Float64_used_as_word32) {
+  // NumberTo(Int,Uint)32(x: kRepFloat64 | kType(Int,Uint)32) used as
+  // kType(Int,Uint)32 | kRepWord32
+  Type* types[] = {Type::Signed32(), Type::Unsigned32()};
+  MachineType mach[] = {kTypeInt32, kTypeUint32, kMachNone};
+
+  for (int i = 0; i < 2; i++) {
+    for (int u = 0; u < 3; u++) {
+      TestingGraph t(types[i]);
+      Node* input = t.ExampleWithTypeAndRep(
+          types[i], static_cast<MachineType>(kRepFloat64 | mach[i]));
+      const Operator* op = i == 0 ? t.simplified()->NumberToInt32()
+                                  : t.simplified()->NumberToUint32();
+      Node* trunc = t.graph()->NewNode(op, input);
+      Node* use = t.Use(trunc, static_cast<MachineType>(kRepWord32 | mach[u]));
+      t.Return(use);
+      t.Lower();
+      IrOpcode::Value opcode = i == 0 ? IrOpcode::kChangeFloat64ToInt32
+                                      : IrOpcode::kChangeFloat64ToUint32;
+      CheckChangeOf(opcode, input, use->InputAt(0));
+    }
+  }
 }
 
 
-TEST(LowerNumberToUint32_to_TruncateFloat64ToUint32) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64) used as kRepWord32
+TEST(LowerNumberToUI32_of_Float64_used_as_tagged) {
+  // NumberTo(Int,Uint)32(x: kRepFloat64 | kType(Int,Uint)32) used as
+  // kType(Int,Uint)32 | kRepTagged
+  Type* types[] = {Type::Signed32(), Type::Unsigned32(), Type::Any()};
+  MachineType mach[] = {kTypeInt32, kTypeUint32, kMachNone};
+
+  for (int i = 0; i < 2; i++) {
+    for (int u = 0; u < 3; u++) {
+      TestingGraph t(types[i]);
+      Node* input = t.ExampleWithTypeAndRep(
+          types[i], static_cast<MachineType>(kRepFloat64 | mach[i]));
+      const Operator* op = i == 0 ? t.simplified()->NumberToInt32()
+                                  : t.simplified()->NumberToUint32();
+      Node* trunc = t.graph()->NewNode(op, input);
+      // TODO(titzer): we use the store here to force the representation.
+      FieldAccess access = {kTaggedBase, 0, Handle<Name>(), types[u],
+                            static_cast<MachineType>(mach[u] | kRepTagged)};
+      Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
+                                       trunc, t.start, t.start);
+      t.Effect(store);
+      t.Lower();
+      CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, input, store->InputAt(2));
+    }
+  }
 }
 
 
@@ -1268,45 +1408,54 @@
 }
 
 
+namespace {
+
 void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) {
-  Int32Matcher index = Int32Matcher(load_or_store->InputAt(1));
-  CHECK(index.Is(access.offset - access.tag()));
+  IntPtrMatcher mindex(load_or_store->InputAt(1));
+  CHECK(mindex.Is(access.offset - access.tag()));
 }
 
 
 Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) {
-  Int32BinopMatcher index(load_or_store->InputAt(1));
-  CHECK_EQ(IrOpcode::kInt32Add, index.node()->opcode());
-  CHECK(index.right().Is(access.header_size - access.tag()));
+  Node* index = load_or_store->InputAt(1);
+  if (kPointerSize == 8) {
+    CHECK_EQ(IrOpcode::kChangeUint32ToUint64, index->opcode());
+    index = index->InputAt(0);
+  }
 
-  int element_size = ElementSizeOf(access.machine_type);
+  Int32BinopMatcher mindex(index);
+  CHECK_EQ(IrOpcode::kInt32Add, mindex.node()->opcode());
+  CHECK(mindex.right().Is(access.header_size - access.tag()));
 
-  if (element_size != 1) {
-    Int32BinopMatcher mul(index.left().node());
-    CHECK_EQ(IrOpcode::kInt32Mul, mul.node()->opcode());
-    CHECK(mul.right().Is(element_size));
-    return mul.left().node();
+  const int element_size_shift = ElementSizeLog2Of(access.machine_type);
+  if (element_size_shift) {
+    Int32BinopMatcher shl(mindex.left().node());
+    CHECK_EQ(IrOpcode::kWord32Shl, shl.node()->opcode());
+    CHECK(shl.right().Is(element_size_shift));
+    return shl.left().node();
   } else {
-    return index.left().node();
+    return mindex.left().node();
   }
 }
 
 
-static const MachineType machine_reps[] = {
-    kRepBit,    kMachInt8,    kMachInt16,    kMachInt32,
-    kMachInt64, kMachFloat64, kMachAnyTagged};
+const MachineType kMachineReps[] = {kRepBit,       kMachInt8,  kMachInt16,
+                                    kMachInt32,    kMachInt64, kMachFloat64,
+                                    kMachAnyTagged};
+
+}  // namespace
 
 
 TEST(LowerLoadField_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), machine_reps[i]};
+                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
     Node* load =
         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
-    Node* use = t.Use(load, machine_reps[i]);
+    Node* use = t.Use(load, kMachineReps[i]);
     t.Return(use);
     t.Lower();
     CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1314,7 +1463,7 @@
     CheckFieldAccessArithmetic(access, load);
 
     MachineType rep = OpParameter<MachineType>(load);
-    CHECK_EQ(machine_reps[i], rep);
+    CHECK_EQ(kMachineReps[i], rep);
   }
 }
 
@@ -1322,12 +1471,12 @@
 TEST(LowerStoreField_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), machine_reps[i]};
+                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
 
-    Node* val = t.ExampleWithOutput(machine_reps[i]);
+    Node* val = t.ExampleWithOutput(kMachineReps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
                                      val, t.start, t.start);
     t.Effect(store);
@@ -1337,10 +1486,10 @@
     CheckFieldAccessArithmetic(access, store);
 
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (machine_reps[i] & kRepTagged) {
+    if (kMachineReps[i] & kRepTagged) {
       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
     }
-    CHECK_EQ(machine_reps[i], rep.machine_type());
+    CHECK_EQ(kMachineReps[i], rep.machine_type());
   }
 }
 
@@ -1348,14 +1497,13 @@
 TEST(LowerLoadElement_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+                            Type::Any(), kMachineReps[i]};
 
-    Node* load =
-        t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
-                           t.jsgraph.Int32Constant(1024), t.start);
-    Node* use = t.Use(load, machine_reps[i]);
+    Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
+                                    t.p1, t.start, t.start);
+    Node* use = t.Use(load, kMachineReps[i]);
     t.Return(use);
     t.Lower();
     CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1363,7 +1511,7 @@
     CheckElementAccessArithmetic(access, load);
 
     MachineType rep = OpParameter<MachineType>(load);
-    CHECK_EQ(machine_reps[i], rep);
+    CHECK_EQ(kMachineReps[i], rep);
   }
 }
 
@@ -1371,14 +1519,13 @@
 TEST(LowerStoreElement_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+                            Type::Any(), kMachineReps[i]};
 
-    Node* val = t.ExampleWithOutput(machine_reps[i]);
+    Node* val = t.ExampleWithOutput(kMachineReps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                                     t.p1, t.jsgraph.Int32Constant(1024), val,
-                                     t.start, t.start);
+                                     t.p1, val, t.start, t.start);
     t.Effect(store);
     t.Lower();
     CHECK_EQ(IrOpcode::kStore, store->opcode());
@@ -1386,10 +1533,10 @@
     CheckElementAccessArithmetic(access, store);
 
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (machine_reps[i] & kRepTagged) {
+    if (kMachineReps[i] & kRepTagged) {
       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
     }
-    CHECK_EQ(machine_reps[i], rep.machine_type());
+    CHECK_EQ(kMachineReps[i], rep.machine_type());
   }
 }
 
@@ -1397,12 +1544,12 @@
 TEST(InsertChangeForLoadElementIndex) {
   // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
   //   Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.p2, t.start);
+                                  t.p1, t.start, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1416,12 +1563,12 @@
 TEST(InsertChangeForStoreElementIndex) {
   // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
   //   Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* store =
-      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2,
+      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1,
                          t.jsgraph.TrueConstant(), t.start, t.start);
   t.Effect(store);
   t.Lower();
@@ -1440,7 +1587,7 @@
                           kMachFloat64};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.p1, t.start);
+                                  t.p1, t.start, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1467,13 +1614,13 @@
 
 TEST(InsertChangeForStoreElement) {
   // TODO(titzer): test all load/store representation change insertions.
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
-  Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                                   t.jsgraph.Int32Constant(0), t.p2, t.p1,
-                                   t.start, t.start);
+  Node* store =
+      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
+                         t.jsgraph.Int32Constant(0), t.p1, t.start, t.start);
   t.Effect(store);
   t.Lower();
 
@@ -1504,10 +1651,11 @@
   TestingGraph t(Type::Any(), Type::Signed32());
   static const MachineType kMachineTypes[] = {kMachInt32, kMachUint32,
                                               kMachFloat64};
+  Type* kTypes[] = {Type::Signed32(), Type::Unsigned32(), Type::Number()};
 
   for (size_t i = 0; i < arraysize(kMachineTypes); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), kMachineTypes[i]};
+                          Handle<Name>::null(), kTypes[i], kMachineTypes[i]};
 
     Node* load0 =
         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
@@ -1525,36 +1673,405 @@
 }
 
 
-// TODO(titzer): this tests current behavior of assuming an implicit
-// representation change in loading float32s. Fix when float32 is fully
-// supported.
-TEST(ImplicitFloat32ToFloat64InLoads) {
-  TestingGraph t(Type::Any());
+TEST(RunNumberDivide_minus_1_TruncatingToInt32) {
+  SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+  Node* num = t.NumberToInt32(t.Parameter(0));
+  Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1));
+  Node* trunc = t.NumberToInt32(div);
+  t.Return(trunc);
 
-  FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                        Handle<Name>::null(), Type::Any(), kMachFloat32};
+  if (Pipeline::SupportedTarget()) {
+    t.LowerAllNodesAndLowerChanges();
+    t.GenerateCode();
 
-  Node* load =
-      t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
-  t.Return(load);
-  t.Lower();
-  CHECK_EQ(IrOpcode::kLoad, load->opcode());
-  CHECK_EQ(t.p0, load->InputAt(0));
-  CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
+    FOR_INT32_INPUTS(i) {
+      int32_t x = 0 - *i;
+      t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+    }
+  }
 }
 
 
-TEST(ImplicitFloat64ToFloat32InStores) {
-  TestingGraph t(Type::Any(), Type::Signed32());
-  FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                        Handle<Name>::null(), Type::Any(), kMachFloat32};
+TEST(NumberMultiply_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000};
 
-  Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
-                                   t.p1, t.start, t.start);
-  t.Effect(store);
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+    Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
+    t.Return(trunc);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Mul, mul->opcode());
+  }
+}
+
+
+TEST(RunNumberMultiply_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    double k = static_cast<double>(constants[i]);
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(mul);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        int32_t x = DoubleToInt32(static_cast<double>(*i) * k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(RunNumberMultiply_TruncatingToUint32) {
+  uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    double k = static_cast<double>(constants[i]);
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToUint32(mul);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = DoubleToUint32(static_cast<double>(*i) * k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(RunNumberDivide_2_TruncatingToUint32) {
+  SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+  Node* num = t.NumberToUint32(t.Parameter(0));
+  Node* div = t.NumberDivide(num, t.jsgraph.Constant(2));
+  Node* trunc = t.NumberToUint32(div);
+  t.Return(trunc);
+
+  if (Pipeline::SupportedTarget()) {
+    t.LowerAllNodesAndLowerChanges();
+    t.GenerateCode();
+
+    FOR_UINT32_INPUTS(i) {
+      uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0));
+      t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+    }
+  }
+}
+
+
+TEST(NumberMultiply_ConstantOutOfRange) {
+  TestingGraph t(Type::Signed32());
+  Node* k = t.jsgraph.Constant(1000000023);
+  Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+  Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
+  t.Return(trunc);
   t.Lower();
 
-  CHECK_EQ(IrOpcode::kStore, store->opcode());
-  CHECK_EQ(t.p0, store->InputAt(0));
-  CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
+  CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
+}
+
+
+TEST(NumberMultiply_NonTruncating) {
+  TestingGraph t(Type::Signed32());
+  Node* k = t.jsgraph.Constant(111);
+  Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+  t.Return(mul);
+  t.Lower();
+
+  CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
+}
+
+
+TEST(NumberDivide_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberDivide_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* div = t.NumberDivide(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(div);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        if (*i == INT_MAX) continue;  // exclude max int.
+        int32_t x = DoubleToInt32(static_cast<double>(*i) / k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberDivide_TruncatingToUint32) {
+  double constants[] = {1, 3, 100, 1000, 100998348};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachUint32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberDivide_TruncatingToUint32) {
+  uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    uint32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k)));
+    Node* trunc = t.NumberToUint32(div);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = *i / k;
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberDivide_BadConstants) {
+  {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(-1);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Sub, use->InputAt(0)->opcode());
+  }
+
+  {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(0);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
+    CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
+  }
+
+  {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(0);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachUint32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
+    CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
+  }
+}
+
+
+TEST(NumberModulus_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    Node* use = t.Use(mod, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberModulus_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(mod);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        if (*i == INT_MAX) continue;  // exclude max int.
+        int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k));
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberModulus_TruncatingToUint32) {
+  double constants[] = {1, 3, 100, 1000, 100998348};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod);
+    Node* ret = t.Return(trunc);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kUint32Mod, ret->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberModulus_TruncatingToUint32) {
+  uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    uint32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* mod =
+        t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k)));
+    Node* trunc = t.NumberToUint32(mod);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = *i % k;
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberModulus_Int32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    t.Return(mod);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode());  // Pesky -0 behavior.
+  }
+}
+
+
+TEST(NumberModulus_Uint32) {
+  const double kConstants[] = {2, 100, 1000, 1024, 2048};
+  const MachineType kTypes[] = {kMachInt32, kMachUint32};
+
+  for (auto const type : kTypes) {
+    for (auto const c : kConstants) {
+      TestingGraph t(Type::Unsigned32());
+      Node* k = t.jsgraph.Constant(c);
+      Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+      Node* use = t.Use(mod, type);
+      t.Return(use);
+      t.Lower();
+
+      CHECK_EQ(IrOpcode::kUint32Mod, use->InputAt(0)->opcode());
+    }
+  }
+}
+
+
+TEST(PhiRepresentation) {
+  HandleAndZoneScope scope;
+  Zone* z = scope.main_zone();
+
+  struct TestData {
+    Type* arg1;
+    Type* arg2;
+    MachineType use;
+    MachineTypeUnion expected;
+  };
+
+  TestData test_data[] = {
+      {Type::Signed32(), Type::Unsigned32(), kMachInt32,
+       kRepWord32 | kTypeNumber},
+      {Type::Signed32(), Type::Unsigned32(), kMachUint32,
+       kRepWord32 | kTypeNumber},
+      {Type::Signed32(), Type::Signed32(), kMachInt32, kMachInt32},
+      {Type::Unsigned32(), Type::Unsigned32(), kMachInt32, kMachUint32},
+      {Type::Number(), Type::Signed32(), kMachInt32, kMachFloat64},
+      {Type::Signed32(), Type::String(), kMachInt32, kMachAnyTagged}};
+
+  for (auto const d : test_data) {
+    TestingGraph t(d.arg1, d.arg2, Type::Boolean());
+
+    Node* br = t.graph()->NewNode(t.common()->Branch(), t.p2, t.start);
+    Node* tb = t.graph()->NewNode(t.common()->IfTrue(), br);
+    Node* fb = t.graph()->NewNode(t.common()->IfFalse(), br);
+    Node* m = t.graph()->NewNode(t.common()->Merge(2), tb, fb);
+
+    Node* phi =
+        t.graph()->NewNode(t.common()->Phi(kMachAnyTagged, 2), t.p0, t.p1, m);
+
+    Bounds phi_bounds = Bounds::Either(Bounds(d.arg1), Bounds(d.arg2), z);
+    NodeProperties::SetBounds(phi, phi_bounds);
+
+    Node* use = t.Use(phi, d.use);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(d.expected, OpParameter<MachineType>(phi));
+  }
 }
diff --git a/test/cctest/compiler/test-typer.cc b/test/cctest/compiler/test-typer.cc
new file mode 100644
index 0000000..5f7f55a
--- /dev/null
+++ b/test/cctest/compiler/test-typer.cc
@@ -0,0 +1,380 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <functional>
+
+#include "src/codegen.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/typer.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/graph-builder-tester.h"
+#include "test/cctest/types-fuzz.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+
+// TODO(titzer): generate a large set of deterministic inputs for these tests.
+class TyperTester : public HandleAndZoneScope, public GraphAndBuilders {
+ public:
+  TyperTester()
+      : GraphAndBuilders(main_zone()),
+        types_(main_zone(), isolate()),
+        typer_(graph(), MaybeHandle<Context>()),
+        javascript_(main_zone()) {
+    Node* s = graph()->NewNode(common()->Start(3));
+    graph()->SetStart(s);
+    context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start());
+    rng_ = isolate()->random_number_generator();
+
+    integers.push_back(0);
+    integers.push_back(0);
+    integers.push_back(-1);
+    integers.push_back(+1);
+    integers.push_back(-V8_INFINITY);
+    integers.push_back(+V8_INFINITY);
+    for (int i = 0; i < 5; ++i) {
+      double x = rng_->NextInt();
+      integers.push_back(x);
+      x *= rng_->NextInt();
+      if (!IsMinusZero(x)) integers.push_back(x);
+    }
+
+    int32s.push_back(0);
+    int32s.push_back(0);
+    int32s.push_back(-1);
+    int32s.push_back(+1);
+    int32s.push_back(kMinInt);
+    int32s.push_back(kMaxInt);
+    for (int i = 0; i < 10; ++i) {
+      int32s.push_back(rng_->NextInt());
+    }
+  }
+
+  Types<Type, Type*, Zone> types_;
+  Typer typer_;
+  JSOperatorBuilder javascript_;
+  Node* context_node_;
+  v8::base::RandomNumberGenerator* rng_;
+  std::vector<double> integers;
+  std::vector<double> int32s;
+
+  Isolate* isolate() { return main_isolate(); }
+  Graph* graph() { return main_graph_; }
+  CommonOperatorBuilder* common() { return &main_common_; }
+
+  Node* Parameter(int index = 0) {
+    return graph()->NewNode(common()->Parameter(index), graph()->start());
+  }
+
+  Type* TypeBinaryOp(const Operator* op, Type* lhs, Type* rhs) {
+    Node* p0 = Parameter(0);
+    Node* p1 = Parameter(1);
+    NodeProperties::SetBounds(p0, Bounds(lhs));
+    NodeProperties::SetBounds(p1, Bounds(rhs));
+    Node* n = graph()->NewNode(
+        op, p0, p1, context_node_, graph()->start(), graph()->start());
+    return NodeProperties::GetBounds(n).upper;
+  }
+
+  Type* RandomRange(bool int32 = false) {
+    std::vector<double>& numbers = int32 ? int32s : integers;
+    double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
+    double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
+    return NewRange(i, j);
+  }
+
+  Type* NewRange(double i, double j) {
+    Factory* f = isolate()->factory();
+    i::Handle<i::Object> min = f->NewNumber(i);
+    i::Handle<i::Object> max = f->NewNumber(j);
+    if (min->Number() > max->Number()) std::swap(min, max);
+    return Type::Range(min, max, main_zone());
+  }
+
+  double RandomInt(double min, double max) {
+    switch (rng_->NextInt(4)) {
+      case 0: return min;
+      case 1: return max;
+      default: break;
+    }
+    if (min == +V8_INFINITY) return +V8_INFINITY;
+    if (max == -V8_INFINITY) return -V8_INFINITY;
+    if (min == -V8_INFINITY && max == +V8_INFINITY) {
+      return rng_->NextInt() * static_cast<double>(rng_->NextInt());
+    }
+    double result = nearbyint(min + (max - min) * rng_->NextDouble());
+    if (IsMinusZero(result)) return 0;
+    if (std::isnan(result)) return rng_->NextInt(2) ? min : max;
+    DCHECK(min <= result && result <= max);
+    return result;
+  }
+
+  double RandomInt(Type::RangeType* range) {
+    return RandomInt(range->Min()->Number(), range->Max()->Number());
+  }
+
+  // Careful, this function runs O(max_width^5) trials.
+  template <class BinaryFunction>
+  void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun,
+                                    int max_width) {
+    const int min_min = -2 - max_width / 2;
+    const int max_min = 2 + max_width / 2;
+    for (int width = 0; width < max_width; width++) {
+      for (int lmin = min_min; lmin <= max_min; lmin++) {
+        for (int rmin = min_min; rmin <= max_min; rmin++) {
+          Type* r1 = NewRange(lmin, lmin + width);
+          Type* r2 = NewRange(rmin, rmin + width);
+          Type* expected_type = TypeBinaryOp(op, r1, r2);
+
+          for (int x1 = lmin; x1 < lmin + width; x1++) {
+            for (int x2 = rmin; x2 < rmin + width; x2++) {
+              double result_value = opfun(x1, x2);
+              Type* result_type = Type::Constant(
+                  isolate()->factory()->NewNumber(result_value), main_zone());
+              CHECK(result_type->Is(expected_type));
+            }
+          }
+        }
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) {
+    TestBinaryArithOpCloseToZero(op, opfun, 8);
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange()->AsRange();
+      Type::RangeType* r2 = RandomRange()->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        double x1 = RandomInt(r1);
+        double x2 = RandomInt(r2);
+        double result_value = opfun(x1, x2);
+        Type* result_type = Type::Constant(
+            isolate()->factory()->NewNumber(result_value), main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange()->AsRange();
+      Type::RangeType* r2 = RandomRange()->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        double x1 = RandomInt(r1);
+        double x2 = RandomInt(r2);
+        bool result_value = opfun(x1, x2);
+        Type* result_type =
+            Type::Constant(result_value ? isolate()->factory()->true_value()
+                                        : isolate()->factory()->false_value(),
+                           main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange(true)->AsRange();
+      Type::RangeType* r2 = RandomRange(true)->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        int32_t x1 = static_cast<int32_t>(RandomInt(r1));
+        int32_t x2 = static_cast<int32_t>(RandomInt(r2));
+        double result_value = opfun(x1, x2);
+        Type* result_type = Type::Constant(
+            isolate()->factory()->NewNumber(result_value), main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  Type* RandomSubtype(Type* type) {
+    Type* subtype;
+    do {
+      subtype = types_.Fuzz();
+    } while (!subtype->Is(type));
+    return subtype;
+  }
+
+  void TestBinaryMonotonicity(const Operator* op) {
+    for (int i = 0; i < 50; ++i) {
+      Type* type1 = types_.Fuzz();
+      Type* type2 = types_.Fuzz();
+      Type* type = TypeBinaryOp(op, type1, type2);
+      Type* subtype1 = RandomSubtype(type1);;
+      Type* subtype2 = RandomSubtype(type2);;
+      Type* subtype = TypeBinaryOp(op, subtype1, subtype2);
+      CHECK(subtype->Is(type));
+    }
+  }
+};
+
+
+static int32_t shift_left(int32_t x, int32_t y) { return x << y; }
+static int32_t shift_right(int32_t x, int32_t y) { return x >> y; }
+static int32_t bit_or(int32_t x, int32_t y) { return x | y; }
+static int32_t bit_and(int32_t x, int32_t y) { return x & y; }
+static int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
+
+
+//------------------------------------------------------------------------------
+// Soundness
+//   For simplicity, we currently only test soundness on expression operators
+//   that have a direct equivalent in C++.  Also, testing is currently limited
+//   to ranges as input types.
+
+
+TEST(TypeJSAdd) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Add(), std::plus<double>());
+}
+
+
+TEST(TypeJSSubtract) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Subtract(), std::minus<double>());
+}
+
+
+TEST(TypeJSMultiply) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Multiply(), std::multiplies<double>());
+}
+
+
+TEST(TypeJSDivide) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Divide(), std::divides<double>());
+}
+
+
+TEST(TypeJSModulus) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Modulus(), modulo);
+}
+
+
+TEST(TypeJSBitwiseOr) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseOr(), bit_or);
+}
+
+
+TEST(TypeJSBitwiseAnd) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseAnd(), bit_and);
+}
+
+
+TEST(TypeJSBitwiseXor) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseXor(), bit_xor);
+}
+
+
+TEST(TypeJSShiftLeft) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.ShiftLeft(), shift_left);
+}
+
+
+TEST(TypeJSShiftRight) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.ShiftRight(), shift_right);
+}
+
+
+TEST(TypeJSLessThan) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.LessThan(), std::less<double>());
+}
+
+
+TEST(TypeJSLessThanOrEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.LessThanOrEqual(), std::less_equal<double>());
+}
+
+
+TEST(TypeJSGreaterThan) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.GreaterThan(), std::greater<double>());
+}
+
+
+TEST(TypeJSGreaterThanOrEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.GreaterThanOrEqual(), std::greater_equal<double>());
+}
+
+
+TEST(TypeJSEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.Equal(), std::equal_to<double>());
+}
+
+
+TEST(TypeJSNotEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.NotEqual(), std::not_equal_to<double>());
+}
+
+
+// For numbers there's no difference between strict and non-strict equality.
+TEST(TypeJSStrictEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.StrictEqual(), std::equal_to<double>());
+}
+
+
+TEST(TypeJSStrictNotEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.StrictNotEqual(), std::not_equal_to<double>());
+}
+
+
+//------------------------------------------------------------------------------
+// Monotonicity
+
+
+// List should be in sync with JS_SIMPLE_BINOP_LIST.
+#define JSBINOP_LIST(V) \
+  V(Equal) \
+  V(NotEqual) \
+  V(StrictEqual) \
+  V(StrictNotEqual) \
+  V(LessThan) \
+  V(GreaterThan) \
+  V(LessThanOrEqual) \
+  V(GreaterThanOrEqual) \
+  V(BitwiseOr) \
+  V(BitwiseXor) \
+  V(BitwiseAnd) \
+  V(ShiftLeft) \
+  V(ShiftRight) \
+  V(ShiftRightLogical) \
+  V(Add) \
+  V(Subtract) \
+  V(Multiply) \
+  V(Divide) \
+  V(Modulus)
+
+
+#define TEST_FUNC(name)                             \
+  TEST(Monotonicity_##name) {                       \
+    TyperTester t;                                  \
+    t.TestBinaryMonotonicity(t.javascript_.name()); \
+  }
+JSBINOP_LIST(TEST_FUNC)
+#undef TEST_FUNC
diff --git a/test/cctest/compiler/value-helper.h b/test/cctest/compiler/value-helper.h
index b5da982..218a773 100644
--- a/test/cctest/compiler/value-helper.h
+++ b/test/cctest/compiler/value-helper.h
@@ -60,6 +60,45 @@
     CheckHeapConstant(isolate_->heap()->false_value(), node);
   }
 
+  static std::vector<float> float32_vector() {
+    static const float kValues[] = {
+        -std::numeric_limits<float>::infinity(), -2.70497e+38f, -1.4698e+37f,
+        -1.22813e+35f,                           -1.20555e+35f, -1.34584e+34f,
+        -1.0079e+32f,                            -6.49364e+26f, -3.06077e+25f,
+        -1.46821e+25f,                           -1.17658e+23f, -1.9617e+22f,
+        -2.7357e+20f,                            -1.48708e+13f, -1.89633e+12f,
+        -4.66622e+11f,                           -2.22581e+11f, -1.45381e+10f,
+        -1.3956e+09f,                            -1.32951e+09f, -1.30721e+09f,
+        -1.19756e+09f,                           -9.26822e+08f, -6.35647e+08f,
+        -4.00037e+08f,                           -1.81227e+08f, -5.09256e+07f,
+        -964300.0f,                              -192446.0f,    -28455.0f,
+        -27194.0f,                               -26401.0f,     -20575.0f,
+        -17069.0f,                               -9167.0f,      -960.178f,
+        -113.0f,                                 -62.0f,        -15.0f,
+        -7.0f,                                   -0.0256635f,   -4.60374e-07f,
+        -3.63759e-10f,                           -4.30175e-14f, -5.27385e-15f,
+        -1.48084e-15f,                           -1.05755e-19f, -3.2995e-21f,
+        -1.67354e-23f,                           -1.11885e-23f, -1.78506e-30f,
+        -5.07594e-31f,                           -3.65799e-31f, -1.43718e-34f,
+        -1.27126e-38f,                           -0.0f,         0.0f,
+        1.17549e-38f,                            1.56657e-37f,  4.08512e-29f,
+        3.31357e-28f,                            6.25073e-22f,  4.1723e-13f,
+        1.44343e-09f,                            5.27004e-08f,  9.48298e-08f,
+        5.57888e-07f,                            4.89988e-05f,  0.244326f,
+        12.4895f,                                19.0f,         47.0f,
+        106.0f,                                  538.324f,      564.536f,
+        819.124f,                                7048.0f,       12611.0f,
+        19878.0f,                                20309.0f,      797056.0f,
+        1.77219e+09f,                            1.51116e+11f,  4.18193e+13f,
+        3.59167e+16f,                            3.38211e+19f,  2.67488e+20f,
+        1.78831e+21f,                            9.20914e+21f,  8.35654e+23f,
+        1.4495e+24f,                             5.94015e+25f,  4.43608e+30f,
+        2.44502e+33f,                            2.61152e+33f,  1.38178e+37f,
+        1.71306e+37f,                            3.31899e+38f,  3.40282e+38f,
+        std::numeric_limits<float>::infinity()};
+    return std::vector<float>(&kValues[0], &kValues[arraysize(kValues)]);
+  }
+
   static std::vector<double> float64_vector() {
     static const double nan = v8::base::OS::nan_value();
     static const double values[] = {
@@ -82,6 +121,8 @@
   static const std::vector<uint32_t> uint32_vector() {
     static const uint32_t kValues[] = {
         0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
+        // This row is useful for testing lea optimizations on intel.
+        0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000008, 0x00000009,
         0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
         0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
         0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
@@ -117,6 +158,7 @@
 
 #define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var)
 #define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var)
+#define FOR_FLOAT32_INPUTS(var) FOR_INPUTS(float, float32, var)
 #define FOR_FLOAT64_INPUTS(var) FOR_INPUTS(double, float64, var)
 
 #define FOR_INT32_SHIFTS(var) for (int32_t var = 0; var < 32; var++)
diff --git a/test/cctest/test-accessors.cc b/test/cctest/test-accessors.cc
index 5bf61c8..5f452ea 100644
--- a/test/cctest/test-accessors.cc
+++ b/test/cctest/test-accessors.cc
@@ -38,6 +38,7 @@
 using ::v8::Value;
 using ::v8::Context;
 using ::v8::Local;
+using ::v8::Name;
 using ::v8::String;
 using ::v8::Script;
 using ::v8::Function;
@@ -513,7 +514,7 @@
 }
 
 
-void JSONStringifyGetter(Local<String> name,
+void JSONStringifyGetter(Local<Name> name,
                          const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_str("crbug-161028"));
 }
@@ -525,8 +526,8 @@
   v8::HandleScope scope(isolate);
 
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(
-      JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator));
   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
   CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected));
@@ -577,3 +578,30 @@
   CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
   CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());
 }
+
+
+static void EmptyGetter(Local<Name> name,
+                        const v8::PropertyCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+}
+
+
+static void OneProperty(Local<String> name,
+                        const v8::PropertyCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  info.GetReturnValue().Set(v8_num(1));
+}
+
+
+THREADED_TEST(Regress433458) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter));
+  obj->SetNativeDataProperty(v8_str("prop"), OneProperty);
+  env->Global()->Set(v8_str("obj"), obj->NewInstance());
+  CompileRun(
+      "Object.defineProperty(obj, 'prop', { writable: false });"
+      "Object.defineProperty(obj, 'prop', { writable: true });");
+}
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index d647a31..2e071ac 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -86,7 +86,7 @@
       Builtins::kIllegal)).ToObjectChecked();
 
   // Return success.
-  return Smi::FromInt(42);
+  return heap->true_value();
 }
 
 
@@ -100,7 +100,7 @@
   v8::Handle<v8::Context> env = v8::Context::New(CcTest::isolate());
   env->Enter();
   Handle<Object> o = Test();
-  CHECK(o->IsSmi() && Smi::cast(*o)->value() == 42);
+  CHECK(o->IsTrue());
   env->Exit();
 }
 
@@ -162,7 +162,7 @@
   // Call the accessor through JavaScript.
   v8::Handle<v8::Value> result = v8::Script::Compile(
       v8::String::NewFromUtf8(CcTest::isolate(), "(new Foo).get"))->Run();
-  CHECK_EQ(42, result->Int32Value());
+  CHECK_EQ(true, result->BooleanValue());
   env->Exit();
 }
 
@@ -198,7 +198,8 @@
   const size_t code_range_size = 32*MB;
   CcTest::InitializeVM();
   CodeRange code_range(reinterpret_cast<Isolate*>(CcTest::isolate()));
-  code_range.SetUp(code_range_size);
+  code_range.SetUp(code_range_size +
+                   kReservedCodeRangePages * v8::base::OS::CommitPageSize());
   size_t current_allocated = 0;
   size_t total_allocated = 0;
   List< ::Block> blocks(1000);
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 0e80384..06cf553 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -185,7 +185,8 @@
 }
 
 
-static void TestSignature(const char* loop_js, Local<Value> receiver) {
+static void TestSignature(const char* loop_js, Local<Value> receiver,
+                          v8::Isolate* isolate) {
   i::ScopedVector<char> source(200);
   i::SNPrintF(source,
               "for (var i = 0; i < 10; i++) {"
@@ -202,7 +203,7 @@
     CHECK_EQ(10, signature_callback_count);
   } else {
     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-             try_catch.Exception()->ToString());
+             try_catch.Exception()->ToString(isolate));
   }
 }
 
@@ -267,17 +268,17 @@
     i::SNPrintF(
         source, "var test_object = %s; test_object", test_objects[i]);
     Local<Value> test_object = CompileRun(source.start());
-    TestSignature("test_object.prop();", test_object);
-    TestSignature("test_object.accessor;", test_object);
-    TestSignature("test_object[accessor_key];", test_object);
-    TestSignature("test_object.accessor = 1;", test_object);
-    TestSignature("test_object[accessor_key] = 1;", test_object);
+    TestSignature("test_object.prop();", test_object, isolate);
+    TestSignature("test_object.accessor;", test_object, isolate);
+    TestSignature("test_object[accessor_key];", test_object, isolate);
+    TestSignature("test_object.accessor = 1;", test_object, isolate);
+    TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
     if (i >= bad_signature_start_offset) test_object = Local<Value>();
-    TestSignature("test_object.prop_sig();", test_object);
-    TestSignature("test_object.accessor_sig;", test_object);
-    TestSignature("test_object[accessor_sig_key];", test_object);
-    TestSignature("test_object.accessor_sig = 1;", test_object);
-    TestSignature("test_object[accessor_sig_key] = 1;", test_object);
+    TestSignature("test_object.prop_sig();", test_object, isolate);
+    TestSignature("test_object.accessor_sig;", test_object, isolate);
+    TestSignature("test_object[accessor_sig_key];", test_object, isolate);
+    TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
+    TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
   }
 }
 
@@ -356,7 +357,7 @@
   v8::Isolate* isolate = env->GetIsolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
-  Local<String> undef_str = undef->ToString();
+  Local<String> undef_str = undef->ToString(isolate);
   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
   undef_str->WriteUtf8(value);
   CHECK_EQ(0, strcmp(value, "undefined"));
@@ -742,6 +743,58 @@
 }
 
 
+class RandomLengthResource : public v8::String::ExternalStringResource {
+ public:
+  explicit RandomLengthResource(int length) : length_(length) {}
+  virtual const uint16_t* data() const { return string_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  uint16_t string_[10];
+  int length_;
+};
+
+
+class RandomLengthOneByteResource
+    : public v8::String::ExternalOneByteStringResource {
+ public:
+  explicit RandomLengthOneByteResource(int length) : length_(length) {}
+  virtual const char* data() const { return string_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  char string_[10];
+  int length_;
+};
+
+
+THREADED_TEST(NewExternalForVeryLongString) {
+  {
+    LocalContext env;
+    v8::HandleScope scope(env->GetIsolate());
+    v8::TryCatch try_catch;
+    RandomLengthOneByteResource r(1 << 30);
+    v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+    CHECK(str.IsEmpty());
+    CHECK(try_catch.HasCaught());
+    String::Utf8Value exception_value(try_catch.Exception());
+    CHECK_EQ("RangeError: Invalid string length", *exception_value);
+  }
+
+  {
+    LocalContext env;
+    v8::HandleScope scope(env->GetIsolate());
+    v8::TryCatch try_catch;
+    RandomLengthResource r(1 << 30);
+    v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+    CHECK(str.IsEmpty());
+    CHECK(try_catch.HasCaught());
+    String::Utf8Value exception_value(try_catch.Exception());
+    CHECK_EQ("RangeError: Invalid string length", *exception_value);
+  }
+}
+
+
 THREADED_TEST(ScavengeExternalString) {
   i::FLAG_stress_compaction = false;
   i::FLAG_gc_global = false;
@@ -934,7 +987,7 @@
   // If CPU profiler is active check that when API callback is invoked
   // VMState is set to EXTERNAL.
   if (isolate->cpu_profiler()->is_profiling()) {
-    CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
+    CHECK_EQ(v8::EXTERNAL, isolate->current_vm_state());
     CHECK(isolate->external_callback_scope());
     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
   }
@@ -1181,7 +1234,8 @@
 
 THREADED_PROFILED_TEST(FastReturnValues) {
   LocalContext env;
-  v8::HandleScope scope(CcTest::isolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   v8::Handle<v8::Value> value;
   // check int32_t and uint32_t
   int32_t int_values[] = {
@@ -1206,13 +1260,13 @@
   // check double
   value = TestFastReturnValues<double>();
   CHECK(value->IsNumber());
-  CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
+  CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
   // check bool values
   for (int i = 0; i < 2; i++) {
     fast_return_value_bool = i == 0;
     value = TestFastReturnValues<bool>();
     CHECK(value->IsBoolean());
-    CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
+    CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
   }
   // check oddballs
   ReturnValueOddball oddballs[] = {
@@ -1542,6 +1596,34 @@
 }
 
 
+THREADED_TEST(IsGeneratorFunctionOrObject) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  CompileRun("function *gen() { yield 1; }\nfunction func() {}");
+  v8::Handle<Value> gen = CompileRun("gen");
+  v8::Handle<Value> genObj = CompileRun("gen()");
+  v8::Handle<Value> object = CompileRun("{a:42}");
+  v8::Handle<Value> func = CompileRun("func");
+
+  CHECK(gen->IsGeneratorFunction());
+  CHECK(gen->IsFunction());
+  CHECK(!gen->IsGeneratorObject());
+
+  CHECK(!genObj->IsGeneratorFunction());
+  CHECK(!genObj->IsFunction());
+  CHECK(genObj->IsGeneratorObject());
+
+  CHECK(!object->IsGeneratorFunction());
+  CHECK(!object->IsFunction());
+  CHECK(!object->IsGeneratorObject());
+
+  CHECK(!func->IsGeneratorFunction());
+  CHECK(func->IsFunction());
+  CHECK(!func->IsGeneratorObject());
+}
+
+
 THREADED_TEST(ArgumentsObject) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
@@ -1904,7 +1986,7 @@
 int echo_named_call_count;
 
 
-static void EchoNamedProperty(Local<String> name,
+static void EchoNamedProperty(Local<Name> name,
                               const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK_EQ(v8_str("data"), info.Data());
@@ -1946,18 +2028,41 @@
   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
 }
 
-void EmptyInterceptorGetter(Local<String> name,
-                            const v8::PropertyCallbackInfo<v8::Value>& info) {
+void SymbolAccessorGetterReturnsDefault(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  CHECK(name->IsSymbol());
+  Local<Symbol> sym = Local<Symbol>::Cast(name);
+  if (sym->Name()->IsUndefined()) return;
+  info.GetReturnValue().Set(info.Data());
 }
 
-void EmptyInterceptorSetter(Local<String> name,
-                            Local<Value> value,
-                            const v8::PropertyCallbackInfo<v8::Value>& info) {
+static void ThrowingSymbolAccessorGetter(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
 }
 
-void InterceptorGetter(Local<String> name,
-                       const v8::PropertyCallbackInfo<v8::Value>& info) {
-  // Intercept names that start with 'interceptor_'.
+
+void EmptyInterceptorGetter(Local<Name> name,
+                            const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
+                            const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyGenericInterceptorGetter(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyGenericInterceptorSetter(
+    Local<Name> name, Local<Value> value,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void StringInterceptorGetter(
+    Local<String> name,
+    const v8::PropertyCallbackInfo<v8::Value>&
+        info) {  // Intercept names that start with 'interceptor_'.
   String::Utf8Value utf8(name);
   char* name_str = *utf8;
   char prefix[] = "interceptor_";
@@ -1969,9 +2074,9 @@
   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
 }
 
-void InterceptorSetter(Local<String> name,
-                       Local<Value> value,
-                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+
+void StringInterceptorSetter(Local<String> name, Local<Value> value,
+                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   // Intercept accesses that set certain integer values, for which the name does
   // not start with 'accessor_'.
   String::Utf8Value utf8(name);
@@ -1990,6 +2095,57 @@
   }
 }
 
+void InterceptorGetter(Local<Name> generic_name,
+                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+  if (generic_name->IsSymbol()) return;
+  StringInterceptorGetter(Local<String>::Cast(generic_name), info);
+}
+
+void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
+                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+  if (generic_name->IsSymbol()) return;
+  StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
+}
+
+void GenericInterceptorGetter(Local<Name> generic_name,
+                              const v8::PropertyCallbackInfo<v8::Value>& info) {
+  Local<String> str;
+  if (generic_name->IsSymbol()) {
+    Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
+    if (name->IsUndefined()) return;
+    str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
+  } else {
+    Local<String> name = Local<String>::Cast(generic_name);
+    String::Utf8Value utf8(name);
+    char* name_str = *utf8;
+    if (*name_str == '_') return;
+    str = String::Concat(v8_str("_str_"), name);
+  }
+
+  Handle<Object> self = Handle<Object>::Cast(info.This());
+  info.GetReturnValue().Set(self->Get(str));
+}
+
+void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
+                              const v8::PropertyCallbackInfo<v8::Value>& info) {
+  Local<String> str;
+  if (generic_name->IsSymbol()) {
+    Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
+    if (name->IsUndefined()) return;
+    str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
+  } else {
+    Local<String> name = Local<String>::Cast(generic_name);
+    String::Utf8Value utf8(name);
+    char* name_str = *utf8;
+    if (*name_str == '_') return;
+    str = String::Concat(v8_str("_str_"), name);
+  }
+
+  Handle<Object> self = Handle<Object>::Cast(info.This());
+  self->Set(str, value);
+  info.GetReturnValue().Set(value);
+}
+
 void AddAccessor(Handle<FunctionTemplate> templ,
                  Handle<String> name,
                  v8::AccessorGetterCallback getter,
@@ -2011,6 +2167,13 @@
   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
 }
 
+void AddInterceptor(Handle<FunctionTemplate> templ,
+                    v8::GenericNamedPropertyGetterCallback getter,
+                    v8::GenericNamedPropertySetterCallback setter) {
+  templ->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(getter, setter));
+}
+
 
 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
   v8::HandleScope scope(CcTest::isolate());
@@ -2030,6 +2193,62 @@
 }
 
 
+THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
+  LocalContext env;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
+  Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
+  v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
+
+  child->Inherit(parent);
+  AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
+  AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
+
+  env->Global()->Set(v8_str("Child"), child->GetFunction());
+  env->Global()->Set(v8_str("age"), age);
+  CompileRun(
+      "var child = new Child;"
+      "child[age] = 10;");
+  ExpectInt32("child[age]", 10);
+  ExpectBoolean("child.hasOwnProperty('age')", false);
+  ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
+}
+
+
+THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
+  LocalContext env;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
+  Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
+  v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
+  v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
+
+  child->Inherit(parent);
+  AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
+  AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
+
+  env->Global()->Set(v8_str("Child"), child->GetFunction());
+  env->Global()->Set(v8_str("age"), age);
+  env->Global()->Set(v8_str("anon"), anon);
+  CompileRun(
+      "var child = new Child;"
+      "child[age] = 10;");
+  ExpectInt32("child[age]", 10);
+  ExpectInt32("child._sym_age", 10);
+
+  // Check that it also sees strings.
+  CompileRun("child.foo = 47");
+  ExpectInt32("child.foo", 47);
+  ExpectInt32("child._str_foo", 47);
+
+  // Check that the interceptor can punt (in this case, on anonymous symbols).
+  CompileRun("child[anon] = 31337");
+  ExpectInt32("child[anon]", 31337);
+}
+
+
 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
@@ -2275,9 +2494,8 @@
   v8::HandleScope scope(CcTest::isolate());
   v8::Handle<v8::FunctionTemplate> templ =
       v8::FunctionTemplate::New(CcTest::isolate());
-  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
-                                                     0, 0, 0, 0,
-                                                     v8_str("data"));
+  templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -2312,9 +2530,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
-                                                       0, 0, 0, 0,
-                                                       v8_num(637));
+  templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -2334,8 +2551,7 @@
 }
 
 static void CheckThisNamedPropertyHandler(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2352,8 +2568,7 @@
 
 
 void CheckThisNamedPropertySetter(
-    Local<String> property,
-    Local<Value> value,
+    Local<Name> property, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
   ApiTestFuzzer::Fuzz();
@@ -2370,8 +2585,7 @@
 
 
 void CheckThisNamedPropertyQuery(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2388,8 +2602,7 @@
 
 
 void CheckThisNamedPropertyDeleter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2419,19 +2632,15 @@
 
   // Set up a prototype chain with three interceptors.
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetIndexedPropertyHandler(
-      CheckThisIndexedPropertyHandler,
-      CheckThisIndexedPropertySetter,
-      CheckThisIndexedPropertyQuery,
-      CheckThisIndexedPropertyDeleter,
-      CheckThisIndexedPropertyEnumerator);
+  templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
+      CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
+      CheckThisIndexedPropertyEnumerator));
 
-  templ->InstanceTemplate()->SetNamedPropertyHandler(
-      CheckThisNamedPropertyHandler,
-      CheckThisNamedPropertySetter,
-      CheckThisNamedPropertyQuery,
-      CheckThisNamedPropertyDeleter,
-      CheckThisNamedPropertyEnumerator);
+  templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
+      CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
+      CheckThisNamedPropertyEnumerator));
 
   bottom = templ->GetFunction()->NewInstance();
   Local<v8::Object> top = templ->GetFunction()->NewInstance();
@@ -2463,8 +2672,7 @@
 
 
 static void PrePropertyHandlerGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("pre")->Equals(key)) {
     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
@@ -2473,8 +2681,7 @@
 
 
 static void PrePropertyHandlerQuery(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (v8_str("pre")->Equals(key)) {
     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
   }
@@ -2485,9 +2692,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
-  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
-                                                    0,
-                                                    PrePropertyHandlerQuery);
+  desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
   LocalContext env(NULL, desc->InstanceTemplate());
   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
   v8::Handle<Value> result_pre = CompileRun("pre");
@@ -2560,16 +2766,17 @@
 
 
 static void ThrowingPropertyHandlerGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  // Since this interceptor is used on "with" objects, the runtime will look up
+  // @@unscopables.  Punt.
+  if (key->IsSymbol()) return;
   ApiTestFuzzer::Fuzz();
   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
 }
 
 
 static void ThrowingPropertyHandlerSet(
-    Local<String> key,
-    Local<Value>,
+    Local<Name> key, Local<Value>,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetIsolate()->ThrowException(key);
   info.GetReturnValue().SetUndefined();  // not the same as empty handle
@@ -2580,8 +2787,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
-                               ThrowingPropertyHandlerSet);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
   LocalContext env;
   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   v8::Handle<Value> otto = CompileRun(
@@ -2749,6 +2956,16 @@
 }
 
 
+THREADED_TEST(GetIsolate) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  Local<v8::Object> obj = v8::Object::New(isolate);
+  CHECK_EQ(isolate, obj->GetIsolate());
+  CHECK_EQ(isolate, CcTest::global()->GetIsolate());
+}
+
+
 THREADED_TEST(IdentityHash) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
@@ -2813,6 +3030,53 @@
 }
 
 
+TEST(SymbolIdentityHash) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  {
+    Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
+    int hash = symbol->GetIdentityHash();
+    int hash1 = symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash1);
+    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+    int hash3 = symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash3);
+  }
+
+  {
+    v8::Handle<v8::Symbol> js_symbol =
+        CompileRun("Symbol('foo')").As<v8::Symbol>();
+    int hash = js_symbol->GetIdentityHash();
+    int hash1 = js_symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash1);
+    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+    int hash3 = js_symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash3);
+  }
+}
+
+
+TEST(StringIdentityHash) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
+  int hash = str->GetIdentityHash();
+  int hash1 = str->GetIdentityHash();
+  CHECK_EQ(hash, hash1);
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+  int hash3 = str->GetIdentityHash();
+  CHECK_EQ(hash, hash3);
+
+  Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
+  int hash4 = str2->GetIdentityHash();
+  CHECK_EQ(hash, hash4);
+}
+
+
 THREADED_TEST(SymbolProperties) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
@@ -3195,6 +3459,24 @@
 }
 
 
+THREADED_TEST(ArrayBuffer_DisableNeuter) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  i::ScopedVector<uint8_t> my_data(100);
+  memset(my_data.start(), 0, 100);
+  Local<v8::ArrayBuffer> ab =
+      v8::ArrayBuffer::New(isolate, my_data.start(), 100);
+  CHECK(ab->IsNeuterable());
+
+  i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
+  buf->set_is_neuterable(false);
+
+  CHECK(!ab->IsNeuterable());
+}
+
+
 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
@@ -3411,7 +3693,7 @@
 
 static bool interceptor_for_hidden_properties_called;
 static void InterceptorForHiddenProperties(
-    Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   interceptor_for_hidden_properties_called = true;
 }
 
@@ -3428,7 +3710,8 @@
   // Associate an interceptor with an object and start setting hidden values.
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
   Local<v8::Function> function = fun_templ->GetFunction();
   Local<v8::Object> obj = function->NewInstance();
   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
@@ -4144,6 +4427,45 @@
 }
 
 
+THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
+  LocalContext env;
+  v8::Isolate* iso = env->GetIsolate();
+  HandleScope scope(iso);
+
+  WeakCallCounter counter(1234);
+
+  WeakCallCounterAndPersistent<Value> weak_obj(&counter);
+
+  // Create a weak object that references a internalized string.
+  {
+    HandleScope scope(iso);
+    weak_obj.handle.Reset(iso, Object::New(iso));
+    weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
+    CHECK(weak_obj.handle.IsWeak());
+    Local<Object>::New(iso, weak_obj.handle.As<Object>())->Set(
+        v8_str("x"),
+        String::NewFromUtf8(iso, "magic cookie", String::kInternalizedString));
+  }
+  // Do a single full GC
+  i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
+  i::Heap* heap = i_iso->heap();
+  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+
+  // We should have received the weak callback.
+  CHECK_EQ(1, counter.NumberOfWeakCalls());
+
+  // Check that the string is still alive.
+  {
+    HandleScope scope(iso);
+    i::MaybeHandle<i::String> magic_string =
+        i::StringTable::LookupStringIfExists(
+            i_iso,
+            v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
+    magic_string.Check();
+  }
+}
+
+
 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
 // on the buildbots, so was made non-threaded for the time being.
 TEST(ApiObjectGroupsCycleForScavenger) {
@@ -4266,13 +4588,14 @@
 
 TEST(TryCatchCustomException) {
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   v8::TryCatch try_catch;
   CompileRun("function CustomError() { this.a = 'b'; }"
              "(function f() { throw new CustomError(); })();");
   CHECK(try_catch.HasCaught());
-  CHECK(try_catch.Exception()->ToObject()->
-            Get(v8_str("a"))->Equals(v8_str("b")));
+  CHECK(try_catch.Exception()->ToObject(isolate)->Get(v8_str("a"))->Equals(
+      v8_str("b")));
 }
 
 
@@ -4766,49 +5089,51 @@
 
 THREADED_TEST(ConversionNumber) {
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   // Very large number.
   CompileRun("var obj = Math.pow(2,32) * 1237;");
   Local<Value> obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
-  CHECK_EQ(0, obj->ToInt32()->Value());
-  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
+  CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(0, obj->ToInt32(isolate)->Value());
+  CHECK(0u ==
+        obj->ToUint32(isolate)->Value());  // NOLINT - no CHECK_EQ for unsigned.
   // Large number.
   CompileRun("var obj = -1234567890123;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
-  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
-  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
+  CHECK(2382691125u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Small positive integer.
   CompileRun("var obj = 42;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(42.0, obj->ToNumber()->Value());
-  CHECK_EQ(42, obj->ToInt32()->Value());
-  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(42, obj->ToInt32(isolate)->Value());
+  CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Negative integer.
   CompileRun("var obj = -37;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-37.0, obj->ToNumber()->Value());
-  CHECK_EQ(-37, obj->ToInt32()->Value());
-  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
+  CHECK(4294967259u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Positive non-int32 integer.
   CompileRun("var obj = 0x81234567;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
-  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
-  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
+  CHECK(2166572391u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Fraction.
   CompileRun("var obj = 42.3;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(42.3, obj->ToNumber()->Value());
-  CHECK_EQ(42, obj->ToInt32()->Value());
-  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(42, obj->ToInt32(isolate)->Value());
+  CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Large negative fraction.
   CompileRun("var obj = -5726623061.75;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
-  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
-  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
+  CHECK(2863311531u == obj->ToUint32(isolate)->Value());  // NOLINT
 }
 
 
@@ -4873,29 +5198,29 @@
     "var obj = new TestClass();");
   Local<Value> obj = env->Global()->Get(v8_str("obj"));
 
-  v8::TryCatch try_catch;
+  v8::TryCatch try_catch(isolate);
 
-  Local<Value> to_string_result = obj->ToString();
+  Local<Value> to_string_result = obj->ToString(isolate);
   CHECK(to_string_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_number_result = obj->ToNumber();
+  Local<Value> to_number_result = obj->ToNumber(isolate);
   CHECK(to_number_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_integer_result = obj->ToInteger();
+  Local<Value> to_integer_result = obj->ToInteger(isolate);
   CHECK(to_integer_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_uint32_result = obj->ToUint32();
+  Local<Value> to_uint32_result = obj->ToUint32(isolate);
   CHECK(to_uint32_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_int32_result = obj->ToInt32();
+  Local<Value> to_int32_result = obj->ToInt32(isolate);
   CHECK(to_int32_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
+  Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
   CHECK(to_object_result.IsEmpty());
   CHECK(try_catch.HasCaught());
   try_catch.Reset();
@@ -4931,7 +5256,7 @@
   }
   v8::HandleScope scope(args.GetIsolate());
   v8::TryCatch try_catch;
-  Local<Value> result = CompileRun(args[0]->ToString());
+  Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
   CHECK(!try_catch.HasCaught() || result.IsEmpty());
   args.GetReturnValue().Set(try_catch.HasCaught());
 }
@@ -5980,7 +6305,7 @@
 }
 
 
-static void XPropertyGetter(Local<String> property,
+static void XPropertyGetter(Local<Name> property,
                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(info.Data()->IsUndefined());
@@ -5992,7 +6317,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> script = v8_compile("obj.x");
@@ -6007,7 +6332,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   LocalContext context;
   // Create an object with a named interceptor.
   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
@@ -6041,7 +6366,7 @@
 
   context1->Enter();
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   // Create an object with a named interceptor.
   v8::Local<v8::Object> object = templ->NewInstance();
   context1->Global()->Set(v8_str("interceptor_obj"), object);
@@ -6076,8 +6401,7 @@
 
 
 static void SetXOnPrototypeGetter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
   // Set x on the prototype object and do not handle the get request.
   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
   proto.As<v8::Object>()->Set(v8_str("x"),
@@ -6094,7 +6418,8 @@
       v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_template
       = function_template->InstanceTemplate();
-  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
+  instance_template->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
   LocalContext context;
   context->Global()->Set(v8_str("F"), function_template->GetFunction());
   // Create an instance of F and introduce a map transition for x.
@@ -6130,8 +6455,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
-                                   IndexedPropertySetter);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedPropertyGetter, IndexedPropertySetter));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> getter_script = v8_compile(
@@ -6196,11 +6521,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
-                                   UnboxedDoubleIndexedPropertySetter,
-                                   0,
-                                   0,
-                                   UnboxedDoubleIndexedPropertyEnumerator);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
+      0, UnboxedDoubleIndexedPropertyEnumerator));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   // When obj is created, force it to be Stored in a FastDoubleArray.
@@ -6210,7 +6533,7 @@
       "for (x in obj) {key_count++;};"
       "obj;");
   Local<Value> result = create_unboxed_double_script->Run();
-  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
+  CHECK(result->ToObject(isolate)->HasRealIndexedProperty(2000));
   Local<Script> key_count_check = v8_compile("key_count;");
   result = key_count_check->Run();
   CHECK_EQ(v8_num(40013), result);
@@ -6252,11 +6575,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
-                                   0,
-                                   0,
-                                   0,
-                                   SloppyArgsIndexedPropertyEnumerator);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      SloppyIndexedPropertyGetter, 0, 0, 0,
+      SloppyArgsIndexedPropertyEnumerator));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> create_args_script = v8_compile(
@@ -6278,7 +6599,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
@@ -6300,7 +6622,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
@@ -6324,7 +6647,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6352,7 +6676,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6390,7 +6715,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6414,7 +6740,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6454,7 +6781,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6484,7 +6812,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6515,7 +6844,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6546,7 +6876,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -7371,14 +7702,175 @@
 };
 
 
-static void DisposeAndSetFlag(
-    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
-  data.GetParameter()->handle.Reset();
+static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
   data.GetParameter()->flag = true;
 }
 
 
+static void IndependentWeakHandle(bool global_gc, bool interlinked) {
+  v8::Isolate* iso = CcTest::isolate();
+  v8::HandleScope scope(iso);
+  v8::Handle<Context> context = Context::New(iso);
+  Context::Scope context_scope(context);
+
+  FlagAndPersistent object_a, object_b;
+
+  intptr_t big_heap_size;
+
+  {
+    v8::HandleScope handle_scope(iso);
+    Local<Object> a(v8::Object::New(iso));
+    Local<Object> b(v8::Object::New(iso));
+    object_a.handle.Reset(iso, a);
+    object_b.handle.Reset(iso, b);
+    if (interlinked) {
+      a->Set(v8_str("x"), b);
+      b->Set(v8_str("x"), a);
+    }
+    if (global_gc) {
+      CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+    } else {
+      CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+    }
+    // We are relying on this creating a big flag array and reserving the space
+    // up front.
+    v8::Handle<Value> big_array = CompileRun("new Array(50000)");
+    a->Set(v8_str("y"), big_array);
+    big_heap_size = CcTest::heap()->SizeOfObjects();
+  }
+
+  object_a.flag = false;
+  object_b.flag = false;
+  object_a.handle.SetPhantom(&object_a, &SetFlag);
+  object_b.handle.SetPhantom(&object_b, &SetFlag);
+  CHECK(!object_b.handle.IsIndependent());
+  object_a.handle.MarkIndependent();
+  object_b.handle.MarkIndependent();
+  CHECK(object_b.handle.IsIndependent());
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
+  // A single GC should be enough to reclaim the memory, since we are using
+  // phantom handles.
+  CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
+  CHECK(object_a.flag);
+  CHECK(object_b.flag);
+}
+
+
 THREADED_TEST(IndependentWeakHandle) {
+  IndependentWeakHandle(false, false);
+  IndependentWeakHandle(false, true);
+  IndependentWeakHandle(true, false);
+  IndependentWeakHandle(true, true);
+}
+
+
+class Trivial {
+ public:
+  explicit Trivial(int x) : x_(x) {}
+
+  int x() { return x_; }
+  void set_x(int x) { x_ = x; }
+
+ private:
+  int x_;
+};
+
+
+class Trivial2 {
+ public:
+  Trivial2(int x, int y) : y_(y), x_(x) {}
+
+  int x() { return x_; }
+  void set_x(int x) { x_ = x; }
+
+  int y() { return y_; }
+  void set_y(int y) { y_ = y; }
+
+ private:
+  int y_;
+  int x_;
+};
+
+
+void CheckInternalFields(
+    const v8::InternalFieldsCallbackData<Trivial, Trivial2>& data) {
+  Trivial* t1 = data.GetInternalField1();
+  Trivial2* t2 = data.GetInternalField2();
+  CHECK_EQ(42, t1->x());
+  CHECK_EQ(103, t2->x());
+  t1->set_x(1729);
+  t2->set_x(33550336);
+}
+
+
+void InternalFieldCallback(bool global_gc) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
+  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
+  Trivial* t1;
+  Trivial2* t2;
+  instance_templ->SetInternalFieldCount(2);
+  {
+    v8::HandleScope scope(isolate);
+    Local<v8::Object> obj = templ->GetFunction()->NewInstance();
+    v8::Persistent<v8::Object> handle(isolate, obj);
+    CHECK_EQ(2, obj->InternalFieldCount());
+    CHECK(obj->GetInternalField(0)->IsUndefined());
+    t1 = new Trivial(42);
+    t2 = new Trivial2(103, 9);
+
+    obj->SetAlignedPointerInInternalField(0, t1);
+    t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
+    CHECK_EQ(42, t1->x());
+
+    obj->SetAlignedPointerInInternalField(1, t2);
+    t2 =
+        reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
+    CHECK_EQ(103, t2->x());
+
+    handle.SetPhantom(CheckInternalFields, 0, 1);
+    if (!global_gc) {
+      handle.MarkIndependent();
+    }
+  }
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
+
+  CHECK_EQ(1729, t1->x());
+  CHECK_EQ(33550336, t2->x());
+
+  delete t1;
+  delete t2;
+}
+
+
+THREADED_TEST(InternalFieldCallback) {
+  InternalFieldCallback(false);
+  InternalFieldCallback(true);
+}
+
+
+static void ResetUseValueAndSetFlag(
+    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
+  // Blink will reset the handle, and then use the other handle, so they
+  // can't use the same backing slot.
+  data.GetParameter()->handle.Reset();
+  data.GetValue()->IsBoolean();  // Make sure the handle still works.
+  data.GetParameter()->flag = true;
+}
+
+
+static void ResetWeakHandle(bool global_gc) {
   v8::Isolate* iso = CcTest::isolate();
   v8::HandleScope scope(iso);
   v8::Handle<Context> context = Context::New(iso);
@@ -7388,24 +7880,44 @@
 
   {
     v8::HandleScope handle_scope(iso);
-    object_a.handle.Reset(iso, v8::Object::New(iso));
-    object_b.handle.Reset(iso, v8::Object::New(iso));
+    Local<Object> a(v8::Object::New(iso));
+    Local<Object> b(v8::Object::New(iso));
+    object_a.handle.Reset(iso, a);
+    object_b.handle.Reset(iso, b);
+    if (global_gc) {
+      CcTest::heap()->CollectAllGarbage(
+          TestHeap::Heap::kAbortIncrementalMarkingMask);
+    } else {
+      CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+    }
   }
 
   object_a.flag = false;
   object_b.flag = false;
-  object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
-  object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
-  CHECK(!object_b.handle.IsIndependent());
-  object_a.handle.MarkIndependent();
-  object_b.handle.MarkIndependent();
-  CHECK(object_b.handle.IsIndependent());
-  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
+  object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
+  if (!global_gc) {
+    object_a.handle.MarkIndependent();
+    object_b.handle.MarkIndependent();
+    CHECK(object_b.handle.IsIndependent());
+  }
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(
+        TestHeap::Heap::kAbortIncrementalMarkingMask);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
   CHECK(object_a.flag);
   CHECK(object_b.flag);
 }
 
 
+THREADED_TEST(ResetWeakHandle) {
+  ResetWeakHandle(false);
+  ResetWeakHandle(true);
+}
+
+
 static void InvokeScavenge() {
   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
 }
@@ -7533,9 +8045,8 @@
 }
 
 
-static void NoBlockGetterX(Local<String> name,
-                           const v8::PropertyCallbackInfo<v8::Value>&) {
-}
+static void NoBlockGetterX(Local<Name> name,
+                           const v8::PropertyCallbackInfo<v8::Value>&) {}
 
 
 static void NoBlockGetterI(uint32_t index,
@@ -7543,7 +8054,7 @@
 }
 
 
-static void PDeleter(Local<String> name,
+static void PDeleter(Local<Name> name,
                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   if (!name->Equals(v8_str("foo"))) {
     return;  // not intercepted
@@ -7567,8 +8078,10 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
-  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
+                                                        NULL, PDeleter, NULL));
+  obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NoBlockGetterI, NULL, NULL, IDeleter, NULL));
   LocalContext context;
   context->Global()->Set(v8_str("k"), obj->NewInstance());
   CompileRun(
@@ -7590,7 +8103,7 @@
 }
 
 
-static void GetK(Local<String> name,
+static void GetK(Local<Name> name,
                  const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (name->Equals(v8_str("foo")) ||
@@ -7631,8 +8144,10 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
-  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
+  obj->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
+  obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetK, NULL, NULL, NULL, IndexedEnum));
   LocalContext context;
   context->Global()->Set(v8_str("k"), obj->NewInstance());
   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
@@ -7724,7 +8239,7 @@
 }
 
 
-static void PGetter2(Local<String> name,
+static void PGetter2(Local<Name> name,
                      const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   p_getter_count2++;
@@ -7761,7 +8276,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(PGetter2);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
   p_getter_count2 = 0;
   RunHolderTest(obj);
   CHECK_EQ(40, p_getter_count2);
@@ -8419,6 +8934,85 @@
 }
 
 
+static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  v8::Handle<String> foo = v8_str("foo");
+  v8::Handle<String> message = v8_str("message");
+  v8::Handle<Value> error = v8::Exception::Error(foo);
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
+  info.GetIsolate()->ThrowException(error);
+  info.GetReturnValue().SetUndefined();
+}
+
+
+THREADED_TEST(ExceptionCreateMessage) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  v8::Handle<String> foo_str = v8_str("foo");
+  v8::Handle<String> message_str = v8_str("message");
+
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+
+  Local<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
+  v8::Local<v8::Object> global = context->Global();
+  global->Set(v8_str("throwV8Exception"), fun->GetFunction());
+
+  TryCatch try_catch;
+  CompileRun(
+      "function f1() {\n"
+      "  throwV8Exception();\n"
+      "};\n"
+      "f1();");
+  CHECK(try_catch.HasCaught());
+
+  v8::Handle<v8::Value> error = try_catch.Exception();
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
+
+  v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
+  CHECK(!message.IsEmpty());
+  CHECK_EQ(2, message->GetLineNumber());
+  CHECK_EQ(2, message->GetStartColumn());
+
+  v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
+  CHECK(!stackTrace.IsEmpty());
+  CHECK_EQ(2, stackTrace->GetFrameCount());
+
+  stackTrace = v8::Exception::GetStackTrace(error);
+  CHECK(!stackTrace.IsEmpty());
+  CHECK_EQ(2, stackTrace->GetFrameCount());
+
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+
+  // Now check message location when SetCaptureStackTraceForUncaughtExceptions
+  // is false.
+  try_catch.Reset();
+
+  CompileRun(
+      "function f2() {\n"
+      "  return throwV8Exception();\n"
+      "};\n"
+      "f2();");
+  CHECK(try_catch.HasCaught());
+
+  error = try_catch.Exception();
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
+
+  message = v8::Exception::CreateMessage(error);
+  CHECK(!message.IsEmpty());
+  CHECK_EQ(2, message->GetLineNumber());
+  CHECK_EQ(9, message->GetStartColumn());
+
+  // Should be empty stack trace.
+  stackTrace = message->GetStackTrace();
+  CHECK(stackTrace.IsEmpty());
+  CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
+}
+
+
 static void YGetter(Local<String> name,
                     const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
@@ -8532,6 +9126,33 @@
   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
 }
 
+
+TEST(ApiUncaughtExceptionInObjectObserve) {
+  v8::internal::FLAG_stack_size = 150;
+  report_count = 0;
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
+  CompileRun(
+      "var obj = {};"
+      "var observe_count = 0;"
+      "function observer1() { ++observe_count; };"
+      "function observer2() { ++observe_count; };"
+      "function observer_throws() { throw new Error(); };"
+      "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, stack_overflow);"
+      "Object.observe(obj, observer2);"
+      "Object.observe(obj, observer_throws.bind());"
+      "obj.foo = 'bar';");
+  CHECK_EQ(3, report_count);
+  ExpectInt32("observe_count", 2);
+  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
+}
+
+
 static const char* script_resource_name = "ExceptionInNativeScript.js";
 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
                                                 v8::Handle<Value>) {
@@ -8603,7 +9224,7 @@
 
 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
-  CompileRun(args[0]->ToString());
+  CompileRun(args[0]->ToString(args.GetIsolate()));
 }
 
 
@@ -8877,11 +9498,11 @@
   CHECK(indexed_security_check_with_gc_called);
 
   named_security_check_with_gc_called = false;
-  CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
+  CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
   CHECK(named_security_check_with_gc_called);
 
   indexed_security_check_with_gc_called = false;
-  CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
+  CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
   CHECK(indexed_security_check_with_gc_called);
 }
 
@@ -9609,20 +10230,52 @@
   LocalContext env;
   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
 
-  v8::TryCatch try_catch;
-  CompileRun(
-      "function f() { return super.hasOwnProperty; };"
-      "var m = f.toMethod(prohibited);"
-      "m();");
-  CHECK(try_catch.HasCaught());
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { return super.hasOwnProperty; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { return super[42]; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { super.hasOwnProperty = function () {}; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
+        "function f() { "
+        "     'use strict';"
+        "     super.x = function () {}; "
+        "};"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
 }
 
 
 static void IndexedPropertyEnumerator(
     const v8::PropertyCallbackInfo<v8::Array>& info) {
-  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
+  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
-  result->Set(1, v8::Object::New(info.GetIsolate()));
   info.GetReturnValue().Set(result);
 }
 
@@ -9631,7 +10284,7 @@
     const v8::PropertyCallbackInfo<v8::Array>& info) {
   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
   result->Set(0, v8_str("x"));
-  result->Set(1, v8::Object::New(info.GetIsolate()));
+  result->Set(1, v8::Symbol::GetIterator(info.GetIsolate()));
   info.GetReturnValue().Set(result);
 }
 
@@ -9644,10 +10297,10 @@
 
   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
-  obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
-                                          IndexedPropertyEnumerator);
-  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
-                                        NamedPropertyEnumerator);
+  obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
+  obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
 
   LocalContext context;
   v8::Handle<v8::Object> global = context->Global();
@@ -9657,13 +10310,26 @@
       CompileRun("Object.getOwnPropertyNames(object)");
   CHECK(result->IsArray());
   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
-  CHECK_EQ(3, result_array->Length());
+  CHECK_EQ(2, result_array->Length());
   CHECK(result_array->Get(0)->IsString());
   CHECK(result_array->Get(1)->IsString());
-  CHECK(result_array->Get(2)->IsString());
   CHECK_EQ(v8_str("7"), result_array->Get(0));
-  CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
-  CHECK_EQ(v8_str("x"), result_array->Get(2));
+  CHECK_EQ(v8_str("x"), result_array->Get(1));
+
+  result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
+  CHECK(result->IsArray());
+  result_array = v8::Handle<v8::Array>::Cast(result);
+  CHECK_EQ(2, result_array->Length());
+  CHECK(result_array->Get(0)->IsString());
+  CHECK(result_array->Get(1)->IsString());
+  CHECK_EQ(v8_str("7"), result_array->Get(0));
+  CHECK_EQ(v8_str("x"), result_array->Get(1));
+
+  result = CompileRun("Object.getOwnPropertySymbols(object)");
+  CHECK(result->IsArray());
+  result_array = v8::Handle<v8::Array>::Cast(result);
+  CHECK_EQ(1, result_array->Length());
+  CHECK_EQ(result_array->Get(0), v8::Symbol::GetIterator(isolate));
 }
 
 
@@ -9937,15 +10603,13 @@
 
 
 static void AccessControlNamedGetter(
-    Local<String>,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(42);
 }
 
 
 static void AccessControlNamedSetter(
-    Local<String>,
-    Local<Value> value,
+    Local<Name>, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(value);
 }
@@ -9984,10 +10648,10 @@
       v8::ObjectTemplate::New(isolate);
   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
                                            IndexedAccessCounter);
-  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
-                                           AccessControlNamedSetter);
-  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
-                                             AccessControlIndexedSetter);
+  object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      AccessControlNamedGetter, AccessControlNamedSetter));
+  object_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      AccessControlIndexedGetter, AccessControlIndexedSetter));
   Local<v8::Object> object = object_template->NewInstance();
 
   v8::HandleScope scope1(isolate);
@@ -10069,8 +10733,7 @@
 
 
 static void GlobalObjectInstancePropertiesGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>&) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
   ApiTestFuzzer::Fuzz();
 }
 
@@ -10082,8 +10745,8 @@
   Local<Value> global_object;
 
   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
-  t->InstanceTemplate()->SetNamedPropertyHandler(
-      GlobalObjectInstancePropertiesGet);
+  t->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   instance_template->Set(v8_str("x"), v8_num(42));
   instance_template->Set(v8_str("f"),
@@ -10207,9 +10870,8 @@
 }
 
 
-static void ShadowNamedGet(Local<String> key,
-                           const v8::PropertyCallbackInfo<v8::Value>&) {
-}
+static void ShadowNamedGet(Local<Name> key,
+                           const v8::PropertyCallbackInfo<v8::Value>&) {}
 
 
 THREADED_TEST(ShadowObject) {
@@ -10221,8 +10883,10 @@
   LocalContext context(NULL, global_template);
 
   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
-  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
-  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
+  t->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
+  t->InstanceTemplate()->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
   Local<ObjectTemplate> proto = t->PrototypeTemplate();
   Local<ObjectTemplate> instance = t->InstanceTemplate();
 
@@ -10709,7 +11373,7 @@
         "(function() { var o = new obj('tipli'); return o.a; })()");
     CHECK(!try_catch.HasCaught());
     CHECK(value->IsString());
-    String::Utf8Value string_value1(value->ToString());
+    String::Utf8Value string_value1(value->ToString(isolate));
     CHECK_EQ("tipli", *string_value1);
 
     Local<Value> args2[] = { v8_str("tipli") };
@@ -10719,7 +11383,7 @@
     value = object2->Get(v8_str("a"));
     CHECK(!try_catch.HasCaught());
     CHECK(value->IsString());
-    String::Utf8Value string_value2(value->ToString());
+    String::Utf8Value string_value2(value->ToString(isolate));
     CHECK_EQ("tipli", *string_value2);
 
     // Call the Object's constructor with a Boolean.
@@ -10982,8 +11646,7 @@
 
 
 // Test that calling eval in a context which has been detached from
-// its global throws an exception.  This behavior is consistent with
-// other JavaScript implementations.
+// its global proxy works.
 THREADED_TEST(EvalInDetachedGlobal) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
@@ -11011,8 +11674,7 @@
   context0->DetachGlobal();
   v8::TryCatch catcher;
   x_value = CompileRun("fun('x')");
-  CHECK(x_value.IsEmpty());
-  CHECK(catcher.HasCaught());
+  CHECK_EQ(42, x_value->Int32Value());
   context1->Exit();
 }
 
@@ -11330,8 +11992,7 @@
 
 
 static void InterceptorHasOwnPropertyGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
 }
 
@@ -11342,7 +12003,8 @@
   v8::HandleScope scope(isolate);
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
   Local<Function> function = fun_templ->GetFunction();
   context->Global()->Set(v8_str("constructor"), function);
   v8::Handle<Value> value = CompileRun(
@@ -11361,8 +12023,7 @@
 
 
 static void InterceptorHasOwnPropertyGetterGC(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
 }
@@ -11374,7 +12035,8 @@
   v8::HandleScope scope(isolate);
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
   Local<Function> function = fun_templ->GetFunction();
   context->Global()->Set(v8_str("constructor"), function);
   // Let's first make some stuff so we can be sure to get a good GC.
@@ -11398,18 +12060,14 @@
 }
 
 
-typedef void (*NamedPropertyGetter)(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info);
-
-
-static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
-                                   const char* source,
-                                   int expected) {
+static void CheckInterceptorLoadIC(
+    v8::GenericNamedPropertyGetterCallback getter, const char* source,
+    int expected) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
+                                                          v8_str("data")));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(source);
@@ -11418,8 +12076,7 @@
 
 
 static void InterceptorLoadICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   v8::Isolate* isolate = CcTest::isolate();
   CHECK_EQ(isolate, info.GetIsolate());
@@ -11445,8 +12102,7 @@
 // (those cases are special cased to get better performance).
 
 static void InterceptorLoadXICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   info.GetReturnValue().Set(
       v8_str("x")->Equals(name) ?
@@ -11561,8 +12217,7 @@
 
 static int interceptor_load_not_handled_calls = 0;
 static void InterceptorLoadNotHandled(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ++interceptor_load_not_handled_calls;
 }
 
@@ -11623,7 +12278,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   templ->SetAccessor(v8_str("y"), Return239Callback);
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
@@ -11653,7 +12309,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback);
 
@@ -11687,7 +12344,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   templ->SetAccessor(v8_str("y"), Return239Callback);
 
   LocalContext context;
@@ -11716,7 +12374,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback);
 
@@ -11745,7 +12404,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
 
@@ -11778,7 +12438,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
 
@@ -11804,8 +12465,7 @@
 
 
 static void InterceptorLoadICGetter0(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
@@ -11820,8 +12480,7 @@
 
 
 static void InterceptorStoreICSetter(
-    Local<String> key,
-    Local<Value> value,
+    Local<Name> key, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8_str("x")->Equals(key));
   CHECK_EQ(42, value->Int32Value());
@@ -11834,9 +12493,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
-                                 InterceptorStoreICSetter,
-                                 0, 0, 0, v8_str("data"));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
+      v8_str("data")));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -11850,7 +12509,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11869,8 +12529,7 @@
 v8::Handle<Value> call_ic_function3;
 
 static void InterceptorCallICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(call_ic_function);
@@ -11882,7 +12541,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function =
@@ -11902,7 +12562,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11917,8 +12577,7 @@
 
 static v8::Handle<Value> call_ic_function4;
 static void InterceptorCallICGetter4(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(call_ic_function4);
@@ -11932,7 +12591,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function4 =
@@ -11953,7 +12613,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11981,7 +12641,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11998,8 +12658,7 @@
 
 static v8::Handle<Value> call_ic_function5;
 static void InterceptorCallICGetter5(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name))
     info.GetReturnValue().Set(call_ic_function5);
@@ -12013,7 +12672,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function5 =
@@ -12032,8 +12692,7 @@
 
 static v8::Handle<Value> call_ic_function6;
 static void InterceptorCallICGetter6(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name))
     info.GetReturnValue().Set(call_ic_function6);
@@ -12047,7 +12706,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function6 =
@@ -12078,7 +12738,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -12109,7 +12769,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -12135,7 +12795,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
 
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
@@ -12160,8 +12820,7 @@
 }
 
 static void InterceptorCallICFastApi(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
   int* call_count =
@@ -12350,9 +13009,9 @@
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12380,9 +13039,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12413,9 +13072,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12452,9 +13111,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12491,9 +13150,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12515,7 +13174,7 @@
   CHECK(try_catch.HasCaught());
   // TODO(verwaest): Adjust message.
   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   CHECK_GE(interceptor_call_count, 50);
 }
@@ -12534,9 +13193,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12557,7 +13216,7 @@
       "}");
   CHECK(try_catch.HasCaught());
   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   CHECK_GE(interceptor_call_count, 50);
 }
@@ -12690,7 +13349,7 @@
   CHECK(try_catch.HasCaught());
   // TODO(verwaest): Adjust message.
   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 }
 
@@ -12728,7 +13387,7 @@
       "}");
   CHECK(try_catch.HasCaught());
   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 }
 
@@ -12736,8 +13395,7 @@
 v8::Handle<Value> keyed_call_ic_function;
 
 static void InterceptorKeyedCallICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name)) {
     info.GetReturnValue().Set(keyed_call_ic_function);
@@ -12751,7 +13409,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -12776,7 +13434,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
   keyed_call_ic_function =
@@ -12804,7 +13463,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -12830,7 +13489,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
@@ -12856,7 +13515,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
 
@@ -12879,7 +13538,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
@@ -12900,8 +13559,7 @@
 static int interceptor_call_count = 0;
 
 static void InterceptorICRefErrorGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
     info.GetReturnValue().Set(call_ic_function2);
@@ -12916,7 +13574,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
   v8::Handle<Value> value = CompileRun(
@@ -12944,8 +13603,7 @@
 static int interceptor_ic_exception_get_count = 0;
 
 static void InterceptorICExceptionGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
     info.GetReturnValue().Set(call_ic_function3);
@@ -12964,7 +13622,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
   v8::Handle<Value> value = CompileRun(
@@ -12992,9 +13651,8 @@
 static int interceptor_ic_exception_set_count = 0;
 
 static void InterceptorICExceptionSetter(
-      Local<String> key,
-      Local<Value> value,
-      const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, Local<Value> value,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (++interceptor_ic_exception_set_count > 20) {
     info.GetIsolate()->ThrowException(v8_num(42));
@@ -13009,7 +13667,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   v8::Handle<Value> value = CompileRun(
     "function f() {"
@@ -13028,8 +13687,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(
-      static_cast<v8::NamedPropertyGetterCallback>(0));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
   LocalContext context;
   templ->Set(CcTest::isolate(), "x", v8_num(42));
   v8::Handle<v8::Object> obj = templ->NewInstance();
@@ -13045,8 +13704,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(
-      static_cast<v8::IndexedPropertyGetterCallback>(0));
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      static_cast<v8::IndexedPropertyGetterCallback>(0)));
   LocalContext context;
   templ->Set(CcTest::isolate(), "42", v8_num(42));
   v8::Handle<v8::Object> obj = templ->NewInstance();
@@ -13061,7 +13720,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -13315,7 +13975,7 @@
 
   // Normal ToString call should call replaced Object.prototype.toString
   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
-  Local<String> value = instance->ToString();
+  Local<String> value = instance->ToString(isolate);
   CHECK(value->IsString() && value->Equals(customized_tostring));
 
   // ObjectProtoToString should not call replace toString function.
@@ -13333,9 +13993,127 @@
 }
 
 
-THREADED_TEST(ObjectGetConstructorName) {
+TEST(ObjectProtoToStringES6) {
+  // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
+  i::FLAG_harmony_tostring = true;
   LocalContext context;
-  v8::HandleScope scope(context->GetIsolate());
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
+  templ->SetClassName(v8_str("MyClass"));
+
+  Local<String> customized_tostring = v8_str("customized toString");
+
+  // Replace Object.prototype.toString
+  CompileRun(
+      "Object.prototype.toString = function() {"
+      "  return 'customized toString';"
+      "}");
+
+  // Normal ToString call should call replaced Object.prototype.toString
+  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
+  Local<String> value = instance->ToString(isolate);
+  CHECK(value->IsString() && value->Equals(customized_tostring));
+
+  // ObjectProtoToString should not call replace toString function.
+  value = instance->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
+
+  // Check global
+  value = context->Global()->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
+
+  // Check ordinary object
+  Local<Value> object = CompileRun("new Object()");
+  value = object.As<v8::Object>()->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
+
+  // Check that ES6 semantics using @@toStringTag work
+  Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
+
+#define TEST_TOSTRINGTAG(type, tag, expected)                \
+  do {                                                       \
+    object = CompileRun("new " #type "()");                  \
+    object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
+    value = object.As<v8::Object>()->ObjectProtoToString();  \
+    CHECK(value->IsString() &&                               \
+          value->Equals(v8_str("[object " #expected "]")));  \
+  } while (0)
+
+  TEST_TOSTRINGTAG(Array, Object, Object);
+  TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
+  TEST_TOSTRINGTAG(Object, Array, ~Array);
+  TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
+  TEST_TOSTRINGTAG(Object, Date, ~Date);
+  TEST_TOSTRINGTAG(Object, Error, ~Error);
+  TEST_TOSTRINGTAG(Object, Function, ~Function);
+  TEST_TOSTRINGTAG(Object, Number, ~Number);
+  TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
+  TEST_TOSTRINGTAG(Object, String, ~String);
+  TEST_TOSTRINGTAG(Object, Foo, Foo);
+
+#undef TEST_TOSTRINGTAG
+
+  // @@toStringTag getter throws
+  Local<Value> obj = v8::Object::New(isolate);
+  obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value.IsEmpty());
+    CHECK(try_catch.HasCaught());
+  }
+
+  // @@toStringTag getter does not throw
+  obj = v8::Object::New(isolate);
+  obj.As<v8::Object>()->SetAccessor(
+      toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag value
+  obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag getter throws
+  obj = CompileRun(
+      "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
+      "  get: function() { throw 'Test'; }"
+      "}); obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value.IsEmpty());
+    CHECK(try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag getter does not throw
+  obj = CompileRun(
+      "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
+      "  get: function() { return 'Test'; }"
+      "}); obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+}
+
+
+THREADED_TEST(ObjectGetConstructorName) {
+  v8::Isolate* isolate = CcTest::isolate();
+  LocalContext context;
+  v8::HandleScope scope(isolate);
   v8_compile("function Parent() {};"
              "function Child() {};"
              "Child.prototype = new Parent();"
@@ -13345,16 +14123,17 @@
              "var x = new outer.inner();")->Run();
 
   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
-  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
-      v8_str("Parent")));
+  CHECK(p->IsObject() &&
+        p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
 
   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
-  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
-      v8_str("Child")));
+  CHECK(c->IsObject() &&
+        c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
 
   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
-  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
-      v8_str("outer.inner")));
+  CHECK(x->IsObject() &&
+        x->ToObject(isolate)->GetConstructorName()->Equals(
+            v8_str("outer.inner")));
 }
 
 
@@ -13902,7 +14681,7 @@
   v8::Local<Context> env = Context::New(isolate);
   env->Enter();
   v8::Handle<Value> value = NestedScope(env);
-  v8::Handle<String> str(value->ToString());
+  v8::Handle<String> str(value->ToString(isolate));
   CHECK(!str.IsEmpty());
   env->Exit();
 }
@@ -14744,7 +15523,7 @@
   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
   CHECK_EQ(0, props->Length());
   for (uint32_t i = 0; i < props->Length(); i++) {
-    printf("p[%d]\n", i);
+    printf("p[%u]\n", i);
   }
 }
 
@@ -15291,7 +16070,7 @@
 #ifndef V8_INTERPRETED_REGEXP
 
 struct RegExpInterruptionData {
-  int loop_count;
+  v8::base::Atomic32 loop_count;
   UC16VectorResource* string_resource;
   v8::Persistent<v8::String> string;
 } regexp_interruption_data;
@@ -15303,9 +16082,10 @@
       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
 
   virtual void Run() {
-    for (regexp_interruption_data.loop_count = 0;
-         regexp_interruption_data.loop_count < 7;
-         regexp_interruption_data.loop_count++) {
+    for (v8::base::NoBarrier_Store(&regexp_interruption_data.loop_count, 0);
+         v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) < 7;
+         v8::base::NoBarrier_AtomicIncrement(
+             &regexp_interruption_data.loop_count, 1)) {
       v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
     }
@@ -15319,7 +16099,9 @@
 
 
 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
-  if (regexp_interruption_data.loop_count != 2) return;
+  if (v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) != 2) {
+    return;
+  }
   v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::String> string = v8::Local<v8::String>::New(
       CcTest::isolate(), regexp_interruption_data.string);
@@ -15407,9 +16189,14 @@
   force_set_set_count++;
 }
 
+static void ForceSetInterceptGetter(
+    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  CHECK(name->IsString());
+  ForceSetGetter(Local<String>::Cast(name), info);
+}
+
 static void ForceSetInterceptSetter(
-    v8::Local<v8::String> name,
-    v8::Local<v8::Value> value,
+    v8::Local<v8::Name> name, v8::Local<v8::Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   force_set_set_count++;
   info.GetReturnValue().SetUndefined();
@@ -15469,7 +16256,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      ForceSetInterceptGetter, ForceSetInterceptSetter));
   LocalContext context(NULL, templ);
   v8::Handle<v8::Object> global = context->Global();
 
@@ -15537,7 +16325,7 @@
 
 
 static void ForceDeleteDeleter(
-    v8::Local<v8::String> name,
+    v8::Local<v8::Name> name,
     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   force_delete_interceptor_count++;
   if (pass_on_delete) return;
@@ -15552,7 +16340,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(0, 0, 0, ForceDeleteDeleter));
   LocalContext context(NULL, templ);
   v8::Handle<v8::Object> global = context->Global();
 
@@ -16195,8 +16984,8 @@
   }
   v8::Handle<v8::ObjectTemplate> templ =
       v8::ObjectTemplate::New(context->GetIsolate());
-  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
-                                   NotHandledIndexedPropertySetter);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
   v8::Handle<v8::Object> obj = templ->NewInstance();
   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
   context->Global()->Set(v8_str("pixels"), obj);
@@ -17335,6 +18124,7 @@
 static void StackTraceForUncaughtExceptionListener(
     v8::Handle<v8::Message> message,
     v8::Handle<Value>) {
+  report_count++;
   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
   CHECK_EQ(2, stack_trace->GetFrameCount());
   checkStackFrame("origin", "foo", 2, 3, false, false,
@@ -17365,6 +18155,38 @@
   Function::Cast(*trouble)->Call(global, 0, NULL);
   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
+  CHECK_EQ(1, report_count);
+}
+
+
+TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
+  report_count = 0;
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  // Create an Error object first.
+  CompileRunWithOrigin(
+      "function foo() {\n"
+      "e=new Error('err');\n"
+      "};\n"
+      "function bar() {\n"
+      "  foo();\n"
+      "};\n"
+      "var e;",
+      "origin");
+  v8::Local<v8::Object> global = env->Global();
+  Local<Value> trouble = global->Get(v8_str("bar"));
+  CHECK(trouble->IsFunction());
+  Function::Cast(*trouble)->Call(global, 0, NULL);
+
+  // Enable capturing detailed stack trace late, and throw the exception.
+  // The detailed stack trace should be extracted from the simple stack.
+  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+  CompileRunWithOrigin("throw e", "origin");
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
+  CHECK_EQ(1, report_count);
 }
 
 
@@ -17519,6 +18341,343 @@
 }
 
 
+v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
+int promise_reject_counter = 0;
+int promise_revoke_counter = 0;
+int promise_reject_line_number = -1;
+int promise_reject_frame_count = -1;
+
+void PromiseRejectCallback(v8::PromiseRejectMessage message) {
+  if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
+    promise_reject_counter++;
+    CcTest::global()->Set(v8_str("rejected"), message.GetPromise());
+    CcTest::global()->Set(v8_str("value"), message.GetValue());
+    v8::Handle<v8::StackTrace> stack_trace =
+        v8::Exception::CreateMessage(message.GetValue())->GetStackTrace();
+    if (!stack_trace.IsEmpty()) {
+      promise_reject_frame_count = stack_trace->GetFrameCount();
+      if (promise_reject_frame_count > 0) {
+        CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
+        promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
+      } else {
+        promise_reject_line_number = -1;
+      }
+    }
+  } else {
+    promise_revoke_counter++;
+    CcTest::global()->Set(v8_str("revoked"), message.GetPromise());
+    CHECK(message.GetValue().IsEmpty());
+  }
+}
+
+
+v8::Handle<v8::Promise> GetPromise(const char* name) {
+  return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
+}
+
+
+v8::Handle<v8::Value> RejectValue() {
+  return CcTest::global()->Get(v8_str("value"));
+}
+
+
+void ResetPromiseStates() {
+  promise_reject_counter = 0;
+  promise_revoke_counter = 0;
+  promise_reject_line_number = -1;
+  promise_reject_frame_count = -1;
+  CcTest::global()->Set(v8_str("rejected"), v8_str(""));
+  CcTest::global()->Set(v8_str("value"), v8_str(""));
+  CcTest::global()->Set(v8_str("revoked"), v8_str(""));
+}
+
+
+TEST(PromiseRejectCallback) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  isolate->SetPromiseRejectCallback(PromiseRejectCallback);
+
+  ResetPromiseStates();
+
+  // Create promise p0.
+  CompileRun(
+      "var reject;            \n"
+      "var p0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reject = rej;      \n"
+      "  }                    \n"
+      ");                     \n");
+  CHECK(!GetPromise("p0")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add resolve handler (and default reject handler) to p0.
+  CompileRun("var p1 = p0.then(function(){});");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject p0.
+  CompileRun("reject('ppp');");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
+  CHECK(RejectValue()->Equals(v8_str("ppp")));
+
+  // Reject p0 again. Callback is not triggered again.
+  CompileRun("reject();");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add resolve handler to p1.
+  CompileRun("var p2 = p1.then(function(){});");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(GetPromise("p1")->HasHandler());
+  CHECK(!GetPromise("p2")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
+  CHECK(RejectValue()->Equals(v8_str("ppp")));
+  CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
+
+  ResetPromiseStates();
+
+  // Create promise q0.
+  CompileRun(
+      "var q0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reject = rej;      \n"
+      "  }                    \n"
+      ");                     \n");
+  CHECK(!GetPromise("q0")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add reject handler to q0.
+  CompileRun("var q1 = q0.catch(function() {});");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject q0.
+  CompileRun("reject('qq')");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add a new reject handler, which rejects by returning Promise.reject().
+  // The returned promise q_ triggers a reject callback at first, only to
+  // revoke it when returning it causes q2 to be rejected.
+  CompileRun(
+      "var q_;"
+      "var q2 = q0.catch(               \n"
+      "   function() {                  \n"
+      "     q_ = Promise.reject('qqq'); \n"
+      "     return q_;                  \n"
+      "   }                             \n"
+      ");                               \n");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK(!GetPromise("q2")->HasHandler());
+  CHECK(GetPromise("q_")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
+  CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
+  CHECK(RejectValue()->Equals(v8_str("qqq")));
+
+  // Add a reject handler to the resolved q1, which rejects by throwing.
+  CompileRun(
+      "var q3 = q1.then(  \n"
+      "   function() {    \n"
+      "     throw 'qqqq'; \n"
+      "   }               \n"
+      ");                 \n");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(GetPromise("q1")->HasHandler());
+  CHECK(!GetPromise("q2")->HasHandler());
+  CHECK(!GetPromise("q3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
+  CHECK(RejectValue()->Equals(v8_str("qqqq")));
+
+  ResetPromiseStates();
+
+  // Create promise r0, which has three handlers, two of which handle rejects.
+  CompileRun(
+      "var r0 = new Promise(             \n"
+      "  function(res, rej) {            \n"
+      "    reject = rej;                 \n"
+      "  }                               \n"
+      ");                                \n"
+      "var r1 = r0.catch(function() {}); \n"
+      "var r2 = r0.then(function() {});  \n"
+      "var r3 = r0.then(function() {},   \n"
+      "                 function() {});  \n");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(!GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject r0.
+  CompileRun("reject('rrr')");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(!GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
+  CHECK(RejectValue()->Equals(v8_str("rrr")));
+
+  // Add reject handler to r2.
+  CompileRun("var r4 = r2.catch(function() {});");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK(!GetPromise("r4")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
+  CHECK(RejectValue()->Equals(v8_str("rrr")));
+
+  // Add reject handlers to r4.
+  CompileRun("var r5 = r4.then(function() {}, function() {});");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK(GetPromise("r4")->HasHandler());
+  CHECK(!GetPromise("r5")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+
+  ResetPromiseStates();
+
+  // Create promise s0, which has three handlers, none of which handle rejects.
+  CompileRun(
+      "var s0 = new Promise(            \n"
+      "  function(res, rej) {           \n"
+      "    reject = rej;                \n"
+      "  }                              \n"
+      ");                               \n"
+      "var s1 = s0.then(function() {}); \n"
+      "var s2 = s0.then(function() {}); \n"
+      "var s3 = s0.then(function() {}); \n");
+  CHECK(GetPromise("s0")->HasHandler());
+  CHECK(!GetPromise("s1")->HasHandler());
+  CHECK(!GetPromise("s2")->HasHandler());
+  CHECK(!GetPromise("s3")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject s0.
+  CompileRun("reject('sss')");
+  CHECK(GetPromise("s0")->HasHandler());
+  CHECK(!GetPromise("s1")->HasHandler());
+  CHECK(!GetPromise("s2")->HasHandler());
+  CHECK(!GetPromise("s3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK(RejectValue()->Equals(v8_str("sss")));
+
+  // Test stack frames.
+  V8::SetCaptureStackTraceForUncaughtExceptions(true);
+
+  ResetPromiseStates();
+
+  // Create promise t0, which is rejected in the constructor with an error.
+  CompileRunWithOrigin(
+      "var t0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reference_error;   \n"
+      "  }                    \n"
+      ");                     \n",
+      "pro", 0, 0);
+  CHECK(!GetPromise("t0")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(2, promise_reject_frame_count);
+  CHECK_EQ(3, promise_reject_line_number);
+
+  ResetPromiseStates();
+
+  // Create promise u0 and chain u1 to it, which is rejected via throw.
+  CompileRunWithOrigin(
+      "var u0 = Promise.resolve();        \n"
+      "var u1 = u0.then(                  \n"
+      "           function() {            \n"
+      "             (function() {         \n"
+      "                throw new Error(); \n"
+      "              })();                \n"
+      "           }                       \n"
+      "         );                        \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("u0")->HasHandler());
+  CHECK(!GetPromise("u1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(2, promise_reject_frame_count);
+  CHECK_EQ(5, promise_reject_line_number);
+
+  // Throw in u3, which handles u1's rejection.
+  CompileRunWithOrigin(
+      "function f() {                \n"
+      "  return (function() {        \n"
+      "    return new Error();       \n"
+      "  })();                       \n"
+      "}                             \n"
+      "var u2 = Promise.reject(f()); \n"
+      "var u3 = u1.catch(            \n"
+      "           function() {       \n"
+      "             return u2;       \n"
+      "           }                  \n"
+      "         );                   \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("u0")->HasHandler());
+  CHECK(GetPromise("u1")->HasHandler());
+  CHECK(GetPromise("u2")->HasHandler());
+  CHECK(!GetPromise("u3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(2, promise_revoke_counter);
+  CHECK_EQ(3, promise_reject_frame_count);
+  CHECK_EQ(3, promise_reject_line_number);
+
+  ResetPromiseStates();
+
+  // Create promise rejected promise v0, which is incorrectly handled by v1
+  // via chaining cycle.
+  CompileRunWithOrigin(
+      "var v0 = Promise.reject(); \n"
+      "var v1 = v0.catch(         \n"
+      "           function() {    \n"
+      "             return v1;    \n"
+      "           }               \n"
+      "         );                \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("v0")->HasHandler());
+  CHECK(!GetPromise("v1")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK_EQ(0, promise_reject_frame_count);
+  CHECK_EQ(-1, promise_reject_line_number);
+}
+
+
 void AnalyzeStackOfEvalWithSourceURL(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
@@ -17835,40 +18994,6 @@
 }
 
 
-TEST(Regress2107) {
-  const intptr_t MB = 1024 * 1024;
-  const int kIdlePauseInMs = 1000;
-  LocalContext env;
-  v8::Isolate* isolate = env->GetIsolate();
-  v8::HandleScope scope(env->GetIsolate());
-  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
-  // Send idle notification to start a round of incremental GCs.
-  env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  // Emulate 7 page reloads.
-  for (int i = 0; i < 7; i++) {
-    {
-      v8::HandleScope inner_scope(env->GetIsolate());
-      v8::Local<v8::Context> ctx = v8::Context::New(isolate);
-      ctx->Enter();
-      CreateGarbageInOldSpace();
-      ctx->Exit();
-    }
-    env->GetIsolate()->ContextDisposedNotification();
-    env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  }
-  // Create garbage and check that idle notification still collects it.
-  CreateGarbageInOldSpace();
-  intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
-  CHECK_GT(size_with_garbage, initial_size + MB);
-  bool finished = false;
-  for (int i = 0; i < 200 && !finished; i++) {
-    finished = env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  }
-  intptr_t final_size = CcTest::heap()->SizeOfObjects();
-  CHECK_LT(final_size, initial_size + 1);
-}
-
-
 TEST(Regress2333) {
   LocalContext env;
   for (int i = 0; i < 3; i++) {
@@ -17998,10 +19123,11 @@
 
 
 TEST(ExternalizeOldSpaceTwoByteCons) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   v8::Local<v8::String> cons =
-      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
+      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   CcTest::heap()->CollectAllAvailableGarbage();
   CHECK(CcTest::heap()->old_pointer_space()->Contains(
@@ -18020,10 +19146,11 @@
 
 
 TEST(ExternalizeOldSpaceOneByteCons) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   v8::Local<v8::String> cons =
-      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
+      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   CcTest::heap()->CollectAllAvailableGarbage();
   CHECK(CcTest::heap()->old_pointer_space()->Contains(
@@ -18042,8 +19169,9 @@
 
 
 TEST(VisitExternalStrings) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   const char* string = "Some string";
   uint16_t* two_byte_string = AsciiToTwoByteString(string);
   TestResource* resource[4];
@@ -18113,7 +19241,7 @@
     const char* s = "One string to test them all";
     TestOneByteResource* inscription =
         new TestOneByteResource(i::StrDup(s), &destroyed);
-    v8::Local<v8::String> ring = CompileRun("ring")->ToString();
+    v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
     ring->MakeExternal(inscription);
     // Ring is still alive.  Orcs are roaming freely across our lands.
@@ -18128,6 +19256,9 @@
 
 
 TEST(ExternalInternalizedStringCollectedAtGC) {
+  // TODO(mvstanton): vector ics need weak support.
+  if (i::FLAG_vector_ics) return;
+
   int destroyed = 0;
   { LocalContext env;
     v8::HandleScope handle_scope(env->GetIsolate());
@@ -18135,7 +19266,7 @@
     const char* s = "One string to test them all";
     TestOneByteResource* inscription =
         new TestOneByteResource(i::StrDup(s), &destroyed);
-    v8::Local<v8::String> ring = CompileRun("ring")->ToString();
+    v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
     ring->MakeExternal(inscription);
     // Ring is still alive.  Orcs are roaming freely across our lands.
@@ -18274,7 +19405,7 @@
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
   v8::TryCatch tc;
-  v8::Handle<v8::String> str(args[0]->ToString());
+  v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
   USE(str);
   if (tc.HasCaught())
     tc.ReThrow();
@@ -18625,7 +19756,7 @@
 }
 
 
-void FooGetInterceptor(Local<String> name,
+void FooGetInterceptor(Local<Name> name,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
@@ -18634,8 +19765,7 @@
 }
 
 
-void FooSetInterceptor(Local<String> name,
-                       Local<Value> value,
+void FooSetInterceptor(Local<Name> name, Local<Value> value,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
@@ -18681,15 +19811,13 @@
 
 
 static void NamedPropertyGetterWhichReturns42(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_num(42));
 }
 
 
 static void NamedPropertySetterWhichSetsYOnThisTo23(
-    Local<String> name,
-    Local<Value> value,
+    Local<Name> name, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   if (name->Equals(v8_str("x"))) {
     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
@@ -18701,8 +19829,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
-                                 NamedPropertySetterWhichSetsYOnThisTo23);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedPropertyGetterWhichReturns42,
+      NamedPropertySetterWhichSetsYOnThisTo23));
   LocalContext context;
   context->Global()->Set(v8_str("P"), templ->NewInstance());
   CompileRun("function C1() {"
@@ -19860,7 +20989,7 @@
   CHECK_EQ(42, object.WrapperClassId());
 
   Visitor42 visitor(&object);
-  v8::V8::VisitHandlesWithClassIds(&visitor);
+  v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
   CHECK_EQ(1, visitor.counter_);
 
   object.Reset();
@@ -19994,8 +21123,8 @@
 }
 
 
-static void Getter(v8::Local<v8::String> property,
-                   const v8::PropertyCallbackInfo<v8::Value>& info ) {
+static void Getter(v8::Local<v8::Name> property,
+                   const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_str("42!"));
 }
 
@@ -20014,7 +21143,8 @@
   v8::Context::Scope context_scope(context.local());
 
   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
-  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
+  tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
+                                                         NULL, Enumerator));
   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
         "var result = []; for (var k in o) result.push(k); result"));
@@ -20159,8 +21289,7 @@
 
 
 void HasOwnPropertyNamedPropertyGetter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
 }
 
@@ -20172,15 +21301,13 @@
 
 
 void HasOwnPropertyNamedPropertyQuery(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
 }
 
 
 void HasOwnPropertyNamedPropertyQuery2(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
 }
 
@@ -20209,7 +21336,7 @@
         "Bar.prototype = new Foo();"
         "new Bar();");
     CHECK(value->IsObject());
-    Handle<Object> object = value->ToObject();
+    Handle<Object> object = value->ToObject(isolate);
     CHECK(object->Has(v8_str("foo")));
     CHECK(!object->HasOwnProperty(v8_str("foo")));
     CHECK(object->HasOwnProperty(v8_str("bar")));
@@ -20219,7 +21346,8 @@
   }
   { // Check named getter interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        HasOwnPropertyNamedPropertyGetter));
     Handle<Object> instance = templ->NewInstance();
     CHECK(!instance->HasOwnProperty(v8_str("42")));
     CHECK(instance->HasOwnProperty(v8_str("foo")));
@@ -20227,7 +21355,8 @@
   }
   { // Check indexed getter interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
+    templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+        HasOwnPropertyIndexedPropertyGetter));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("42")));
     CHECK(!instance->HasOwnProperty(v8_str("43")));
@@ -20235,14 +21364,16 @@
   }
   { // Check named query interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        0, 0, HasOwnPropertyNamedPropertyQuery));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("foo")));
     CHECK(!instance->HasOwnProperty(v8_str("bar")));
   }
   { // Check indexed query interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
+    templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+        0, 0, HasOwnPropertyIndexedPropertyQuery));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("42")));
     CHECK(!instance->HasOwnProperty(v8_str("41")));
@@ -20256,9 +21387,9 @@
   }
   { // Check that query wins on disagreement.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
-                                   0,
-                                   HasOwnPropertyNamedPropertyQuery2);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        HasOwnPropertyNamedPropertyGetter, 0,
+        HasOwnPropertyNamedPropertyQuery2));
     Handle<Object> instance = templ->NewInstance();
     CHECK(!instance->HasOwnProperty(v8_str("foo")));
     CHECK(instance->HasOwnProperty(v8_str("bar")));
@@ -20270,9 +21401,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(NULL,
-                                   NULL,
-                                   HasOwnPropertyIndexedPropertyQuery);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
@@ -20417,29 +21547,40 @@
 }
 
 
+static int CountLiveMapsInMapCache(i::Context* context) {
+  i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
+  int length = map_cache->length();
+  int count = 0;
+  for (int i = 0; i < length; i++) {
+    i::Object* value = map_cache->get(i);
+    if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
+  }
+  return count;
+}
+
+
 THREADED_TEST(Regress1516) {
   LocalContext context;
   v8::HandleScope scope(context->GetIsolate());
 
+  // Object with 20 properties is not a common case, so it should be removed
+  // from the cache after GC.
   { v8::HandleScope temp_scope(context->GetIsolate());
-    CompileRun("({'a': 0})");
+    CompileRun(
+        "({"
+        "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
+        "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
+        "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
+        "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
+        "})");
   }
 
-  int elements;
-  { i::MapCache* map_cache =
-        i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
-    elements = map_cache->NumberOfElements();
-    CHECK_LE(1, elements);
-  }
+  int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
+  CHECK_LE(1, elements);
 
-  CcTest::heap()->CollectAllGarbage(
-      i::Heap::kAbortIncrementalMarkingMask);
-  { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
-    if (raw_map_cache != CcTest::heap()->undefined_value()) {
-      i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
-      CHECK_GT(elements, map_cache->NumberOfElements());
-    }
-  }
+  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+
+  CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
 }
 
 
@@ -20448,12 +21589,11 @@
                                                 v8::AccessType type,
                                                 Local<Value> data) {
   // Only block read access to __proto__.
-  if (type == v8::ACCESS_GET &&
-      name->IsString() &&
-      name->ToString()->Length() == 9 &&
-      name->ToString()->Utf8Length() == 9) {
+  if (type == v8::ACCESS_GET && name->IsString() &&
+      name.As<v8::String>()->Length() == 9 &&
+      name.As<v8::String>()->Utf8Length() == 9) {
     char buffer[10];
-    CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
+    CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer));
     return strncmp(buffer, "__proto__", 9) != 0;
   }
 
@@ -20500,8 +21640,7 @@
       context->Global();
 
   // Global object, the  prototype of proxy_object. No security checks.
-  Local<Object> global_object =
-      proxy_object->GetPrototype()->ToObject();
+  Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
 
   // Hidden prototype without security check.
   Local<Object> hidden_prototype =
@@ -20545,7 +21684,7 @@
 
   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
   CHECK(result5->Equals(
-      object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
+      object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
 
   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
   CHECK(result6.IsEmpty());
@@ -20581,8 +21720,8 @@
                          const char* code) {
   Local<Value> result = CompileRun(code);
   CHECK(result->IsObject());
-  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
-  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
+  CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
+  CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
 }
 
 
@@ -20970,8 +22109,8 @@
   Handle<Object> exec_state = event_details.GetExecutionState();
   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
   CompileRun("function f(id) { new FrameDetails(id, 0); }");
-  Handle<Function> fun = Handle<Function>::Cast(
-      CcTest::global()->Get(v8_str("f"))->ToObject());
+  Handle<Function> fun =
+      Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
   fun->Call(CcTest::global(), 1, &break_id);
 }
 
@@ -20995,7 +22134,7 @@
 }
 
 
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
 static int probes_counter = 0;
 static int misses_counter = 0;
 static int updates_counter = 0;
@@ -21029,7 +22168,7 @@
 
 
 static void StubCacheHelper(bool primary) {
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
   i::FLAG_native_code_counters = true;
   if (primary) {
     i::FLAG_test_primary_stub_cache = true;
@@ -21376,7 +22515,8 @@
   LocalContext context;
   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
   if (interceptor) {
-    templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
+                                                            FooSetInterceptor));
   } else {
     templ->SetAccessor(v8_str("foo"),
                        GetterWhichReturns42,
@@ -21782,7 +22922,8 @@
 
 
 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
-  args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
+  args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
+      args[1]->ToString(args.GetIsolate()));
 }
 
 
@@ -21998,8 +23139,6 @@
 
     TestBody();
 
-    isolate_->ClearInterrupt();
-
     // Verify we arrived here because interruptor was called
     // not due to a bug causing us to exit the loop too early.
     CHECK(!should_continue());
@@ -22149,7 +23288,8 @@
     proto->Set(v8_str("shouldContinue"), Function::New(
         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
-    instance_template->SetNamedPropertyHandler(EmptyInterceptor);
+    instance_template->SetHandler(
+        v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
 
     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
 
@@ -22158,9 +23298,7 @@
 
  private:
   static void EmptyInterceptor(
-      Local<String> property,
-      const v8::PropertyCallbackInfo<v8::Value>& info) {
-  }
+      Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
 };
 
 
@@ -22249,10 +23387,9 @@
 }
 
 
-class ClearInterruptFromAnotherThread
-    : public RequestInterruptTestBase {
+class RequestMultipleInterrupts : public RequestInterruptTestBase {
  public:
-  ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
+  RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
 
   virtual void StartInterruptThread() {
     i_thread.Start();
@@ -22269,39 +23406,33 @@
  private:
   class InterruptThread : public v8::base::Thread {
    public:
-    explicit InterruptThread(ClearInterruptFromAnotherThread* test)
+    enum { NUM_INTERRUPTS = 10 };
+    explicit InterruptThread(RequestMultipleInterrupts* test)
         : Thread(Options("RequestInterruptTest")), test_(test) {}
 
     virtual void Run() {
       test_->sem_.Wait();
-      test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
-      test_->sem_.Wait();
-      test_->isolate_->ClearInterrupt();
-      test_->sem2_.Signal();
+      for (int i = 0; i < NUM_INTERRUPTS; i++) {
+        test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
+      }
     }
 
     static void OnInterrupt(v8::Isolate* isolate, void* data) {
-      ClearInterruptFromAnotherThread* test =
-          reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
-      test->sem_.Signal();
-      bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
-      // Crash instead of timeout to make this failure more prominent.
-      CHECK(success);
-      test->should_continue_ = false;
+      RequestMultipleInterrupts* test =
+          reinterpret_cast<RequestMultipleInterrupts*>(data);
+      test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
     }
 
    private:
-     ClearInterruptFromAnotherThread* test_;
+    RequestMultipleInterrupts* test_;
   };
 
   InterruptThread i_thread;
-  v8::base::Semaphore sem2_;
+  int counter_;
 };
 
 
-TEST(ClearInterruptFromAnotherThread) {
-  ClearInterruptFromAnotherThread().RunTest();
-}
+TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
 
 
 static Local<Value> function_new_expected_env;
@@ -22606,6 +23737,7 @@
   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
   Handle<v8::Promise> p = pr->GetPromise();
   Handle<v8::Promise> r = rr->GetPromise();
+  CHECK_EQ(isolate, p->GetIsolate());
 
   // IsPromise predicate.
   CHECK(p->IsPromise());
@@ -22867,10 +23999,8 @@
   CHECK_EQ(13, line_number);
 }
 
-
-void SourceURLHelper(const char* source, const char* expected_source_url,
-                     const char* expected_source_mapping_url) {
-  Local<Script> script = v8_compile(source);
+void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
+                        const char* expected_source_mapping_url) {
   if (expected_source_url != NULL) {
     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
     CHECK_EQ(expected_source_url, *url);
@@ -22886,6 +24016,12 @@
   }
 }
 
+void SourceURLHelper(const char* source, const char* expected_source_url,
+                     const char* expected_source_mapping_url) {
+  Local<Script> script = v8_compile(source);
+  CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
+}
+
 
 TEST(ScriptSourceURLAndSourceMappingURL) {
   LocalContext env;
@@ -23077,7 +24213,9 @@
 void RunStreamingTest(const char** chunks,
                       v8::ScriptCompiler::StreamedSource::Encoding encoding =
                           v8::ScriptCompiler::StreamedSource::ONE_BYTE,
-                      bool expected_success = true) {
+                      bool expected_success = true,
+                      const char* expected_source_url = NULL,
+                      const char* expected_source_mapping_url = NULL) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
   v8::HandleScope scope(isolate);
@@ -23106,6 +24244,8 @@
     v8::Handle<Value> result(script->Run());
     // All scripts are supposed to return the fixed value 13 when ran.
     CHECK_EQ(13, result->Int32Value());
+    CheckMagicComments(script, expected_source_url,
+                       expected_source_mapping_url);
   } else {
     CHECK(script.IsEmpty());
     CHECK(try_catch.HasCaught());
@@ -23170,14 +24310,14 @@
 
 
 TEST(StreamingUtf8Script) {
-  // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers
+  // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
   // don't like it.
   const char* chunk1 =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
       "  // ASCII.\n"
-      "  var foob\xeb\x91\x80r = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  var foob\xec\x92\x81r = 13;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   const char* chunks[] = {chunk1, "foo(); ", NULL};
   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
@@ -23188,7 +24328,7 @@
   // A sanity check to prove that the approach of splitting UTF-8
   // characters is correct. Here is an UTF-8 character which will take three
   // bytes.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
 
   char chunk1[] =
@@ -23198,7 +24338,7 @@
       "  var foob";
   char chunk2[] =
       "XXXr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   for (int i = 0; i < 3; ++i) {
     chunk2[i] = reference[i];
@@ -23211,7 +24351,7 @@
 TEST(StreamingUtf8ScriptWithSplitCharacters) {
   // Stream data where a multi-byte UTF-8 character is split between two data
   // chunks.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23219,7 +24359,7 @@
       "  var foobX";
   char chunk2[] =
       "XXr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   chunk1[strlen(chunk1) - 1] = reference[0];
   chunk2[0] = reference[1];
@@ -23235,7 +24375,7 @@
   // Case 1: a chunk contains only bytes for a split character (and no other
   // data). This kind of a chunk would be exceptionally small, but we should
   // still decode it correctly.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   // The small chunk is at the beginning of the split character
   {
     char chunk1[] =
@@ -23246,7 +24386,7 @@
     char chunk2[] = "XX";
     char chunk3[] =
         "Xr = 13;\n"
-        "  return foob\xeb\x91\x80r;\n"
+        "  return foob\xec\x92\x81r;\n"
         "}\n";
     chunk2[0] = reference[0];
     chunk2[1] = reference[1];
@@ -23264,7 +24404,7 @@
     char chunk2[] = "XX";
     char chunk3[] =
         "r = 13;\n"
-        "  return foob\xeb\x91\x80r;\n"
+        "  return foob\xec\x92\x81r;\n"
         "}\n";
     chunk1[strlen(chunk1) - 1] = reference[0];
     chunk2[0] = reference[1];
@@ -23276,8 +24416,8 @@
   // decoded correctly and not just ignored.
   {
     char chunk1[] =
-        "var foob\xeb\x91\x80 = 13;\n"
-        "foob\xeb\x91\x80";
+        "var foob\xec\x92\x81 = 13;\n"
+        "foob\xec\x92\x81";
     const char* chunks[] = {chunk1, NULL};
     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
   }
@@ -23288,7 +24428,7 @@
   // Test cases where a UTF-8 character is split over several chunks. Those
   // cases are not supported (the embedder should give the data in big enough
   // chunks), but we shouldn't crash, just produce a parse error.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23297,7 +24437,7 @@
   char chunk2[] = "X";
   char chunk3[] =
       "Xr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   chunk1[strlen(chunk1) - 1] = reference[0];
   chunk2[0] = reference[1];
@@ -23332,6 +24472,7 @@
   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
   CHECK(cached_data != NULL);
   CHECK(cached_data->data != NULL);
+  CHECK(!cached_data->rejected);
   CHECK_GT(cached_data->length, 0);
 }
 
@@ -23339,7 +24480,7 @@
 TEST(StreamingScriptWithInvalidUtf8) {
   // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
   // chunk don't produce a crash.
-  const char* reference = "\xeb\x91\x80\x80\x80";
+  const char* reference = "\xec\x92\x81\x80\x80";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23347,10 +24488,274 @@
       "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
   char chunk2[] =
       "r = 13;\n"
-      "  return foob\xeb\x91\x80\x80\x80r;\n"
+      "  return foob\xec\x92\x81\x80\x80r;\n"
       "}\n";
   for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
 
   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
 }
+
+
+TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
+  // Regression test: Stream data where there are several multi-byte UTF-8
+  // characters in a sequence and one of them is split between two data chunks.
+  const char* reference = "\xec\x92\x81";
+  char chunk1[] =
+      "function foo() {\n"
+      "  // This function will contain an UTF-8 character which is not in\n"
+      "  // ASCII.\n"
+      "  var foob\xec\x92\x81X";
+  char chunk2[] =
+      "XXr = 13;\n"
+      "  return foob\xec\x92\x81\xec\x92\x81r;\n"
+      "}\n";
+  chunk1[strlen(chunk1) - 1] = reference[0];
+  chunk2[0] = reference[1];
+  chunk2[1] = reference[2];
+  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
+  // Another regression test, similar to the previous one. The difference is
+  // that the split character is not the last one in the sequence.
+  const char* reference = "\xec\x92\x81";
+  char chunk1[] =
+      "function foo() {\n"
+      "  // This function will contain an UTF-8 character which is not in\n"
+      "  // ASCII.\n"
+      "  var foobX";
+  char chunk2[] =
+      "XX\xec\x92\x81r = 13;\n"
+      "  return foob\xec\x92\x81\xec\x92\x81r;\n"
+      "}\n";
+  chunk1[strlen(chunk1) - 1] = reference[0];
+  chunk2[0] = reference[1];
+  chunk2[1] = reference[2];
+  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
+  const char* garbage = "garbage garbage garbage garbage garbage garbage";
+  const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
+  int length = 16;
+  v8::ScriptCompiler::CachedData* cached_data =
+      new v8::ScriptCompiler::CachedData(data, length);
+  DCHECK(!cached_data->rejected);
+  v8::ScriptOrigin origin(v8_str("origin"));
+  v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
+  v8::Handle<v8::Script> script =
+      v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
+  CHECK(cached_data->rejected);
+  CHECK_EQ(42, script->Run()->Int32Value());
+}
+
+
+TEST(InvalidCacheData) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
+  TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
+}
+
+
+TEST(ParserCacheRejectedGracefully) {
+  i::FLAG_min_preparse_length = 0;
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  // Produce valid cached data.
+  v8::ScriptOrigin origin(v8_str("origin"));
+  v8::Local<v8::String> source_str = v8_str("function foo() {}");
+  v8::ScriptCompiler::Source source(source_str, origin);
+  v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
+      CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
+  CHECK(!script.IsEmpty());
+  const v8::ScriptCompiler::CachedData* original_cached_data =
+      source.GetCachedData();
+  CHECK(original_cached_data != NULL);
+  CHECK(original_cached_data->data != NULL);
+  CHECK(!original_cached_data->rejected);
+  CHECK_GT(original_cached_data->length, 0);
+  // Recompiling the same script with it won't reject the data.
+  {
+    v8::ScriptCompiler::Source source_with_cached_data(
+        source_str, origin,
+        new v8::ScriptCompiler::CachedData(original_cached_data->data,
+                                           original_cached_data->length));
+    v8::Handle<v8::Script> script =
+        v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
+                                    v8::ScriptCompiler::kConsumeParserCache);
+    CHECK(!script.IsEmpty());
+    const v8::ScriptCompiler::CachedData* new_cached_data =
+        source_with_cached_data.GetCachedData();
+    CHECK(new_cached_data != NULL);
+    CHECK(!new_cached_data->rejected);
+  }
+  // Compile an incompatible script with the cached data. The new script doesn't
+  // have the same starting position for the function as the old one, so the old
+  // cached data will be incompatible with it and will be rejected.
+  {
+    v8::Local<v8::String> incompatible_source_str =
+        v8_str("   function foo() {}");
+    v8::ScriptCompiler::Source source_with_cached_data(
+        incompatible_source_str, origin,
+        new v8::ScriptCompiler::CachedData(original_cached_data->data,
+                                           original_cached_data->length));
+    v8::Handle<v8::Script> script =
+        v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
+                                    v8::ScriptCompiler::kConsumeParserCache);
+    CHECK(!script.IsEmpty());
+    const v8::ScriptCompiler::CachedData* new_cached_data =
+        source_with_cached_data.GetCachedData();
+    CHECK(new_cached_data != NULL);
+    CHECK(new_cached_data->rejected);
+  }
+}
+
+
+TEST(StringConcatOverflow) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  RandomLengthOneByteResource* r =
+      new RandomLengthOneByteResource(i::String::kMaxLength);
+  v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
+  CHECK(!str.IsEmpty());
+  v8::TryCatch try_catch;
+  v8::Local<v8::String> result = v8::String::Concat(str, str);
+  CHECK(result.IsEmpty());
+  CHECK(!try_catch.HasCaught());
+}
+
+
+TEST(TurboAsmDisablesNeuter) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+#if V8_TURBOFAN_TARGET
+  bool should_be_neuterable = !i::FLAG_turbo_asm;
+#else
+  bool should_be_neuterable = true;
+#endif
+  const char* load =
+      "function Module(stdlib, foreign, heap) {"
+      "  'use asm';"
+      "  var MEM32 = new stdlib.Int32Array(heap);"
+      "  function load() { return MEM32[0]; }"
+      "  return { load: load };"
+      "}"
+      "var buffer = new ArrayBuffer(4);"
+      "Module(this, {}, buffer).load();"
+      "buffer";
+
+  v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
+  CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+
+  const char* store =
+      "function Module(stdlib, foreign, heap) {"
+      "  'use asm';"
+      "  var MEM32 = new stdlib.Int32Array(heap);"
+      "  function store() { MEM32[0] = 0; }"
+      "  return { store: store };"
+      "}"
+      "var buffer = new ArrayBuffer(4);"
+      "Module(this, {}, buffer).store();"
+      "buffer";
+
+  result = CompileRun(store).As<v8::ArrayBuffer>();
+  CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+}
+
+
+TEST(GetPrototypeAccessControl) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  v8::Handle<v8::ObjectTemplate> obj_template =
+      v8::ObjectTemplate::New(isolate);
+  obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
+                                        BlockEverythingIndexed);
+
+  env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { %_GetPrototype(prohibited); }"
+        "%OptimizeFunctionOnNextCall(f);"
+        "f();");
+    CHECK(try_catch.HasCaught());
+  }
+}
+
+
+TEST(GetPrototypeHidden) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
+  t->SetHiddenPrototype(true);
+  Handle<Object> proto = t->GetFunction()->NewInstance();
+  Handle<Object> object = Object::New(isolate);
+  Handle<Object> proto2 = Object::New(isolate);
+  object->SetPrototype(proto);
+  proto->SetPrototype(proto2);
+
+  env->Global()->Set(v8_str("object"), object);
+  env->Global()->Set(v8_str("proto"), proto);
+  env->Global()->Set(v8_str("proto2"), proto2);
+
+  v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
+  CHECK(result->Equals(proto2));
+
+  result = CompileRun(
+      "function f() { return %_GetPrototype(object); }"
+      "%OptimizeFunctionOnNextCall(f);"
+      "f()");
+  CHECK(result->Equals(proto2));
+}
+
+
+TEST(ClassPrototypeCreationContext) {
+  i::FLAG_harmony_classes = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  Handle<Object> result = Handle<Object>::Cast(
+      CompileRun("'use strict'; class Example { }; Example.prototype"));
+  CHECK(env.local() == result->CreationContext());
+}
+
+
+TEST(SimpleStreamingScriptWithSourceURL) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
+                          "//# sourceURL=bar2.js\n", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
+                   "bar2.js");
+}
+
+
+TEST(StreamingScriptWithSplitSourceURL) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; } f",
+                          "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
+                   "bar2.js");
+}
+
+
+TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
+                          " sourceMappingURL=bar2.js\n", "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
+                   "bar2.js");
+}
diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc
index ed9563d..2bcf022 100644
--- a/test/cctest/test-assembler-arm.cc
+++ b/test/cctest/test-assembler-arm.cc
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include <iostream>  // NOLINT(readability/streams)
+
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
@@ -34,6 +36,7 @@
 #include "src/factory.h"
 #include "src/ostreams.h"
 
+using namespace v8::base;
 using namespace v8::internal;
 
 
@@ -1372,14 +1375,14 @@
   __ pkhtb(r2, r0, Operand(r1, ASR, 8));
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst1)));
 
-  __ uxtb16(r2, Operand(r0, ROR, 8));
+  __ uxtb16(r2, r0, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst2)));
 
-  __ uxtb(r2, Operand(r0, ROR, 8));
+  __ uxtb(r2, r0, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst3)));
 
   __ ldr(r0, MemOperand(r4, OFFSET_OF(T, src2)));
-  __ uxtab(r2, r0, Operand(r1, ROR, 8));
+  __ uxtab(r2, r0, r1, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst4)));
 
   __ ldm(ia_w, sp, r4.bit() | pc.bit());
@@ -1439,21 +1442,19 @@
     CHECK_EQ(expected_, t.result);
 
 
-TEST(18) {
+TEST(sdiv) {
   // Test the sdiv.
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-
-  typedef struct {
-    uint32_t dividend;
-    uint32_t divisor;
-    uint32_t result;
-  } T;
-  T t;
-
   Assembler assm(isolate, NULL, 0);
 
+  struct T {
+    int32_t dividend;
+    int32_t divisor;
+    int32_t result;
+  } t;
+
   if (CpuFeatures::IsSupported(SUDIV)) {
     CpuFeatureScope scope(&assm, SUDIV);
 
@@ -1477,6 +1478,8 @@
 #endif
     F3 f = FUNCTION_CAST<F3>(code->entry());
     Object* dummy;
+    TEST_SDIV(0, kMinInt, 0);
+    TEST_SDIV(0, 1024, 0);
     TEST_SDIV(1073741824, kMinInt, -2);
     TEST_SDIV(kMinInt, kMinInt, -1);
     TEST_SDIV(5, 10, 2);
@@ -1495,6 +1498,322 @@
 #undef TEST_SDIV
 
 
+#define TEST_UDIV(expected_, dividend_, divisor_) \
+  t.dividend = dividend_;                         \
+  t.divisor = divisor_;                           \
+  t.result = 0;                                   \
+  dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); \
+  CHECK_EQ(expected_, t.result);
+
+
+TEST(udiv) {
+  // Test the udiv.
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  Assembler assm(isolate, NULL, 0);
+
+  struct T {
+    uint32_t dividend;
+    uint32_t divisor;
+    uint32_t result;
+  } t;
+
+  if (CpuFeatures::IsSupported(SUDIV)) {
+    CpuFeatureScope scope(&assm, SUDIV);
+
+    __ mov(r3, Operand(r0));
+
+    __ ldr(r0, MemOperand(r3, OFFSET_OF(T, dividend)));
+    __ ldr(r1, MemOperand(r3, OFFSET_OF(T, divisor)));
+
+    __ sdiv(r2, r0, r1);
+    __ str(r2, MemOperand(r3, OFFSET_OF(T, result)));
+
+    __ bx(lr);
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef DEBUG
+    OFStream os(stdout);
+    code->Print(os);
+#endif
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    Object* dummy;
+    TEST_UDIV(0, 0, 0);
+    TEST_UDIV(0, 1024, 0);
+    TEST_UDIV(5, 10, 2);
+    TEST_UDIV(3, 10, 3);
+    USE(dummy);
+  }
+}
+
+
+#undef TEST_UDIV
+
+
+TEST(smmla) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmla(r1, r1, r2, r3);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt(), z = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, z, 0);
+    CHECK_EQ(bits::SignedMulHighAndAdd32(x, y, z), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(smmul) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmul(r1, r1, r2);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(bits::SignedMulHigh32(x, y), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtb) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtb(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int8_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtab) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtab(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int8_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxth) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxth(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int16_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtah) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtah(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int16_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtb) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtb(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint8_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtab) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtab(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint8_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxth) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxth(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint16_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtah) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtah(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint16_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
 TEST(code_relative_offset) {
   // Test extracting the offset of a label from the beginning of the code
   // in a register.
@@ -1565,4 +1884,100 @@
   CHECK_EQ(42, res);
 }
 
+
+TEST(ARMv8_vrintX) {
+  // Test the vrintX floating point instructions.
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+
+  typedef struct {
+    double input;
+    double ar;
+    double nr;
+    double mr;
+    double pr;
+    double zr;
+  } T;
+  T t;
+
+  // Create a function that accepts &t, and loads, manipulates, and stores
+  // the doubles and floats.
+  Assembler assm(isolate, NULL, 0);
+  Label L, C;
+
+
+  if (CpuFeatures::IsSupported(ARMv8)) {
+    CpuFeatureScope scope(&assm, ARMv8);
+
+    __ mov(ip, Operand(sp));
+    __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+
+    __ mov(r4, Operand(r0));
+
+    // Test vrinta
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrinta(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, ar));
+
+    // Test vrintn
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintn(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, nr));
+
+    // Test vrintp
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintp(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, pr));
+
+    // Test vrintm
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintm(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, mr));
+
+    // Test vrintz
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintz(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, zr));
+
+    __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef DEBUG
+    OFStream os(stdout);
+    code->Print(os);
+#endif
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+
+    Object* dummy = nullptr;
+    USE(dummy);
+
+#define CHECK_VRINT(input_val, ares, nres, mres, pres, zres) \
+  t.input = input_val;                                       \
+  dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);            \
+  CHECK_EQ(ares, t.ar);                                      \
+  CHECK_EQ(nres, t.nr);                                      \
+  CHECK_EQ(mres, t.mr);                                      \
+  CHECK_EQ(pres, t.pr);                                      \
+  CHECK_EQ(zres, t.zr);
+
+    CHECK_VRINT(-0.5, -1.0, -0.0, -1.0, -0.0, -0.0)
+    CHECK_VRINT(-0.6, -1.0, -1.0, -1.0, -0.0, -0.0)
+    CHECK_VRINT(-1.1, -1.0, -1.0, -2.0, -1.0, -1.0)
+    CHECK_VRINT(0.5, 1.0, 0.0, 0.0, 1.0, 0.0)
+    CHECK_VRINT(0.6, 1.0, 1.0, 0.0, 1.0, 0.0)
+    CHECK_VRINT(1.1, 1.0, 1.0, 1.0, 2.0, 1.0)
+    double inf = std::numeric_limits<double>::infinity();
+    CHECK_VRINT(inf, inf, inf, inf, inf, inf)
+    CHECK_VRINT(-inf, -inf, -inf, -inf, -inf, -inf)
+    CHECK_VRINT(-0.0, -0.0, -0.0, -0.0, -0.0, -0.0)
+    double nan = std::numeric_limits<double>::quiet_NaN();
+    CHECK_VRINT(nan, nan, nan, nan, nan, nan)
+
+#undef CHECK_VRINT
+  }
+}
 #undef __
diff --git a/test/cctest/test-assembler-arm64.cc b/test/cctest/test-assembler-arm64.cc
index 587a4ce..108152e 100644
--- a/test/cctest/test-assembler-arm64.cc
+++ b/test/cctest/test-assembler-arm64.cc
@@ -6554,6 +6554,95 @@
 }
 
 
+TEST(frintp) {
+  INIT_V8();
+  SETUP();
+
+  START();
+  __ Fmov(s16, 1.0);
+  __ Fmov(s17, 1.1);
+  __ Fmov(s18, 1.5);
+  __ Fmov(s19, 1.9);
+  __ Fmov(s20, 2.5);
+  __ Fmov(s21, -1.5);
+  __ Fmov(s22, -2.5);
+  __ Fmov(s23, kFP32PositiveInfinity);
+  __ Fmov(s24, kFP32NegativeInfinity);
+  __ Fmov(s25, 0.0);
+  __ Fmov(s26, -0.0);
+  __ Fmov(s27, -0.2);
+
+  __ Frintp(s0, s16);
+  __ Frintp(s1, s17);
+  __ Frintp(s2, s18);
+  __ Frintp(s3, s19);
+  __ Frintp(s4, s20);
+  __ Frintp(s5, s21);
+  __ Frintp(s6, s22);
+  __ Frintp(s7, s23);
+  __ Frintp(s8, s24);
+  __ Frintp(s9, s25);
+  __ Frintp(s10, s26);
+  __ Frintp(s11, s27);
+
+  __ Fmov(d16, -0.5);
+  __ Fmov(d17, -0.8);
+  __ Fmov(d18, 1.5);
+  __ Fmov(d19, 1.9);
+  __ Fmov(d20, 2.5);
+  __ Fmov(d21, -1.5);
+  __ Fmov(d22, -2.5);
+  __ Fmov(d23, kFP32PositiveInfinity);
+  __ Fmov(d24, kFP32NegativeInfinity);
+  __ Fmov(d25, 0.0);
+  __ Fmov(d26, -0.0);
+  __ Fmov(d27, -0.2);
+
+  __ Frintp(d12, d16);
+  __ Frintp(d13, d17);
+  __ Frintp(d14, d18);
+  __ Frintp(d15, d19);
+  __ Frintp(d16, d20);
+  __ Frintp(d17, d21);
+  __ Frintp(d18, d22);
+  __ Frintp(d19, d23);
+  __ Frintp(d20, d24);
+  __ Frintp(d21, d25);
+  __ Frintp(d22, d26);
+  __ Frintp(d23, d27);
+  END();
+
+  RUN();
+
+  CHECK_EQUAL_FP32(1.0, s0);
+  CHECK_EQUAL_FP32(2.0, s1);
+  CHECK_EQUAL_FP32(2.0, s2);
+  CHECK_EQUAL_FP32(2.0, s3);
+  CHECK_EQUAL_FP32(3.0, s4);
+  CHECK_EQUAL_FP32(-1.0, s5);
+  CHECK_EQUAL_FP32(-2.0, s6);
+  CHECK_EQUAL_FP32(kFP32PositiveInfinity, s7);
+  CHECK_EQUAL_FP32(kFP32NegativeInfinity, s8);
+  CHECK_EQUAL_FP32(0.0, s9);
+  CHECK_EQUAL_FP32(-0.0, s10);
+  CHECK_EQUAL_FP32(-0.0, s11);
+  CHECK_EQUAL_FP64(-0.0, d12);
+  CHECK_EQUAL_FP64(-0.0, d13);
+  CHECK_EQUAL_FP64(2.0, d14);
+  CHECK_EQUAL_FP64(2.0, d15);
+  CHECK_EQUAL_FP64(3.0, d16);
+  CHECK_EQUAL_FP64(-1.0, d17);
+  CHECK_EQUAL_FP64(-2.0, d18);
+  CHECK_EQUAL_FP64(kFP64PositiveInfinity, d19);
+  CHECK_EQUAL_FP64(kFP64NegativeInfinity, d20);
+  CHECK_EQUAL_FP64(0.0, d21);
+  CHECK_EQUAL_FP64(-0.0, d22);
+  CHECK_EQUAL_FP64(-0.0, d23);
+
+  TEARDOWN();
+}
+
+
 TEST(frintz) {
   INIT_V8();
   SETUP();
diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc
index e8c7f95..f59c3c4 100644
--- a/test/cctest/test-assembler-ia32.cc
+++ b/test/cctest/test-assembler-ia32.cc
@@ -170,11 +170,10 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-  // don't print the code - our disassembler can't handle cvttss2si
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
   F3 f = FUNCTION_CAST<F3>(code->entry());
   int res = f(static_cast<float>(-3.1415));
   ::printf("f() = %d\n", res);
@@ -200,11 +199,10 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-  // don't print the code - our disassembler can't handle cvttsd2si
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
   F4 f = FUNCTION_CAST<F4>(code->entry());
   int res = f(2.718281828);
   ::printf("f() = %d\n", res);
@@ -261,13 +259,9 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-#ifdef DEBUG
-  ::printf("\n---\n");
-  // don't print the code - our disassembler can't handle SSE instructions
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
 #endif
   F5 f = FUNCTION_CAST<F5>(code->entry());
   double res = f(2.2, 1.1);
@@ -595,4 +589,458 @@
 }
 
 
+typedef int (*F9)(double x, double y, double z);
+TEST(AssemblerX64FMA_sd) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
+    __ movsd(xmm1, Operand(esp, 3 * kPointerSize));
+    __ movsd(xmm2, Operand(esp, 5 * kPointerSize));
+    // argument in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    __ sub(esp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132sd
+    __ mov(eax, Immediate(1));  // Test number
+    __ movaps(xmm4, xmm0);
+    __ vfmadd132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmadd213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmadd231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmadd132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfmadd213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmadd231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfmsub132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmsub213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmsub231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmsub132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfmsub213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmsub231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmadd132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmadd213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmadd231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmadd132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfnmadd213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmadd231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmsub132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmsub213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmsub231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmsub132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfnmsub213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmsub231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xor_(eax, eax);
+    __ bind(&exit);
+    __ add(esp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F9 f = FUNCTION_CAST<F9>(code->entry());
+  CHECK_EQ(0, f(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
+}
+
+
+typedef int (*F10)(float x, float y, float z);
+TEST(AssemblerX64FMA_ss) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    __ movss(xmm0, Operand(esp, 1 * kPointerSize));
+    __ movss(xmm1, Operand(esp, 2 * kPointerSize));
+    __ movss(xmm2, Operand(esp, 3 * kPointerSize));
+    // arguments in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    __ sub(esp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132ss
+    __ mov(eax, Immediate(1));  // Test number
+    __ movaps(xmm4, xmm0);
+    __ vfmadd132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmadd213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmadd231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmadd132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfmadd213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmadd231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfmsub132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmsub213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmsub231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmsub132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfmsub213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmsub231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmadd132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmadd213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmadd231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmadd132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfnmadd213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmadd231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmsub132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmsub213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmsub231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmsub132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfnmsub213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmsub231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xor_(eax, eax);
+    __ bind(&exit);
+    __ add(esp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F10 f = FUNCTION_CAST<F10>(code->entry());
+  CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
+}
 #undef __
diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc
index 3d305b6..23d0be6 100644
--- a/test/cctest/test-assembler-x64.cc
+++ b/test/cctest/test-assembler-x64.cc
@@ -736,4 +736,454 @@
   F6 f = FUNCTION_CAST<F6>(code->entry());
   CHECK_EQ(2, f(1.0, 2.0));
 }
+
+
+typedef int (*F7)(double x, double y, double z);
+TEST(AssemblerX64FMA_sd) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    // argument in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    __ subq(rsp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132sd
+    __ movl(rax, Immediate(1));  // Test number
+    __ movaps(xmm8, xmm0);
+    __ vfmadd132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmadd213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmadd231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmadd132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfmadd213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmadd231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfmsub132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmsub213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmsub231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmsub132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfmsub213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmsub231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmadd132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmadd213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmadd231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmadd132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfnmadd213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmadd231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmsub132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmsub213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmsub231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmsub132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfnmsub213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmsub231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xorl(rax, rax);
+    __ bind(&exit);
+    __ addq(rsp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F7 f = FUNCTION_CAST<F7>(code->entry());
+  CHECK_EQ(0, f(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
+}
+
+
+typedef int (*F8)(float x, float y, float z);
+TEST(AssemblerX64FMA_ss) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    // arguments in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    __ subq(rsp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132ss
+    __ movl(rax, Immediate(1));  // Test number
+    __ movaps(xmm8, xmm0);
+    __ vfmadd132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmadd213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmadd231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmadd132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfmadd213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmadd231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfmsub132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmsub213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmsub231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmsub132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfmsub213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmsub231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmadd132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmadd213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmadd231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmadd132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfnmadd213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmadd231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmsub132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmsub213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmsub231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmsub132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfnmsub213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmsub231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xorl(rax, rax);
+    __ bind(&exit);
+    __ addq(rsp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F8 f = FUNCTION_CAST<F8>(code->entry());
+  CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
+}
 #undef __
diff --git a/test/cctest/test-ast.cc b/test/cctest/test-ast.cc
index 24819df..096d5c7 100644
--- a/test/cctest/test-ast.cc
+++ b/test/cctest/test-ast.cc
@@ -40,8 +40,8 @@
 
   Isolate* isolate = CcTest::i_isolate();
   Zone zone(isolate);
-  AstNode::IdGen id_gen;
-  AstNodeFactory<AstNullVisitor> factory(&zone, NULL, &id_gen);
+  AstValueFactory value_factory(&zone, 0);
+  AstNodeFactory factory(&value_factory);
   AstNode* node = factory.NewEmptyStatement(RelocInfo::kNoPosition);
   list->Add(node);
   CHECK_EQ(1, list->length());
diff --git a/test/cctest/test-dataflow.cc b/test/cctest/test-bit-vector.cc
similarity index 98%
rename from test/cctest/test-dataflow.cc
rename to test/cctest/test-bit-vector.cc
index 43d950d..ac00fab 100644
--- a/test/cctest/test-dataflow.cc
+++ b/test/cctest/test-bit-vector.cc
@@ -29,7 +29,7 @@
 
 #include "src/v8.h"
 
-#include "src/data-flow.h"
+#include "src/bit-vector.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
@@ -83,7 +83,7 @@
     BitVector v(15, &zone);
     v.Add(0);
     BitVector w(15, &zone);
-    w = v;
+    w.CopyFrom(v);
     CHECK(w.Contains(0));
     w.Add(1);
     BitVector u(w, &zone);
diff --git a/test/cctest/test-code-stubs-mips64.cc b/test/cctest/test-code-stubs-mips64.cc
index 025a8ba..1f7df38 100644
--- a/test/cctest/test-code-stubs-mips64.cc
+++ b/test/cctest/test-code-stubs-mips64.cc
@@ -104,7 +104,7 @@
   for (--reg_num; reg_num >= 2; --reg_num) {
     Register reg = Register::from_code(reg_num);
     if (!reg.is(destination_reg)) {
-      __ lw(at, MemOperand(sp, 0));
+      __ ld(at, MemOperand(sp, 0));
       __ Assert(eq, kRegisterWasClobbered, reg, Operand(at));
       __ Daddu(sp, sp, Operand(kPointerSize));
     }
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc
index 4d6e005..a05231e 100644
--- a/test/cctest/test-compiler.cc
+++ b/test/cctest/test-compiler.cc
@@ -306,12 +306,15 @@
   // We shouldn't have deoptimization support. We want to recompile and
   // verify that our feedback vector preserves information.
   CHECK(!f->shared()->has_deoptimization_support());
-  Handle<FixedArray> feedback_vector(f->shared()->feedback_vector());
+  Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
 
   // Verify that we gathered feedback.
-  int expected_count = FLAG_vector_ics ? 2 : 1;
-  CHECK_EQ(expected_count, feedback_vector->length());
-  CHECK(feedback_vector->get(expected_count - 1)->IsJSFunction());
+  int expected_slots = 0;
+  int expected_ic_slots = 1;
+  CHECK_EQ(expected_slots, feedback_vector->Slots());
+  CHECK_EQ(expected_ic_slots, feedback_vector->ICSlots());
+  FeedbackVectorICSlot slot_for_a(0);
+  CHECK(feedback_vector->Get(slot_for_a)->IsJSFunction());
 
   CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);");
 
@@ -319,8 +322,7 @@
   // of the full code.
   CHECK(f->IsOptimized());
   CHECK(f->shared()->has_deoptimization_support());
-  CHECK(f->shared()->feedback_vector()->
-        get(expected_count - 1)->IsJSFunction());
+  CHECK(f->shared()->feedback_vector()->Get(slot_for_a)->IsJSFunction());
 }
 
 
@@ -346,16 +348,19 @@
           *v8::Handle<v8::Function>::Cast(
               CcTest::global()->Get(v8_str("morphing_call"))));
 
-  int expected_count = FLAG_vector_ics ? 2 : 1;
-  CHECK_EQ(expected_count, f->shared()->feedback_vector()->length());
-  // And yet it's not compiled.
+  // Not compiled, and so no feedback vector allocated yet.
   CHECK(!f->shared()->is_compiled());
+  CHECK_EQ(0, f->shared()->feedback_vector()->Slots());
+  CHECK_EQ(0, f->shared()->feedback_vector()->ICSlots());
 
   CompileRun("morphing_call();");
 
-  // The vector should have the same size despite the new scoping.
-  CHECK_EQ(expected_count, f->shared()->feedback_vector()->length());
+  // Now a feedback vector is allocated.
   CHECK(f->shared()->is_compiled());
+  int expected_slots = 0;
+  int expected_ic_slots = FLAG_vector_ics ? 2 : 1;
+  CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots());
+  CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots());
 }
 
 
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 8d429d2..0e2dd91 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -1064,6 +1064,104 @@
 }
 
 
+// This tests checks distribution of the samples through the source lines.
+TEST(TickLines) {
+  CcTest::InitializeVM();
+  LocalContext env;
+  i::FLAG_turbo_source_positions = true;
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  i::HandleScope scope(isolate);
+
+  i::EmbeddedVector<char, 512> script;
+
+  const char* func_name = "func";
+  i::SNPrintF(script,
+              "function %s() {\n"
+              "  var n = 0;\n"
+              "  var m = 100*100;\n"
+              "  while (m > 1) {\n"
+              "    m--;\n"
+              "    n += m * m * m;\n"
+              "  }\n"
+              "}\n"
+              "%s();\n",
+              func_name, func_name);
+
+  CompileRun(script.start());
+
+  i::Handle<i::JSFunction> func = v8::Utils::OpenHandle(
+      *v8::Local<v8::Function>::Cast((*env)->Global()->Get(v8_str(func_name))));
+  CHECK_NE(NULL, func->shared());
+  CHECK_NE(NULL, func->shared()->code());
+  i::Code* code = NULL;
+  if (func->code()->is_optimized_code()) {
+    code = func->code();
+  } else {
+    CHECK(func->shared()->code() == func->code() || !i::FLAG_crankshaft);
+    code = func->shared()->code();
+  }
+  CHECK_NE(NULL, code);
+  i::Address code_address = code->instruction_start();
+  CHECK_NE(NULL, code_address);
+
+  CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
+  profiles->StartProfiling("", false);
+  ProfileGenerator generator(profiles);
+  ProfilerEventsProcessor* processor = new ProfilerEventsProcessor(
+      &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100));
+  processor->Start();
+  CpuProfiler profiler(isolate, profiles, &generator, processor);
+
+  // Enqueue code creation events.
+  i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
+  int line = 1;
+  int column = 1;
+  profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, code, func->shared(), NULL,
+                           *str, line, column);
+
+  // Enqueue a tick event to enable code events processing.
+  EnqueueTickSampleEvent(processor, code_address);
+
+  processor->StopSynchronously();
+
+  CpuProfile* profile = profiles->StopProfiling("");
+  CHECK_NE(NULL, profile);
+
+  // Check the state of profile generator.
+  CodeEntry* func_entry = generator.code_map()->FindEntry(code_address);
+  CHECK_NE(NULL, func_entry);
+  CHECK_EQ(func_name, func_entry->name());
+  const i::JITLineInfoTable* line_info = func_entry->line_info();
+  CHECK_NE(NULL, line_info);
+  CHECK(!line_info->empty());
+
+  // Check the hit source lines using V8 Public APIs.
+  const i::ProfileTree* tree = profile->top_down();
+  ProfileNode* root = tree->root();
+  CHECK_NE(NULL, root);
+  ProfileNode* func_node = root->FindChild(func_entry);
+  CHECK_NE(NULL, func_node);
+
+  // Add 10 faked ticks to source line #5.
+  int hit_line = 5;
+  int hit_count = 10;
+  for (int i = 0; i < hit_count; i++) func_node->IncrementLineTicks(hit_line);
+
+  unsigned int line_count = func_node->GetHitLineCount();
+  CHECK_EQ(2, line_count);  // Expect two hit source lines - #1 and #5.
+  ScopedVector<v8::CpuProfileNode::LineTick> entries(line_count);
+  CHECK(func_node->GetLineTicks(&entries[0], line_count));
+  int value = 0;
+  for (int i = 0; i < entries.length(); i++)
+    if (entries[i].line == hit_line) {
+      value = entries[i].hit_count;
+      break;
+    }
+  CHECK_EQ(hit_count, value);
+}
+
+
 static const char* call_function_test_source = "function bar(iterations) {\n"
 "}\n"
 "function start(duration) {\n"
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 2f0674a..c3c65fd 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -621,7 +621,7 @@
         last_function_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(result.As<v8::String>());
         function_name->WriteUtf8(last_function_hit);
       }
     }
@@ -656,7 +656,7 @@
         last_script_name_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> script_name(result->ToString());
+        v8::Handle<v8::String> script_name(result.As<v8::String>());
         script_name->WriteUtf8(last_script_name_hit);
       }
     }
@@ -775,7 +775,7 @@
       v8::Handle<v8::Value> result =
           evaluate_check_function->Call(exec_state, argc, argv);
       if (!result->IsTrue()) {
-        v8::String::Utf8Value utf8(checks[i].expected->ToString());
+        v8::String::Utf8Value utf8(checks[i].expected);
         V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *utf8);
       }
     }
@@ -849,7 +849,7 @@
     v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
                                                              argc, argv);
     CHECK(result->IsString());
-    v8::String::Utf8Value function_name(result->ToString());
+    v8::String::Utf8Value function_name(result->ToString(CcTest::isolate()));
     CHECK_EQ(1, StrLength(*function_name));
     CHECK_EQ((*function_name)[0],
               expected_step_sequence[break_point_hit_count]);
@@ -2860,7 +2860,7 @@
   foo->Call(env->Global(), kArgc, args);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(35, break_point_hit_count);
+  CHECK_EQ(45, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2908,7 +2908,7 @@
   foo->Call(env->Global(), kArgc, args);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(34, break_point_hit_count);
+  CHECK_EQ(44, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2952,7 +2952,7 @@
   foo->Call(env->Global(), 0, NULL);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(55, break_point_hit_count);
+  CHECK_EQ(65, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2995,9 +2995,7 @@
 
 
 // Test of the stepping mechanism for named load in a loop.
-TEST(DebugStepNamedStoreLoop) {
-  DoDebugStepNamedStoreLoop(24);
-}
+TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
 
 
 // Test the stepping mechanism with different ICs.
@@ -3330,14 +3328,14 @@
   break_point_hit_count = 0;
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   foo->Call(env->Global(), argc, argv_10);
-  CHECK_EQ(23, break_point_hit_count);
+  CHECK_EQ(45, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
   break_point_hit_count = 0;
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   foo->Call(env->Global(), argc, argv_100);
-  CHECK_EQ(203, break_point_hit_count);
+  CHECK_EQ(405, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3381,7 +3379,7 @@
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   result = foo->Call(env->Global(), argc, argv_10);
   CHECK_EQ(5, result->Int32Value());
-  CHECK_EQ(52, break_point_hit_count);
+  CHECK_EQ(62, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
@@ -3389,7 +3387,7 @@
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   result = foo->Call(env->Global(), argc, argv_100);
   CHECK_EQ(50, result->Int32Value());
-  CHECK_EQ(457, break_point_hit_count);
+  CHECK_EQ(557, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3434,7 +3432,7 @@
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   result = foo->Call(env->Global(), argc, argv_10);
   CHECK_EQ(9, result->Int32Value());
-  CHECK_EQ(55, break_point_hit_count);
+  CHECK_EQ(64, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
@@ -3442,7 +3440,7 @@
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   result = foo->Call(env->Global(), argc, argv_100);
   CHECK_EQ(99, result->Int32Value());
-  CHECK_EQ(505, break_point_hit_count);
+  CHECK_EQ(604, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3473,7 +3471,7 @@
   step_action = StepIn;
   break_point_hit_count = 0;
   foo->Call(env->Global(), 0, NULL);
-  CHECK_EQ(6, break_point_hit_count);
+  CHECK_EQ(8, break_point_hit_count);
 
   // Create a function for testing stepping. Run it to allow it to get
   // optimized.
@@ -3490,7 +3488,7 @@
   step_action = StepIn;
   break_point_hit_count = 0;
   foo->Call(env->Global(), 0, NULL);
-  CHECK_EQ(8, break_point_hit_count);
+  CHECK_EQ(10, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -4352,9 +4350,10 @@
 }
 
 
-static void NamedGetter(v8::Local<v8::String> name,
+static void NamedGetter(v8::Local<v8::Name> name,
                         const v8::PropertyCallbackInfo<v8::Value>& info) {
-  v8::String::Utf8Value n(name);
+  if (name->IsSymbol()) return;
+  v8::String::Utf8Value n(v8::Local<v8::String>::Cast(name));
   if (strcmp(*n, "a") == 0) {
     info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "AA"));
     return;
@@ -4387,26 +4386,26 @@
 
   // Create object with named interceptor.
   v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
-  named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
+  named->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedGetter, NULL, NULL, NULL, NamedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_named"),
       named->NewInstance());
 
   // Create object with indexed interceptor.
   v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
-  indexed->SetIndexedPropertyHandler(IndexedGetter,
-                                     NULL,
-                                     NULL,
-                                     NULL,
-                                     IndexedEnum);
+  indexed->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetter, NULL, NULL, NULL, IndexedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_indexed"),
       indexed->NewInstance());
 
   // Create object with both named and indexed interceptor.
   v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
-  both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
-  both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
+  both->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedGetter, NULL, NULL, NULL, NamedEnum));
+  both->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetter, NULL, NULL, NULL, IndexedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_both"),
       both->NewInstance());
@@ -5264,6 +5263,7 @@
 
     CompileRun(source);
   }
+  threaded_debugging_barriers.barrier_4.Wait();
   isolate_->Dispose();
 }
 
@@ -5285,6 +5285,7 @@
   threaded_debugging_barriers.barrier_2.Wait();
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
+  threaded_debugging_barriers.barrier_4.Wait();
 }
 
 
@@ -5388,6 +5389,7 @@
     breakpoints_barriers->barrier_2.Wait();
     CompileRun(source_2);
   }
+  breakpoints_barriers->barrier_4.Wait();
   isolate_->Dispose();
 }
 
@@ -5503,6 +5505,7 @@
   CHECK_EQ(116, evaluate_int_result);
   // 9: Continue evaluation of source2, reach end.
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer));
+  breakpoints_barriers->barrier_4.Wait();
 }
 
 
@@ -6157,7 +6160,8 @@
         last_function_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(
+            result->ToString(CcTest::isolate()));
         function_name->WriteUtf8(last_function_hit);
       }
     }
@@ -7040,7 +7044,8 @@
       if (!result->IsUndefined()) {
         char fn[80];
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(
+            result->ToString(CcTest::isolate()));
         function_name->WriteUtf8(fn);
         if (strcmp(fn, "bar") == 0) {
           i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
@@ -7105,12 +7110,12 @@
         v8::Handle<v8::Value> result =
             frame_function_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(result->ToString(isolate));
         CHECK(function_name->Equals(v8::String::NewFromUtf8(isolate, "loop")));
         // Get the name of the first argument in frame i.
         result = frame_argument_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> argument_name(result->ToString());
+        v8::Handle<v8::String> argument_name(result->ToString(isolate));
         CHECK(argument_name->Equals(v8::String::NewFromUtf8(isolate, "count")));
         // Get the value of the first argument in frame i. If the
         // funtion is optimized the value will be undefined, otherwise
@@ -7123,7 +7128,7 @@
         // Get the name of the first local variable.
         result = frame_local_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> local_name(result->ToString());
+        v8::Handle<v8::String> local_name(result->ToString(isolate));
         CHECK(local_name->Equals(v8::String::NewFromUtf8(isolate, "local")));
         // Get the value of the first local variable. If the function
         // is optimized the value will be undefined, otherwise it will
@@ -7518,3 +7523,159 @@
   CompileRun("while (true);");
   CHECK(try_catch.HasTerminated());
 }
+
+
+static void DebugEventExpectNoException(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  CHECK_NE(v8::Exception, event);
+}
+
+
+static void TryCatchWrappedThrowCallback(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  v8::TryCatch try_catch;
+  CompileRun("throw 'rejection';");
+  CHECK(try_catch.HasCaught());
+}
+
+
+TEST(DebugPromiseInterceptedByTryCatch) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventExpectNoException);
+  ChangeBreakOnException(false, true);
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
+  CompileRun(
+      "var r;"
+      "p.chain(function() { r = 'resolved'; },"
+      "        function() { r = 'rejected'; });");
+  CHECK(CompileRun("r")->Equals(v8_str("resolved")));
+}
+
+
+static int exception_event_counter = 0;
+
+
+static void DebugEventCountException(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  if (event == v8::Exception) exception_event_counter++;
+}
+
+
+static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  CompileRun("throw 'rejection';");
+}
+
+
+TEST(DebugPromiseRejectedByCallback) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventCountException);
+  ChangeBreakOnException(false, true);
+  exception_event_counter = 0;
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, ThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
+  CompileRun(
+      "var r;"
+      "p.chain(function() { r = 'resolved'; },"
+      "        function(e) { r = 'rejected' + e; });");
+  CHECK(CompileRun("r")->Equals(v8_str("rejectedrejection")));
+  CHECK_EQ(1, exception_event_counter);
+}
+
+
+TEST(DebugBreakOnExceptionInObserveCallback) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventCountException);
+  // Break on uncaught exception
+  ChangeBreakOnException(false, true);
+  exception_event_counter = 0;
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, ThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun(
+      "var obj = {};"
+      "var callbackRan = false;"
+      "Object.observe(obj, function() {"
+      "   callbackRan = true;"
+      "   throw Error('foo');"
+      "});"
+      "obj.prop = 1");
+  CHECK(CompileRun("callbackRan")->BooleanValue());
+  CHECK_EQ(1, exception_event_counter);
+}
+
+
+static void DebugHarmonyScopingListener(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  if (event != v8::Break) return;
+
+  int break_id = CcTest::i_isolate()->debug()->break_id();
+
+  char script[128];
+  i::Vector<char> script_vector(script, sizeof(script));
+  SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
+  ExpectInt32(script, 1);
+
+  SNPrintF(script_vector, "var frame = new FrameMirror(%d, 0);", break_id);
+  CompileRun(script);
+  ExpectInt32("frame.evaluate('x').value_", 1);
+  ExpectInt32("frame.evaluate('y').value_", 2);
+
+  CompileRun("var allScopes = frame.allScopes()");
+  ExpectInt32("allScopes.length", 2);
+
+  ExpectBoolean("allScopes[0].scopeType() === ScopeType.Script", true);
+
+  ExpectInt32("allScopes[0].scopeObject().value_.x", 1);
+
+  ExpectInt32("allScopes[0].scopeObject().value_.y", 2);
+
+  CompileRun("allScopes[0].setVariableValue('x', 5);");
+  CompileRun("allScopes[0].setVariableValue('y', 6);");
+  ExpectInt32("frame.evaluate('x + y').value_", 11);
+}
+
+
+TEST(DebugBreakInLexicalScopes) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(DebugHarmonyScopingListener);
+
+  CompileRun(
+      "'use strict';            \n"
+      "let x = 1;               \n");
+  ExpectInt32(
+      "'use strict';            \n"
+      "let y = 2;               \n"
+      "debugger;                \n"
+      "x * y",
+      30);
+  ExpectInt32(
+      "x = 1; y = 2; \n"
+      "debugger;"
+      "x * y",
+      30);
+}
diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc
index 34f0b69..06afdd2 100644
--- a/test/cctest/test-decls.cc
+++ b/test/cctest/test-decls.cc
@@ -70,9 +70,9 @@
   int query_count() const { return query_count_; }
 
  protected:
-  virtual v8::Handle<Value> Get(Local<String> key);
-  virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value);
-  virtual v8::Handle<Integer> Query(Local<String> key);
+  virtual v8::Handle<Value> Get(Local<Name> key);
+  virtual v8::Handle<Value> Set(Local<Name> key, Local<Value> value);
+  virtual v8::Handle<Integer> Query(Local<Name> key);
 
   void InitializeIfNeeded();
 
@@ -88,12 +88,11 @@
 
   // The handlers are called as static functions that forward
   // to the instance specific virtual methods.
-  static void HandleGet(Local<String> key,
+  static void HandleGet(Local<Name> key,
                         const v8::PropertyCallbackInfo<v8::Value>& info);
-  static void HandleSet(Local<String> key,
-                        Local<Value> value,
+  static void HandleSet(Local<Name> key, Local<Value> value,
                         const v8::PropertyCallbackInfo<v8::Value>& info);
-  static void HandleQuery(Local<String> key,
+  static void HandleQuery(Local<Name> key,
                           const v8::PropertyCallbackInfo<v8::Integer>& info);
 
   v8::Isolate* isolate() const { return CcTest::isolate(); }
@@ -122,11 +121,8 @@
   HandleScope scope(isolate);
   Local<FunctionTemplate> function = FunctionTemplate::New(isolate);
   Local<Value> data = External::New(CcTest::isolate(), this);
-  GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
-                                               &HandleSet,
-                                               &HandleQuery,
-                                               0, 0,
-                                               data);
+  GetHolder(function)->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      &HandleGet, &HandleSet, &HandleQuery, 0, 0, data));
   Local<Context> context = Context::New(isolate,
                                         0,
                                         function->InstanceTemplate(),
@@ -178,8 +174,7 @@
 
 
 void DeclarationContext::HandleGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->get_count_++;
   info.GetReturnValue().Set(context->Get(key));
@@ -187,8 +182,7 @@
 
 
 void DeclarationContext::HandleSet(
-    Local<String> key,
-    Local<Value> value,
+    Local<Name> key, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->set_count_++;
@@ -197,8 +191,7 @@
 
 
 void DeclarationContext::HandleQuery(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->query_count_++;
   info.GetReturnValue().Set(context->Query(key));
@@ -211,18 +204,17 @@
 }
 
 
-v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
+v8::Handle<Value> DeclarationContext::Get(Local<Name> key) {
   return v8::Handle<Value>();
 }
 
 
-v8::Handle<Value> DeclarationContext::Set(Local<String> key,
-                                          Local<Value> value) {
+v8::Handle<Value> DeclarationContext::Set(Local<Name> key, Local<Value> value) {
   return v8::Handle<Value>();
 }
 
 
-v8::Handle<Integer> DeclarationContext::Query(Local<String> key) {
+v8::Handle<Integer> DeclarationContext::Query(Local<Name> key) {
   return v8::Handle<Integer>();
 }
 
@@ -272,7 +264,7 @@
 
 class AbsentPropertyContext: public DeclarationContext {
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     return v8::Handle<Integer>();
   }
 };
@@ -336,7 +328,7 @@
   AppearingPropertyContext() : state_(DECLARE) { }
 
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     switch (state_) {
       case DECLARE:
         // Force declaration by returning that the
@@ -405,7 +397,7 @@
  public:
   ExistsInPrototypeContext() { InitializeIfNeeded(); }
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property exists in the prototype object.
     return Integer::New(isolate(), v8::None);
   }
@@ -464,7 +456,7 @@
 
 class AbsentInPrototypeContext: public DeclarationContext {
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property is absent in the prototype object.
     return Handle<Integer>();
   }
@@ -499,7 +491,7 @@
   }
 
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property exists in the hidden prototype object.
     return Integer::New(isolate(), v8::None);
   }
@@ -644,34 +636,212 @@
 }
 
 
-TEST(CrossScriptReferencesHarmony) {
+TEST(CrossScriptReferences_Simple) {
+  i::FLAG_harmony_scoping = true;
   i::FLAG_use_strict = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+
+  {
+    SimpleContext context;
+    context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1));
+    context.Check("let x = 5; x", EXPECT_EXCEPTION);
+  }
+}
+
+
+TEST(CrossScriptReferences_Simple2) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_use_strict = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+
+  for (int k = 0; k < 100; k++) {
+    SimpleContext context;
+    bool cond = (k % 2) == 0;
+    if (cond) {
+      context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1));
+      context.Check("let z = 4; z", EXPECT_RESULT, Number::New(isolate, 4));
+    } else {
+      context.Check("let z = 1; z", EXPECT_RESULT, Number::New(isolate, 1));
+      context.Check("let x = 4; x", EXPECT_RESULT, Number::New(isolate, 4));
+    }
+    context.Check("let y = 2; x", EXPECT_RESULT,
+                  Number::New(isolate, cond ? 1 : 4));
+  }
+}
+
+
+TEST(CrossScriptReferencesHarmony) {
   i::FLAG_harmony_scoping = true;
   i::FLAG_harmony_modules = true;
 
   v8::Isolate* isolate = CcTest::isolate();
   HandleScope scope(isolate);
 
+  // Check that simple cross-script global scope access works.
   const char* decs[] = {
-    "var x = 1; x", "x", "this.x",
-    "function x() { return 1 }; x()", "x()", "this.x()",
-    "let x = 1; x", "x", "this.x",
-    "const x = 1; x", "x", "this.x",
-    "module x { export let a = 1 }; x.a", "x.a", "this.x.a",
+    "'use strict'; var x = 1; x", "x",
+    "'use strict'; function x() { return 1 }; x()", "x()",
+    "'use strict'; let x = 1; x", "x",
+    "'use strict'; const x = 1; x", "x",
+    "'use strict'; module x { export let a = 1 }; x.a", "x.a",
     NULL
   };
 
-  for (int i = 0; decs[i] != NULL; i += 3) {
+  for (int i = 0; decs[i] != NULL; i += 2) {
     SimpleContext context;
     context.Check(decs[i], EXPECT_RESULT, Number::New(isolate, 1));
     context.Check(decs[i+1], EXPECT_RESULT, Number::New(isolate, 1));
-    // TODO(rossberg): The current ES6 draft spec does not reflect lexical
-    // bindings on the global object. However, this will probably change, in
-    // which case we reactivate the following test.
-    if (i/3 < 2) {
-      context.Check(decs[i+2], EXPECT_RESULT, Number::New(isolate, 1));
-    }
   }
+
+  // Check that cross-script global scope access works with late declarations.
+  {
+    SimpleContext context;
+    context.Check("function d0() { return x0 }",  // dynamic lookup
+                  EXPECT_RESULT, Undefined(isolate));
+    context.Check("this.x0 = -1;"
+                  "d0()",
+                  EXPECT_RESULT, Number::New(isolate, -1));
+    context.Check("'use strict';"
+                  "function f0() { let y = 10; return x0 + y }"
+                  "function g0() { let y = 10; return eval('x0 + y') }"
+                  "function h0() { let y = 10; return (1,eval)('x0') + y }"
+                  "x0 + f0() + g0() + h0()",
+                  EXPECT_RESULT, Number::New(isolate, 26));
+
+    context.Check("'use strict';"
+                  "let x1 = 1;"
+                  "function f1() { let y = 10; return x1 + y }"
+                  "function g1() { let y = 10; return eval('x1 + y') }"
+                  "function h1() { let y = 10; return (1,eval)('x1') + y }"
+                  "function i1() { "
+                  "  let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y"
+                  "}"
+                  "function j1() { let y = 10; return eval('x2 + y') }"
+                  "function k1() { let y = 10; return (1,eval)('x2') + y }"
+                  "function cl() { "
+                  "  let y = 10; "
+                  "  return { "
+                  "    f: function(){ return x1 + y },"
+                  "    g: function(){ return eval('x1 + y') },"
+                  "    h: function(){ return (1,eval)('x1') + y },"
+                  "    i: function(){"
+                  "      return (typeof x2 == 'undefined' ? 0 : 2) + y"
+                  "    },"
+                  "    j: function(){ return eval('x2 + y') },"
+                  "    k: function(){ return (1,eval)('x2') + y },"
+                  "  }"
+                  "}"
+                  "let o = cl();"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("o.f() + o.g() + o.h();",
+                  EXPECT_RESULT, Number::New(isolate, 33));
+    context.Check("i1() + o.i();",
+                  EXPECT_RESULT, Number::New(isolate, 20));
+
+    context.Check("'use strict';"
+                  "let x2 = 2;"
+                  "function f2() { let y = 20; return x2 + y }"
+                  "function g2() { let y = 20; return eval('x2 + y') }"
+                  "function h2() { let y = 20; return (1,eval)('x2') + y }"
+                  "function i2() { let y = 20; return x1 + y }"
+                  "function j2() { let y = 20; return eval('x1 + y') }"
+                  "function k2() { let y = 20; return (1,eval)('x1') + y }"
+                  "x2 + eval('x2') + (1,eval)('x2') + f2() + g2() + h2();",
+                  EXPECT_RESULT, Number::New(isolate, 72));
+    context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i1() + j1() + k1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i2() + j2() + k2();",
+                  EXPECT_RESULT, Number::New(isolate, 63));
+    context.Check("o.f() + o.g() + o.h();",
+                  EXPECT_RESULT, Number::New(isolate, 33));
+    context.Check("o.i() + o.j() + o.k();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i1() + o.i();",
+                  EXPECT_RESULT, Number::New(isolate, 24));
+
+    context.Check("'use strict';"
+                  "let x0 = 100;"
+                  "x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("delete this.x0;"
+                  "x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("this.x1 = 666;"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("delete this.x1;"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+  }
+
+  // Check that caching does respect scopes.
+  {
+    SimpleContext context;
+    const char* script1 = "(function(){ return y1 })()";
+    const char* script2 = "(function(){ return y2 })()";
+
+    context.Check(script1, EXPECT_EXCEPTION);
+    context.Check("this.y1 = 1; this.y2 = 2; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 1));
+    context.Check("'use strict'; let y1 = 3; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 3));
+    context.Check("y1 = 4;",
+                  EXPECT_RESULT, Number::New(isolate, 4));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 4));
+
+    context.Check(script2,
+                  EXPECT_RESULT, Number::New(isolate, 2));
+    context.Check("'use strict'; let y2 = 5; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 4));
+    context.Check(script2,
+                  EXPECT_RESULT, Number::New(isolate, 5));
+  }
+}
+
+
+TEST(GlobalLexicalOSR) {
+  i::FLAG_use_strict = true;
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_harmony_modules = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  SimpleContext context;
+
+  context.Check("'use strict';"
+                "let x = 1; x;",
+                EXPECT_RESULT, Number::New(isolate, 1));
+  context.Check("'use strict';"
+                "let y = 2*x;"
+                "++x;"
+                "let z = 0;"
+                "const limit = 100000;"
+                "for (var i = 0; i < limit; ++i) {"
+                "  z += x + y;"
+                "}"
+                "z;",
+                EXPECT_RESULT, Number::New(isolate, 400000));
 }
 
 
@@ -704,12 +874,280 @@
       SimpleContext context;
       context.Check(firsts[i], EXPECT_RESULT,
                     Number::New(CcTest::isolate(), 1));
-      // TODO(rossberg): All tests should actually be errors in Harmony,
-      // but we currently do not detect the cases where the first declaration
-      // is not lexical.
-      context.Check(seconds[j],
-                    i < 2 ? EXPECT_RESULT : EXPECT_ERROR,
-                    Number::New(CcTest::isolate(), 2));
+      bool success_case = i < 2 && j < 2;
+      Local<Value> success_result;
+      if (success_case) success_result = Number::New(CcTest::isolate(), 2);
+
+      context.Check(seconds[j], success_case ? EXPECT_RESULT : EXPECT_EXCEPTION,
+                    success_result);
     }
   }
 }
+
+
+TEST(CrossScriptDynamicLookup) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    Local<String> undefined_string = String::NewFromUtf8(
+        CcTest::isolate(), "undefined", String::kInternalizedString);
+    Local<String> number_string = String::NewFromUtf8(
+        CcTest::isolate(), "number", String::kInternalizedString);
+
+    context.Check(
+        "function f(o) { with(o) { return x; } }"
+        "function g(o) { with(o) { x = 15; } }"
+        "function h(o) { with(o) { return typeof x; } }",
+        EXPECT_RESULT, Undefined(CcTest::isolate()));
+    context.Check("h({})", EXPECT_RESULT, undefined_string);
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "f({})",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check(
+        "'use strict';"
+        "g({});0",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
+    context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+  }
+}
+
+
+TEST(CrossScriptGlobal) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+  {
+    SimpleContext context;
+
+    context.Check(
+        "var global = this;"
+        "global.x = 255;"
+        "x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 255));
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "global.x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 255));
+    context.Check("global.x = 15; x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 1));
+    context.Check("x = 221; global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "z = 15;"
+        "function f() { return z; };"
+        "for (var k = 0; k < 3; k++) { f(); }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let z = 5; f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    context.Check(
+        "function f() { konst = 10; return konst; };"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    context.Check(
+        "'use strict';"
+        "const konst = 255;"
+        "f()",
+        EXPECT_EXCEPTION);
+  }
+}
+
+
+TEST(CrossScriptStaticLookupUndeclared) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    Local<String> undefined_string = String::NewFromUtf8(
+        CcTest::isolate(), "undefined", String::kInternalizedString);
+    Local<String> number_string = String::NewFromUtf8(
+        CcTest::isolate(), "number", String::kInternalizedString);
+
+    context.Check(
+        "function f(o) { return x; }"
+        "function g(v) { x = v; }"
+        "function h(o) { return typeof x; }",
+        EXPECT_RESULT, Undefined(CcTest::isolate()));
+    context.Check("h({})", EXPECT_RESULT, undefined_string);
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "f({})",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check(
+        "'use strict';"
+        "g(15);x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+    context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+  }
+}
+
+
+TEST(CrossScriptLoadICs) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check(
+        "x = 15;"
+        "function f() { return x; }"
+        "function g() { return x; }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    for (int k = 0; k < 3; k++) {
+      context.Check("g()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(g); g()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+  }
+  {
+    SimpleContext context;
+    context.Check(
+        "x = 15;"
+        "function f() { return x; }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+  }
+}
+
+
+TEST(CrossScriptStoreICs) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check(
+        "var global = this;"
+        "x = 15;"
+        "function f(v) { x = v; }"
+        "function g(v) { x = v; }"
+        "f(10); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f(7); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 7));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("g(31); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 31));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(32); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 32));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    context.Check("%OptimizeFunctionOnNextCall(g); g(18); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 18));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    context.Check("%OptimizeFunctionOnNextCall(f); f(33); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 33));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+  }
+  {
+    SimpleContext context;
+    context.Check(
+        "var global = this;"
+        "x = 15;"
+        "function f(v) { x = v; }"
+        "f(10); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(18); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 18));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f(20); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f(8); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 8));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(13); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 13));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    context.Check("%OptimizeFunctionOnNextCall(f); f(41); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 41));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+  }
+}
+
+
+TEST(CrossScriptAssignmentToConst) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+
+    context.Check("function f() { x = 27; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    context.Check("'use strict';const x = 1; x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 1));
+    context.Check("f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check("f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check("%OptimizeFunctionOnNextCall(f);f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+  }
+}
diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc
index c1f6ce2..095c636 100644
--- a/test/cctest/test-disasm-arm.cc
+++ b/test/cctest/test-disasm-arm.cc
@@ -410,16 +410,40 @@
             "e6843895       pkhbt r3, r4, r5, lsl #17");
     COMPARE(pkhtb(r3, r4, Operand(r5, ASR, 17)),
             "e68438d5       pkhtb r3, r4, r5, asr #17");
-    COMPARE(uxtb(r9, Operand(r10, ROR, 0)),
-            "e6ef907a       uxtb r9, r10");
-    COMPARE(uxtb(r3, Operand(r4, ROR, 8)),
-            "e6ef3474       uxtb r3, r4, ror #8");
-    COMPARE(uxtab(r3, r4, Operand(r5, ROR, 8)),
-            "e6e43475       uxtab r3, r4, r5, ror #8");
-    COMPARE(uxtb16(r3, Operand(r4, ROR, 8)),
-            "e6cf3474       uxtb16 r3, r4, ror #8");
+
+    COMPARE(sxtb(r1, r7, 0, eq), "06af1077       sxtbeq r1, r7");
+    COMPARE(sxtb(r0, r0, 8, ne), "16af0470       sxtbne r0, r0, ror #8");
+    COMPARE(sxtb(r9, r10, 16), "e6af987a       sxtb r9, r10, ror #16");
+    COMPARE(sxtb(r4, r3, 24), "e6af4c73       sxtb r4, r3, ror #24");
+
+    COMPARE(sxtab(r3, r4, r5), "e6a43075       sxtab r3, r4, r5");
+
+    COMPARE(sxth(r5, r0), "e6bf5070       sxth r5, r0");
+    COMPARE(sxth(r5, r9, 8), "e6bf5479       sxth r5, r9, ror #8");
+    COMPARE(sxth(r5, r9, 16, hi), "86bf5879       sxthhi r5, r9, ror #16");
+    COMPARE(sxth(r8, r9, 24, cc), "36bf8c79       sxthcc r8, r9, ror #24");
+
+    COMPARE(sxtah(r3, r4, r5, 16), "e6b43875       sxtah r3, r4, r5, ror #16");
+
+    COMPARE(uxtb(r9, r10), "e6ef907a       uxtb r9, r10");
+    COMPARE(uxtb(r3, r4, 8), "e6ef3474       uxtb r3, r4, ror #8");
+
+    COMPARE(uxtab(r3, r4, r5, 8), "e6e43475       uxtab r3, r4, r5, ror #8");
+
+    COMPARE(uxtb16(r3, r4, 8), "e6cf3474       uxtb16 r3, r4, ror #8");
+
+    COMPARE(uxth(r9, r10), "e6ff907a       uxth r9, r10");
+    COMPARE(uxth(r3, r4, 8), "e6ff3474       uxth r3, r4, ror #8");
+
+    COMPARE(uxtah(r3, r4, r5, 24), "e6f43c75       uxtah r3, r4, r5, ror #24");
   }
 
+  COMPARE(smmla(r0, r1, r2, r3), "e7503211       smmla r0, r1, r2, r3");
+  COMPARE(smmla(r10, r9, r8, r7), "e75a7819       smmla r10, r9, r8, r7");
+
+  COMPARE(smmul(r0, r1, r2), "e750f211       smmul r0, r1, r2");
+  COMPARE(smmul(r8, r9, r10), "e758fa19       smmul r8, r9, r10");
+
   VERIFY_RUN();
 }
 
@@ -680,6 +704,30 @@
 }
 
 
+TEST(ARMv8_vrintX_disasm) {
+  SET_UP();
+
+  if (CpuFeatures::IsSupported(ARMv8)) {
+    COMPARE(vrinta(d0, d0), "feb80b40       vrinta.f64.f64 d0, d0");
+    COMPARE(vrinta(d2, d3), "feb82b43       vrinta.f64.f64 d2, d3");
+
+    COMPARE(vrintp(d0, d0), "feba0b40       vrintp.f64.f64 d0, d0");
+    COMPARE(vrintp(d2, d3), "feba2b43       vrintp.f64.f64 d2, d3");
+
+    COMPARE(vrintn(d0, d0), "feb90b40       vrintn.f64.f64 d0, d0");
+    COMPARE(vrintn(d2, d3), "feb92b43       vrintn.f64.f64 d2, d3");
+
+    COMPARE(vrintm(d0, d0), "febb0b40       vrintm.f64.f64 d0, d0");
+    COMPARE(vrintm(d2, d3), "febb2b43       vrintm.f64.f64 d2, d3");
+
+    COMPARE(vrintz(d0, d0), "eeb60bc0       vrintz.f64.f64 d0, d0");
+    COMPARE(vrintz(d2, d3, ne), "1eb62bc3       vrintzne.f64.f64 d2, d3");
+  }
+
+  VERIFY_RUN();
+}
+
+
 TEST(Neon) {
   SET_UP();
 
diff --git a/test/cctest/test-disasm-arm64.cc b/test/cctest/test-disasm-arm64.cc
index fb01347..208f1f5 100644
--- a/test/cctest/test-disasm-arm64.cc
+++ b/test/cctest/test-disasm-arm64.cc
@@ -1408,6 +1408,10 @@
   COMPARE(frintn(s31, s30), "frintn s31, s30");
   COMPARE(frintn(d12, d13), "frintn d12, d13");
   COMPARE(frintn(d31, d30), "frintn d31, d30");
+  COMPARE(frintp(s10, s11), "frintp s10, s11");
+  COMPARE(frintp(s31, s30), "frintp s31, s30");
+  COMPARE(frintp(d12, d13), "frintp d12, d13");
+  COMPARE(frintp(d31, d30), "frintp d31, d30");
   COMPARE(frintz(s10, s11), "frintz s10, s11");
   COMPARE(frintz(s31, s30), "frintz s31, s30");
   COMPARE(frintz(d12, d13), "frintz d12, d13");
diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc
index 49088f6..a2eaa15 100644
--- a/test/cctest/test-disasm-ia32.cc
+++ b/test/cctest/test-disasm-ia32.cc
@@ -51,7 +51,7 @@
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-  v8::internal::byte buffer[2048];
+  v8::internal::byte buffer[4096];
   Assembler assm(isolate, buffer, sizeof buffer);
   DummyStaticFunction(NULL);  // just bloody use it (DELETE; debugging)
 
@@ -201,6 +201,12 @@
   __ rcl(edx, 7);
   __ rcr(edx, 1);
   __ rcr(edx, 7);
+  __ ror(edx, 1);
+  __ ror(edx, 6);
+  __ ror_cl(edx);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 1);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 6);
+  __ ror_cl(Operand(ebx, ecx, times_4, 10000));
   __ sar(edx, 1);
   __ sar(edx, 6);
   __ sar_cl(edx);
@@ -383,6 +389,8 @@
     // Move operation
     __ movaps(xmm0, xmm1);
     __ shufps(xmm0, xmm0, 0x0);
+    __ cvtsd2ss(xmm0, xmm1);
+    __ cvtsd2ss(xmm0, Operand(ebx, ecx, times_4, 10000));
 
     // logic operation
     __ andps(xmm0, xmm1);
@@ -393,6 +401,14 @@
     __ xorps(xmm0, Operand(ebx, ecx, times_4, 10000));
 
     // Arithmetic operation
+    __ addss(xmm1, xmm0);
+    __ addss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ mulss(xmm1, xmm0);
+    __ mulss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ subss(xmm1, xmm0);
+    __ subss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ divss(xmm1, xmm0);
+    __ divss(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ addps(xmm1, xmm0);
     __ addps(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ subps(xmm1, xmm0);
@@ -401,10 +417,15 @@
     __ mulps(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ divps(xmm1, xmm0);
     __ divps(xmm1, Operand(ebx, ecx, times_4, 10000));
+
+    __ ucomiss(xmm0, xmm1);
+    __ ucomiss(xmm0, Operand(ebx, ecx, times_4, 10000));
   }
   {
     __ cvttss2si(edx, Operand(ebx, ecx, times_4, 10000));
     __ cvtsi2sd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ cvtss2sd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ cvtss2sd(xmm1, xmm0);
     __ movsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ movsd(Operand(ebx, ecx, times_4, 10000), xmm1);
     // 128 bit move instructions.
@@ -414,10 +435,13 @@
     __ movdqu(Operand(ebx, ecx, times_4, 10000), xmm0);
 
     __ addsd(xmm1, xmm0);
+    __ addsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ mulsd(xmm1, xmm0);
+    __ mulsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ subsd(xmm1, xmm0);
     __ subsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ divsd(xmm1, xmm0);
+    __ divsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ ucomisd(xmm0, xmm1);
     __ cmpltsd(xmm0, xmm1);
 
@@ -458,6 +482,83 @@
     }
   }
 
+  // AVX instruction
+  {
+    if (CpuFeatures::IsSupported(AVX)) {
+      CpuFeatureScope scope(&assm, AVX);
+      __ vaddsd(xmm0, xmm1, xmm2);
+      __ vaddsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vmulsd(xmm0, xmm1, xmm2);
+      __ vmulsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vsubsd(xmm0, xmm1, xmm2);
+      __ vsubsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vdivsd(xmm0, xmm1, xmm2);
+      __ vdivsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+    }
+  }
+
+  // FMA3 instruction
+  {
+    if (CpuFeatures::IsSupported(FMA3)) {
+      CpuFeatureScope scope(&assm, FMA3);
+      __ vfmadd132sd(xmm0, xmm1, xmm2);
+      __ vfmadd132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd213sd(xmm0, xmm1, xmm2);
+      __ vfmadd213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd231sd(xmm0, xmm1, xmm2);
+      __ vfmadd231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmsub132sd(xmm0, xmm1, xmm2);
+      __ vfmsub132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub213sd(xmm0, xmm1, xmm2);
+      __ vfmsub213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub231sd(xmm0, xmm1, xmm2);
+      __ vfmsub231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmadd132sd(xmm0, xmm1, xmm2);
+      __ vfnmadd132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd213sd(xmm0, xmm1, xmm2);
+      __ vfnmadd213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd231sd(xmm0, xmm1, xmm2);
+      __ vfnmadd231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmsub132sd(xmm0, xmm1, xmm2);
+      __ vfnmsub132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub213sd(xmm0, xmm1, xmm2);
+      __ vfnmsub213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub231sd(xmm0, xmm1, xmm2);
+      __ vfnmsub231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmadd132ss(xmm0, xmm1, xmm2);
+      __ vfmadd132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd213ss(xmm0, xmm1, xmm2);
+      __ vfmadd213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd231ss(xmm0, xmm1, xmm2);
+      __ vfmadd231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmsub132ss(xmm0, xmm1, xmm2);
+      __ vfmsub132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub213ss(xmm0, xmm1, xmm2);
+      __ vfmsub213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub231ss(xmm0, xmm1, xmm2);
+      __ vfmsub231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmadd132ss(xmm0, xmm1, xmm2);
+      __ vfnmadd132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd213ss(xmm0, xmm1, xmm2);
+      __ vfnmadd213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd231ss(xmm0, xmm1, xmm2);
+      __ vfnmadd231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmsub132ss(xmm0, xmm1, xmm2);
+      __ vfnmsub132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub213ss(xmm0, xmm1, xmm2);
+      __ vfnmsub213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub231ss(xmm0, xmm1, xmm2);
+      __ vfnmsub231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+    }
+  }
+
   // xchg.
   {
     __ xchg(eax, eax);
diff --git a/test/cctest/test-disasm-x64.cc b/test/cctest/test-disasm-x64.cc
index e756ce2..6cd58ec 100644
--- a/test/cctest/test-disasm-x64.cc
+++ b/test/cctest/test-disasm-x64.cc
@@ -51,7 +51,7 @@
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-  v8::internal::byte buffer[2048];
+  v8::internal::byte buffer[4096];
   Assembler assm(isolate, buffer, sizeof buffer);
   DummyStaticFunction(NULL);  // just bloody use it (DELETE; debugging)
 
@@ -117,6 +117,26 @@
   __ imulq(rdx, rcx);
   __ shld(rdx, rcx);
   __ shrd(rdx, rcx);
+  __ shlq(Operand(rdi, rax, times_4, 100), Immediate(1));
+  __ shlq(Operand(rdi, rax, times_4, 100), Immediate(6));
+  __ shlq(Operand(r15, 0), Immediate(1));
+  __ shlq(Operand(r15, 0), Immediate(6));
+  __ shlq_cl(Operand(r15, 0));
+  __ shlq_cl(Operand(r15, 0));
+  __ shlq_cl(Operand(rdi, rax, times_4, 100));
+  __ shlq_cl(Operand(rdi, rax, times_4, 100));
+  __ shlq(rdx, Immediate(1));
+  __ shlq(rdx, Immediate(6));
+  __ shll(Operand(rdi, rax, times_4, 100), Immediate(1));
+  __ shll(Operand(rdi, rax, times_4, 100), Immediate(6));
+  __ shll(Operand(r15, 0), Immediate(1));
+  __ shll(Operand(r15, 0), Immediate(6));
+  __ shll_cl(Operand(r15, 0));
+  __ shll_cl(Operand(r15, 0));
+  __ shll_cl(Operand(rdi, rax, times_4, 100));
+  __ shll_cl(Operand(rdi, rax, times_4, 100));
+  __ shll(rdx, Immediate(1));
+  __ shll(rdx, Immediate(6));
   __ bts(Operand(rdx, 0), rcx);
   __ bts(Operand(rbx, rcx, times_4, 0), rcx);
   __ nop();
@@ -159,14 +179,22 @@
 
   __ nop();
   __ idivq(rdx);
-  __ mul(rdx);
+  __ mull(rdx);
+  __ mulq(rdx);
   __ negq(rdx);
   __ notq(rdx);
   __ testq(Operand(rbx, rcx, times_4, 10000), rdx);
 
-  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000));
   __ imulq(rdx, rcx, Immediate(12));
   __ imulq(rdx, rcx, Immediate(1000));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000), Immediate(12));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000), Immediate(1000));
+  __ imull(r15, rcx, Immediate(12));
+  __ imull(r15, rcx, Immediate(1000));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000), Immediate(12));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000), Immediate(1000));
 
   __ incq(rdx);
   __ incq(Operand(rbx, rcx, times_4, 10000));
@@ -353,6 +381,8 @@
     // Move operation
     __ cvttss2si(rdx, Operand(rbx, rcx, times_4, 10000));
     __ cvttss2si(rdx, xmm1);
+    __ cvtsd2ss(xmm0, xmm1);
+    __ cvtsd2ss(xmm0, Operand(rbx, rcx, times_4, 10000));
     __ movaps(xmm0, xmm1);
 
     // logic operation
@@ -364,6 +394,14 @@
     __ xorps(xmm0, Operand(rbx, rcx, times_4, 10000));
 
     // Arithmetic operation
+    __ addss(xmm1, xmm0);
+    __ addss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ mulss(xmm1, xmm0);
+    __ mulss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ subss(xmm1, xmm0);
+    __ subss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ divss(xmm1, xmm0);
+    __ divss(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ addps(xmm1, xmm0);
     __ addps(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ subps(xmm1, xmm0);
@@ -372,6 +410,9 @@
     __ mulps(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ divps(xmm1, xmm0);
     __ divps(xmm1, Operand(rbx, rcx, times_4, 10000));
+
+    __ ucomiss(xmm0, xmm1);
+    __ ucomiss(xmm0, Operand(rbx, rcx, times_4, 10000));
   }
   // SSE 2 instructions
   {
@@ -379,6 +420,8 @@
     __ cvttsd2si(rdx, xmm1);
     __ cvttsd2siq(rdx, xmm1);
     __ cvttsd2siq(rdx, Operand(rbx, rcx, times_4, 10000));
+    __ cvtqsi2sd(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ cvtqsi2sd(xmm1, rdx);
     __ movsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ movsd(Operand(rbx, rcx, times_4, 10000), xmm1);
     // 128 bit move instructions.
@@ -386,12 +429,23 @@
     __ movdqa(Operand(rbx, rcx, times_4, 10000), xmm0);
 
     __ addsd(xmm1, xmm0);
+    __ addsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ mulsd(xmm1, xmm0);
+    __ mulsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ subsd(xmm1, xmm0);
+    __ subsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ divsd(xmm1, xmm0);
+    __ divsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ ucomisd(xmm0, xmm1);
 
     __ andpd(xmm0, xmm1);
+
+    __ pslld(xmm0, 6);
+    __ psrld(xmm0, 6);
+    __ psllq(xmm0, 6);
+    __ psrlq(xmm0, 6);
+
+    __ pcmpeqd(xmm1, xmm0);
   }
 
   // cmov.
@@ -421,6 +475,89 @@
     }
   }
 
+  // AVX instruction
+  {
+    if (CpuFeatures::IsSupported(AVX)) {
+      CpuFeatureScope scope(&assm, AVX);
+      __ vaddsd(xmm0, xmm1, xmm2);
+      __ vaddsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vmulsd(xmm0, xmm1, xmm2);
+      __ vmulsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vsubsd(xmm0, xmm1, xmm2);
+      __ vsubsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vdivsd(xmm0, xmm1, xmm2);
+      __ vdivsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+    }
+  }
+
+  // FMA3 instruction
+  {
+    if (CpuFeatures::IsSupported(FMA3)) {
+      CpuFeatureScope scope(&assm, FMA3);
+      __ vfmadd132sd(xmm0, xmm1, xmm2);
+      __ vfmadd132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd213sd(xmm0, xmm1, xmm2);
+      __ vfmadd213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd231sd(xmm0, xmm1, xmm2);
+      __ vfmadd231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmadd132sd(xmm9, xmm10, xmm11);
+      __ vfmadd132sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+      __ vfmadd213sd(xmm9, xmm10, xmm11);
+      __ vfmadd213sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+      __ vfmadd231sd(xmm9, xmm10, xmm11);
+      __ vfmadd231sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+
+      __ vfmsub132sd(xmm0, xmm1, xmm2);
+      __ vfmsub132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub213sd(xmm0, xmm1, xmm2);
+      __ vfmsub213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub231sd(xmm0, xmm1, xmm2);
+      __ vfmsub231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmadd132sd(xmm0, xmm1, xmm2);
+      __ vfnmadd132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd213sd(xmm0, xmm1, xmm2);
+      __ vfnmadd213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd231sd(xmm0, xmm1, xmm2);
+      __ vfnmadd231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmsub132sd(xmm0, xmm1, xmm2);
+      __ vfnmsub132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub213sd(xmm0, xmm1, xmm2);
+      __ vfnmsub213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub231sd(xmm0, xmm1, xmm2);
+      __ vfnmsub231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmadd132ss(xmm0, xmm1, xmm2);
+      __ vfmadd132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd213ss(xmm0, xmm1, xmm2);
+      __ vfmadd213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd231ss(xmm0, xmm1, xmm2);
+      __ vfmadd231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmsub132ss(xmm0, xmm1, xmm2);
+      __ vfmsub132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub213ss(xmm0, xmm1, xmm2);
+      __ vfmsub213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub231ss(xmm0, xmm1, xmm2);
+      __ vfmsub231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmadd132ss(xmm0, xmm1, xmm2);
+      __ vfnmadd132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd213ss(xmm0, xmm1, xmm2);
+      __ vfnmadd213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd231ss(xmm0, xmm1, xmm2);
+      __ vfnmadd231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmsub132ss(xmm0, xmm1, xmm2);
+      __ vfnmsub132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub213ss(xmm0, xmm1, xmm2);
+      __ vfnmsub213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub231ss(xmm0, xmm1, xmm2);
+      __ vfnmsub231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+    }
+  }
   // xchg.
   {
     __ xchgq(rax, rax);
diff --git a/test/cctest/test-disasm-x87.cc b/test/cctest/test-disasm-x87.cc
index 6cd33e5..e9b0dc5 100644
--- a/test/cctest/test-disasm-x87.cc
+++ b/test/cctest/test-disasm-x87.cc
@@ -201,6 +201,12 @@
   __ rcl(edx, 7);
   __ rcr(edx, 1);
   __ rcr(edx, 7);
+  __ ror(edx, 1);
+  __ ror(edx, 6);
+  __ ror_cl(edx);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 1);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 6);
+  __ ror_cl(Operand(ebx, ecx, times_4, 10000));
   __ sar(edx, 1);
   __ sar(edx, 6);
   __ sar_cl(edx);
diff --git a/test/cctest/test-feedback-vector.cc b/test/cctest/test-feedback-vector.cc
new file mode 100644
index 0000000..fa2f195
--- /dev/null
+++ b/test/cctest/test-feedback-vector.cc
@@ -0,0 +1,308 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/api.h"
+#include "src/debug.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "src/macro-assembler.h"
+#include "src/objects.h"
+
+using namespace v8::internal;
+
+namespace {
+
+TEST(VectorStructure) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  // Empty vectors are the empty fixed array.
+  FeedbackVectorSpec empty;
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(empty);
+  CHECK(Handle<FixedArray>::cast(vector)
+            .is_identical_to(factory->empty_fixed_array()));
+  // Which can nonetheless be queried.
+  CHECK_EQ(0, vector->ic_with_type_info_count());
+  CHECK_EQ(0, vector->ic_generic_count());
+  CHECK_EQ(0, vector->Slots());
+  CHECK_EQ(0, vector->ICSlots());
+
+  FeedbackVectorSpec one_slot(1, 0);
+  vector = factory->NewTypeFeedbackVector(one_slot);
+  CHECK_EQ(1, vector->Slots());
+  CHECK_EQ(0, vector->ICSlots());
+
+  FeedbackVectorSpec one_icslot(0, 1);
+  if (FLAG_vector_ics) {
+    one_icslot.SetKind(0, Code::CALL_IC);
+  }
+  vector = factory->NewTypeFeedbackVector(one_icslot);
+  CHECK_EQ(0, vector->Slots());
+  CHECK_EQ(1, vector->ICSlots());
+
+  FeedbackVectorSpec spec(3, 5);
+  if (FLAG_vector_ics) {
+    for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC);
+  }
+  vector = factory->NewTypeFeedbackVector(spec);
+  CHECK_EQ(3, vector->Slots());
+  CHECK_EQ(5, vector->ICSlots());
+
+  int metadata_length = vector->ic_metadata_length();
+  if (!FLAG_vector_ics) {
+    CHECK_EQ(0, metadata_length);
+  } else {
+    CHECK(metadata_length > 0);
+  }
+
+  int index = vector->GetIndex(FeedbackVectorSlot(0));
+
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
+  CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
+
+  index = vector->GetIndex(FeedbackVectorICSlot(0));
+  CHECK_EQ(index,
+           TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
+  CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
+
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
+           vector->length());
+}
+
+
+// IC slots need an encoding to recognize what is in there.
+TEST(VectorICMetadata) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  if (!FLAG_vector_ics) {
+    // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so
+    // there is no need for metadata to describe the slots.
+    return;
+  }
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  FeedbackVectorSpec spec(10, 3 * 10);
+  // Set metadata.
+  for (int i = 0; i < 30; i++) {
+    Code::Kind kind;
+    if (i % 3 == 0) {
+      kind = Code::CALL_IC;
+    } else if (i % 3 == 1) {
+      kind = Code::LOAD_IC;
+    } else {
+      kind = Code::KEYED_LOAD_IC;
+    }
+    spec.SetKind(i, kind);
+  }
+
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
+  CHECK_EQ(10, vector->Slots());
+  CHECK_EQ(3 * 10, vector->ICSlots());
+
+  // Meanwhile set some feedback values and type feedback values to
+  // verify the data structure remains intact.
+  vector->change_ic_with_type_info_count(100);
+  vector->change_ic_generic_count(3333);
+  vector->Set(FeedbackVectorSlot(0), *vector);
+
+  // Verify the metadata is correctly set up from the spec.
+  for (int i = 0; i < 30; i++) {
+    Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
+    if (i % 3 == 0) {
+      CHECK_EQ(Code::CALL_IC, kind);
+    } else if (i % 3 == 1) {
+      CHECK_EQ(Code::LOAD_IC, kind);
+    } else {
+      CHECK_EQ(Code::KEYED_LOAD_IC, kind);
+    }
+  }
+}
+
+
+TEST(VectorSlotClearing) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
+  // The reason is that FeedbackVectorICSlots need a full code environment
+  // to fully test (See VectorICProfilerStatistics test below).
+  FeedbackVectorSpec spec(5, 0);
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
+
+  // Fill with information
+  vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
+  vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map());
+  Handle<AllocationSite> site = factory->NewAllocationSite();
+  vector->Set(FeedbackVectorSlot(2), *site);
+
+  vector->ClearSlots(NULL);
+
+  // The feedback vector slots are cleared. AllocationSites are granted
+  // an exemption from clearing, as are smis.
+  CHECK_EQ(Smi::FromInt(1), vector->Get(FeedbackVectorSlot(0)));
+  CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate),
+           vector->Get(FeedbackVectorSlot(1)));
+  CHECK(vector->Get(FeedbackVectorSlot(2))->IsAllocationSite());
+}
+
+
+TEST(VectorICProfilerStatistics) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "function fun() {};"
+      "function f(a) { a(); } f(fun);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Code* code = f->shared()->code();
+  TypeFeedbackInfo* feedback_info =
+      TypeFeedbackInfo::cast(code->type_feedback_info());
+  CHECK_EQ(1, feedback_info->ic_total_count());
+  CHECK_EQ(0, feedback_info->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_info->ic_generic_count());
+  TypeFeedbackVector* feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  // Now send the information generic.
+  CompileRun("f(Object);");
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(1, feedback_vector->ic_generic_count());
+
+  // A collection will make the site uninitialized again.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  // The Array function is special. A call to array remains monomorphic
+  // and isn't cleared by gc because an AllocationSite is being held.
+  CompileRun("f(Array);");
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  int ic_slot = 0;
+  CHECK(
+      feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+  CHECK(
+      feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
+}
+
+
+TEST(VectorCallICStates) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "function foo() { return 17; }"
+      "function f(a) { a(); } f(foo);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Handle<TypeFeedbackVector> feedback_vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
+  FeedbackVectorICSlot slot(0);
+  CallICNexus nexus(feedback_vector, slot);
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  // CallIC doesn't return map feedback.
+  CHECK_EQ(NULL, nexus.FindFirstMap());
+
+  CompileRun("f(function() { return 16; })");
+  CHECK_EQ(GENERIC, nexus.StateFromFeedback());
+
+  // After a collection, state should be reset to UNINITIALIZED.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(UNINITIALIZED, nexus.StateFromFeedback());
+
+  // Array is special. It will remain monomorphic across gcs and it contains an
+  // AllocationSite.
+  CompileRun("f(Array)");
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot))->IsAllocationSite());
+
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+}
+
+
+TEST(VectorLoadICStates) {
+  if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "var o = { foo: 3 };"
+      "function f(a) { return a.foo; } f(o);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Handle<TypeFeedbackVector> feedback_vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
+  FeedbackVectorICSlot slot(0);
+  LoadICNexus nexus(feedback_vector, slot);
+  CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun("f(o)");
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  // Verify that the monomorphic map is the one we expect.
+  Handle<JSObject> o = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
+  CHECK_EQ(o->map(), nexus.FindFirstMap());
+
+  // Now go polymorphic.
+  CompileRun("f({ blarg: 3, foo: 2 })");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun(
+      "delete o.foo;"
+      "f(o)");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+  MapHandleList maps;
+  nexus.FindAllMaps(&maps);
+  CHECK_EQ(4, maps.length());
+
+  // Finally driven megamorphic.
+  CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
+  CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
+  CHECK_EQ(NULL, nexus.FindFirstMap());
+
+  // After a collection, state should not be reset to PREMONOMORPHIC.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
+}
+}
diff --git a/test/cctest/test-func-name-inference.cc b/test/cctest/test-func-name-inference.cc
index bc503b5..7f3dafc 100644
--- a/test/cctest/test-func-name-inference.cc
+++ b/test/cctest/test-func-name-inference.cc
@@ -30,7 +30,7 @@
 
 #include "src/api.h"
 #include "src/debug.h"
-#include "src/runtime.h"
+#include "src/string-search.h"
 #include "test/cctest/cctest.h"
 
 
@@ -46,13 +46,13 @@
 using ::v8::internal::SmartArrayPointer;
 using ::v8::internal::SharedFunctionInfo;
 using ::v8::internal::String;
+using ::v8::internal::Vector;
 
 
 static void CheckFunctionName(v8::Handle<v8::Script> script,
                               const char* func_pos_src,
                               const char* ref_inferred_name) {
   Isolate* isolate = CcTest::i_isolate();
-  Factory* factory = isolate->factory();
 
   // Get script source.
   Handle<Object> obj = v8::Utils::OpenHandle(*script);
@@ -69,12 +69,14 @@
   Handle<String> script_src(String::cast(i_script->source()));
 
   // Find the position of a given func source substring in the source.
-  Handle<String> func_pos_str =
-      factory->NewStringFromAsciiChecked(func_pos_src);
-  int func_pos = Runtime::StringMatch(isolate,
-                                      script_src,
-                                      func_pos_str,
-                                      0);
+  int func_pos;
+  {
+    i::DisallowHeapAllocation no_gc;
+    Vector<const uint8_t> func_pos_str = i::OneByteVector(func_pos_src);
+    String::FlatContent script_content = script_src->GetFlatContent();
+    func_pos = SearchString(isolate, script_content.ToOneByteVector(),
+                            func_pos_str, 0);
+  }
   CHECK_NE(0, func_pos);
 
   // Obtain SharedFunctionInfo for the function.
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 8f9b484..94a5be4 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -890,9 +890,10 @@
 }  // namespace
 
 TEST(HeapSnapshotJSONSerialization) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  v8::HandleScope scope(isolate);
+  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
 
 #define STRING_LITERAL_FOR_TEST \
   "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
@@ -923,7 +924,7 @@
 
   // Verify that snapshot object has required fields.
   v8::Local<v8::Object> parsed_snapshot =
-      env->Global()->Get(v8_str("parsed"))->ToObject();
+      env->Global()->Get(v8_str("parsed"))->ToObject(isolate);
   CHECK(parsed_snapshot->Has(v8_str("snapshot")));
   CHECK(parsed_snapshot->Has(v8_str("nodes")));
   CHECK(parsed_snapshot->Has(v8_str("edges")));
@@ -979,17 +980,18 @@
       "  \"s\", property_type)");
   CHECK(!string_obj_pos_val.IsEmpty());
   int string_obj_pos =
-      static_cast<int>(string_obj_pos_val->ToNumber()->Value());
+      static_cast<int>(string_obj_pos_val->ToNumber(isolate)->Value());
   v8::Local<v8::Object> nodes_array =
-      parsed_snapshot->Get(v8_str("nodes"))->ToObject();
+      parsed_snapshot->Get(v8_str("nodes"))->ToObject(isolate);
   int string_index = static_cast<int>(
-      nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
+      nodes_array->Get(string_obj_pos + 1)->ToNumber(isolate)->Value());
   CHECK_GT(string_index, 0);
   v8::Local<v8::Object> strings_array =
-      parsed_snapshot->Get(v8_str("strings"))->ToObject();
-  v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
+      parsed_snapshot->Get(v8_str("strings"))->ToObject(isolate);
+  v8::Local<v8::String> string =
+      strings_array->Get(string_index)->ToString(isolate);
   v8::Local<v8::String> ref_string =
-      CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
+      CompileRun(STRING_LITERAL_FOR_TEST)->ToString(isolate);
 #undef STRING_LITERAL_FOR_TEST
   CHECK_EQ(*v8::String::Utf8Value(ref_string),
            *v8::String::Utf8Value(string));
@@ -1719,9 +1721,6 @@
   const v8::HeapGraphNode* native_context =
       GetProperty(global, v8::HeapGraphEdge::kInternal, "native_context");
   CHECK_NE(NULL, native_context);
-  const v8::HeapGraphNode* global_context =
-      GetProperty(global, v8::HeapGraphEdge::kInternal, "global_context");
-  CHECK_NE(NULL, global_context);
   const v8::HeapGraphNode* global_proxy =
       GetProperty(global, v8::HeapGraphEdge::kInternal, "global_proxy");
   CHECK_NE(NULL, global_proxy);
@@ -1917,6 +1916,47 @@
 }
 
 
+TEST(FastCaseRedefinedAccessors) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+  CompileRun(
+      "var obj1 = {};\n"
+      "Object.defineProperty(obj1, 'prop', { "
+      "  get: function() { return 42; },\n"
+      "  set: function(value) { return this.prop_ = value; },\n"
+      "  configurable: true,\n"
+      "  enumerable: true,\n"
+      "});\n"
+      "Object.defineProperty(obj1, 'prop', { "
+      "  get: function() { return 153; },\n"
+      "  set: function(value) { return this.prop_ = value; },\n"
+      "  configurable: true,\n"
+      "  enumerable: true,\n"
+      "});\n");
+  v8::Local<v8::Object> js_global =
+      env->Global()->GetPrototype().As<v8::Object>();
+  i::Handle<i::JSObject> js_obj1 =
+      v8::Utils::OpenHandle(*js_global->Get(v8_str("obj1")).As<v8::Object>());
+  USE(js_obj1);
+
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  CHECK_NE(NULL, global);
+  const v8::HeapGraphNode* obj1 =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
+  CHECK_NE(NULL, obj1);
+  const v8::HeapGraphNode* func;
+  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get prop");
+  CHECK_NE(NULL, func);
+  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set prop");
+  CHECK_NE(NULL, func);
+}
+
+
 TEST(SlowCaseAccessors) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
@@ -1952,9 +1992,10 @@
 
 
 TEST(HiddenPropertiesFastCase) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  v8::HandleScope scope(isolate);
+  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
 
   CompileRun(
       "function C(x) { this.a = this; this.b = x; }\n"
@@ -1973,7 +2014,7 @@
   v8::Handle<v8::Value> cHandle =
       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"));
   CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
-  cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));
+  cHandle->ToObject(isolate)->SetHiddenValue(v8_str("key"), v8_str("val"));
 
   snapshot = heap_profiler->TakeHeapSnapshot(
       v8_str("HiddenPropertiesFastCase2"));
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index e526761..f8a7df2 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1375,6 +1375,98 @@
 }
 
 
+TEST(CompilationCacheCachingBehavior) {
+  // If we do not flush code, or have the compilation cache turned off, this
+  // test is invalid.
+  if (!FLAG_flush_code || !FLAG_flush_code_incrementally ||
+      !FLAG_compilation_cache) {
+    return;
+  }
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  Heap* heap = isolate->heap();
+  CompilationCache* compilation_cache = isolate->compilation_cache();
+
+  v8::HandleScope scope(CcTest::isolate());
+  const char* raw_source =
+      "function foo() {"
+      "  var x = 42;"
+      "  var y = 42;"
+      "  var z = x + y;"
+      "};"
+      "foo()";
+  Handle<String> source = factory->InternalizeUtf8String(raw_source);
+  Handle<Context> native_context = isolate->native_context();
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On first compilation, only a hash is inserted in the code cache. We can't
+  // find that value.
+  MaybeHandle<SharedFunctionInfo> info = compilation_cache->LookupScript(
+      source, Handle<Object>(), 0, 0, true, native_context);
+  CHECK(info.is_null());
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On second compilation, the hash is replaced by a real cache entry mapping
+  // the source to the shared function info containing the code.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(!info.is_null());
+
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+
+  // On second compilation, the hash is replaced by a real cache entry mapping
+  // the source to the shared function info containing the code.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(!info.is_null());
+
+  while (!info.ToHandleChecked()->code()->IsOld()) {
+    info.ToHandleChecked()->code()->MakeOlder(NO_MARKING_PARITY);
+  }
+
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+  // Ensure code aging cleared the entry from the cache.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On first compilation, only a hash is inserted in the code cache. We can't
+  // find that value.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+
+  for (int i = 0; i < CompilationCacheTable::kHashGenerations; i++) {
+    compilation_cache->MarkCompactPrologue();
+  }
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // If we aged the cache before caching the script, ensure that we didn't cache
+  // on next compilation.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+}
+
+
 // Count the number of native contexts in the weak list of native contexts.
 int CountNativeContexts() {
   int count = 0;
@@ -1487,7 +1579,7 @@
   }
 
   // Force compilation cache cleanup.
-  CcTest::heap()->NotifyContextDisposed();
+  CcTest::heap()->NotifyContextDisposed(true);
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   // Dispose the native contexts one by one.
@@ -1602,6 +1694,64 @@
 }
 
 
+TEST(TestSizeOfRegExpCode) {
+  if (!FLAG_regexp_optimization) return;
+
+  v8::V8::Initialize();
+
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+
+  LocalContext context;
+
+  // Adjust source below and this check to match
+  // RegExpImple::kRegExpTooLargeToOptimize.
+  DCHECK_EQ(i::RegExpImpl::kRegExpTooLargeToOptimize, 10 * KB);
+
+  // Compile a regexp that is much larger if we are using regexp optimizations.
+  CompileRun(
+      "var reg_exp_source = '(?:a|bc|def|ghij|klmno|pqrstu)';"
+      "var half_size_reg_exp;"
+      "while (reg_exp_source.length < 10 * 1024) {"
+      "  half_size_reg_exp = reg_exp_source;"
+      "  reg_exp_source = reg_exp_source + reg_exp_source;"
+      "}"
+      // Flatten string.
+      "reg_exp_source.match(/f/);");
+
+  // Get initial heap size after several full GCs, which will stabilize
+  // the heap size and return with sweeping finished completely.
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
+  if (collector->sweeping_in_progress()) {
+    collector->EnsureSweepingCompleted();
+  }
+  int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  CompileRun("'foo'.match(reg_exp_source);");
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  int size_with_regexp = static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  CompileRun("'foo'.match(half_size_reg_exp);");
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  int size_with_optimized_regexp =
+      static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  int size_of_regexp_code = size_with_regexp - initial_size;
+
+  CHECK_LE(size_of_regexp_code, 1 * MB);
+
+  // Small regexp is half the size, but compiles to more than twice the code
+  // due to the optimization steps.
+  CHECK_GE(size_with_optimized_regexp,
+           size_with_regexp + size_of_regexp_code * 2);
+}
+
+
 TEST(TestSizeOfObjects) {
   v8::V8::Initialize();
 
@@ -2183,6 +2333,48 @@
 }
 
 
+TEST(IdleNotificationFinishMarking) {
+  i::FLAG_allow_natives_syntax = true;
+  CcTest::InitializeVM();
+  SimulateFullSpace(CcTest::heap()->old_pointer_space());
+  IncrementalMarking* marking = CcTest::heap()->incremental_marking();
+  marking->Abort();
+  marking->Start();
+
+  CHECK_EQ(CcTest::heap()->gc_count(), 0);
+
+  // TODO(hpayer): We cannot write proper unit test right now for heap.
+  // The ideal test would call kMaxIdleMarkingDelayCounter to test the
+  // marking delay counter.
+
+  // Perform a huge incremental marking step but don't complete marking.
+  intptr_t bytes_processed = 0;
+  do {
+    bytes_processed =
+        marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
+                      IncrementalMarking::FORCE_MARKING,
+                      IncrementalMarking::DO_NOT_FORCE_COMPLETION);
+    CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
+  } while (bytes_processed);
+
+  // The next invocations of incremental marking are not going to complete
+  // marking
+  // since the completion threshold is not reached
+  for (size_t i = 0; i < IncrementalMarking::kMaxIdleMarkingDelayCounter - 2;
+       i++) {
+    marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
+                  IncrementalMarking::FORCE_MARKING,
+                  IncrementalMarking::DO_NOT_FORCE_COMPLETION);
+    CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
+  }
+
+  // The next idle notification has to finish incremental marking.
+  const int kLongIdleTime = 1000000;
+  CcTest::isolate()->IdleNotification(kLongIdleTime);
+  CHECK_EQ(CcTest::heap()->gc_count(), 1);
+}
+
+
 // Test that HAllocateObject will always return an object in new-space.
 TEST(OptimizedAllocationAlwaysInNewSpace) {
   i::FLAG_allow_natives_syntax = true;
@@ -2204,7 +2396,8 @@
       "f(1); f(2); f(3);"
       "%OptimizeFunctionOnNextCall(f);"
       "f(4);");
-  CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
+  CHECK_EQ(
+      4, res.As<v8::Object>()->GetRealNamedProperty(v8_str("x"))->Int32Value());
 
   Handle<JSObject> o =
       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
@@ -2342,12 +2535,21 @@
   FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
   FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
   CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1)));
-  CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
+  if (!o->IsUnboxedDoubleField(idx2)) {
+    CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
+  } else {
+    CHECK_EQ(1.1, o->RawFastDoublePropertyAt(idx2));
+  }
 
   JSObject* inner_object =
       reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
   CHECK(CcTest::heap()->InOldPointerSpace(inner_object));
-  CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
+  if (!inner_object->IsUnboxedDoubleField(idx1)) {
+    CHECK(
+        CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
+  } else {
+    CHECK_EQ(2.2, inner_object->RawFastDoublePropertyAt(idx1));
+  }
   CHECK(CcTest::heap()->InOldPointerSpace(
       inner_object->RawFastPropertyAt(idx2)));
 }
@@ -2806,6 +3008,7 @@
              "root = new F");
   root = GetByName("root");
   AddPropertyTo(2, root, "funny");
+  CcTest::heap()->CollectGarbage(NEW_SPACE);
 
   // Count number of live transitions after marking.  Note that one transition
   // is left, because 'o' still holds an instance of one transition target.
@@ -2832,6 +3035,7 @@
 
   root = GetByName("root");
   AddPropertyTo(2, root, "funny");
+  CcTest::heap()->CollectGarbage(NEW_SPACE);
 
   // Count number of live transitions after marking.  Note that one transition
   // is left, because 'o' still holds an instance of one transition target.
@@ -3076,7 +3280,7 @@
 
   OFStream os(stdout);
   g->shared()->Print(os);
-  os << endl;
+  os << std::endl;
 }
 #endif  // OBJECT_PRINT
 
@@ -3147,22 +3351,20 @@
 
   Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
 
-  int expected_length = FLAG_vector_ics ? 4 : 2;
-  CHECK_EQ(expected_length, feedback_vector->length());
-  for (int i = 0; i < expected_length; i++) {
-    if ((i % 2) == 1) {
-      CHECK(feedback_vector->get(i)->IsJSFunction());
-    }
-  }
+  int expected_slots = 2;
+  CHECK_EQ(expected_slots, feedback_vector->ICSlots());
+  int slot1 = 0;
+  int slot2 = 1;
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot1))->IsJSFunction());
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot2))->IsJSFunction());
 
   SimulateIncrementalMarking(CcTest::heap());
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
-  CHECK_EQ(expected_length, feedback_vector->length());
-  for (int i = 0; i < expected_length; i++) {
-    CHECK_EQ(feedback_vector->get(i),
-             *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
-  }
+  CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot1)),
+           *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
+  CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot2)),
+           *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
 }
 
 
@@ -3181,6 +3383,25 @@
 }
 
 
+static void CheckVectorIC(Handle<JSFunction> f, int ic_slot_index,
+                          InlineCacheState desired_state) {
+  Handle<TypeFeedbackVector> vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector());
+  FeedbackVectorICSlot slot(ic_slot_index);
+  LoadICNexus nexus(vector, slot);
+  CHECK(nexus.StateFromFeedback() == desired_state);
+}
+
+
+static void CheckVectorICCleared(Handle<JSFunction> f, int ic_slot_index) {
+  Handle<TypeFeedbackVector> vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector());
+  FeedbackVectorICSlot slot(ic_slot_index);
+  LoadICNexus nexus(vector, slot);
+  CHECK(IC::IsCleared(&nexus));
+}
+
+
 TEST(IncrementalMarkingPreservesMonomorphicIC) {
   if (i::FLAG_always_opt) return;
   CcTest::InitializeVM();
@@ -3196,13 +3417,23 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == MONOMORPHIC);
+  }
 
   SimulateIncrementalMarking(CcTest::heap());
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_after->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_after->ic_state() == MONOMORPHIC);
+  }
 }
 
 
@@ -3228,7 +3459,12 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == MONOMORPHIC);
+  }
 
   // Fire context dispose notification.
   CcTest::isolate()->ContextDisposedNotification();
@@ -3236,7 +3472,60 @@
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(IC::IsCleared(ic_after));
+  if (FLAG_vector_ics) {
+    CheckVectorICCleared(f, 0);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(IC::IsCleared(ic_after));
+  }
+}
+
+
+TEST(IncrementalMarkingPreservesPolymorphicIC) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Local<v8::Value> obj1, obj2;
+
+  {
+    LocalContext env;
+    CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
+    obj1 = env->Global()->Get(v8_str("obj"));
+  }
+
+  {
+    LocalContext env;
+    CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
+    obj2 = env->Global()->Get(v8_str("obj"));
+  }
+
+  // Prepare function f that contains a polymorphic IC for objects
+  // originating from two different native contexts.
+  CcTest::global()->Set(v8_str("obj1"), obj1);
+  CcTest::global()->Set(v8_str("obj2"), obj2);
+  CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+
+  Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == POLYMORPHIC);
+  }
+
+  // Fire context dispose notification.
+  SimulateIncrementalMarking(CcTest::heap());
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+
+  Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_after->ic_state() == POLYMORPHIC);
+  }
 }
 
 
@@ -3269,7 +3558,12 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == POLYMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == POLYMORPHIC);
+  }
 
   // Fire context dispose notification.
   CcTest::isolate()->ContextDisposedNotification();
@@ -3277,7 +3571,12 @@
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(IC::IsCleared(ic_after));
+  if (FLAG_vector_ics) {
+    CheckVectorICCleared(f, 0);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(IC::IsCleared(ic_after));
+  }
 }
 
 
@@ -4021,8 +4320,9 @@
                "bar%d();"
                "bar%d();"
                "bar%d();"
-               "%%OptimizeFunctionOnNextCall(bar%d);"
-               "bar%d();", i, i, i, i, i, i, i, i);
+               "%%OptimizeFwunctionOnNextCall(bar%d);"
+               "bar%d();",
+               i, i, i, i, i, i, i, i);
       CompileRun(source.start());
     }
     heap->CollectAllGarbage(i::Heap::kNoGCFlags);
@@ -4154,7 +4454,7 @@
   v8::Persistent<v8::Object> garbage;
   {
     v8::HandleScope scope(isolate);
-    garbage.Reset(isolate, CompileRun(source)->ToObject());
+    garbage.Reset(isolate, CompileRun(source)->ToObject(isolate));
   }
   weak_ic_cleared = false;
   garbage.SetWeak(static_cast<void*>(&garbage), &ClearWeakIC);
@@ -4181,6 +4481,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicLoadIC) {
+  CheckWeakness(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   loadIC(obj);"
+      "   loadIC(obj);"
+      "   loadIC(obj);"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   loadIC(poly);"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicKeyedLoadIC) {
   CheckWeakness("function keyedLoadIC(obj, field) {"
                 "  return obj[field];"
@@ -4196,6 +4515,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicKeyedLoadIC) {
+  CheckWeakness(
+      "function keyedLoadIC(obj, field) {"
+      "  return obj[field];"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   keyedLoadIC(obj, 'name');"
+      "   keyedLoadIC(obj, 'name');"
+      "   keyedLoadIC(obj, 'name');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   keyedLoadIC(poly, 'name');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicStoreIC) {
   CheckWeakness("function storeIC(obj, value) {"
                 "  obj.name = value;"
@@ -4211,6 +4549,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicStoreIC) {
+  CheckWeakness(
+      "function storeIC(obj, value) {"
+      "  obj.name = value;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   storeIC(obj, 'x');"
+      "   storeIC(obj, 'x');"
+      "   storeIC(obj, 'x');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   storeIC(poly, 'x');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicKeyedStoreIC) {
   CheckWeakness("function keyedStoreIC(obj, field, value) {"
                 "  obj[field] = value;"
@@ -4226,6 +4583,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicKeyedStoreIC) {
+  CheckWeakness(
+      "function keyedStoreIC(obj, field, value) {"
+      "  obj[field] = value;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   keyedStoreIC(obj, 'x');"
+      "   keyedStoreIC(obj, 'x');"
+      "   keyedStoreIC(obj, 'x');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   keyedStoreIC(poly, 'x');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicCompareNilIC) {
   CheckWeakness("function compareNilIC(obj) {"
                 "  return obj == null;"
@@ -4241,6 +4617,160 @@
 }
 
 
+Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) {
+  Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
+  Handle<Object> obj =
+      Object::GetProperty(isolate->global_object(), str).ToHandleChecked();
+  return Handle<JSFunction>::cast(obj);
+}
+
+
+void CheckIC(Code* code, Code::Kind kind, InlineCacheState state) {
+  Code* ic = FindFirstIC(code, kind);
+  CHECK(ic->is_inline_cache_stub());
+  CHECK(ic->ic_state() == state);
+}
+
+
+TEST(MonomorphicStaysMonomorphicAfterGC) {
+  if (FLAG_always_opt) return;
+  // TODO(mvstanton): vector ics need weak support!
+  if (FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  v8::HandleScope scope(CcTest::isolate());
+  CompileRun(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      "function testIC() {"
+      "  var proto = {'name' : 'weak'};"
+      "  var obj = Object.create(proto);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  return proto;"
+      "};");
+  Handle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC");
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC);
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC);
+}
+
+
+TEST(PolymorphicStaysPolymorphicAfterGC) {
+  if (FLAG_always_opt) return;
+  // TODO(mvstanton): vector ics need weak support!
+  if (FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  v8::HandleScope scope(CcTest::isolate());
+  CompileRun(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      "function testIC() {"
+      "  var proto = {'name' : 'weak'};"
+      "  var obj = Object.create(proto);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  var poly = Object.create(proto);"
+      "  poly.x = true;"
+      "  loadIC(poly);"
+      "  return proto;"
+      "};");
+  Handle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC");
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC);
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC);
+}
+
+
+TEST(WeakCell) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+  v8::internal::Factory* factory = isolate->factory();
+
+  HandleScope outer_scope(isolate);
+  Handle<WeakCell> weak_cell1;
+  {
+    HandleScope inner_scope(isolate);
+    Handle<HeapObject> value = factory->NewFixedArray(1, NOT_TENURED);
+    weak_cell1 = inner_scope.CloseAndEscape(factory->NewWeakCell(value));
+  }
+
+  Handle<FixedArray> survivor = factory->NewFixedArray(1, NOT_TENURED);
+  Handle<WeakCell> weak_cell2;
+  {
+    HandleScope inner_scope(isolate);
+    weak_cell2 = inner_scope.CloseAndEscape(factory->NewWeakCell(survivor));
+  }
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectGarbage(NEW_SPACE);
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectGarbage(NEW_SPACE);
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectAllAvailableGarbage();
+  CHECK(weak_cell1->cleared());
+  CHECK_EQ(*survivor, weak_cell2->value());
+}
+
+
+TEST(WeakCellsWithIncrementalMarking) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+  v8::internal::Factory* factory = isolate->factory();
+
+  const int N = 16;
+  HandleScope outer_scope(isolate);
+  Handle<FixedArray> survivor = factory->NewFixedArray(1, NOT_TENURED);
+  Handle<WeakCell> weak_cells[N];
+
+  for (int i = 0; i < N; i++) {
+    HandleScope inner_scope(isolate);
+    Handle<HeapObject> value =
+        i == 0 ? survivor : factory->NewFixedArray(1, NOT_TENURED);
+    Handle<WeakCell> weak_cell = factory->NewWeakCell(value);
+    CHECK(weak_cell->value()->IsFixedArray());
+    IncrementalMarking* marking = heap->incremental_marking();
+    if (marking->IsStopped()) marking->Start();
+    marking->Step(128, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+    heap->CollectGarbage(NEW_SPACE);
+    CHECK(weak_cell->value()->IsFixedArray());
+    weak_cells[i] = inner_scope.CloseAndEscape(weak_cell);
+  }
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+  CHECK_EQ(*survivor, weak_cells[0]->value());
+  for (int i = 1; i < N; i++) {
+    CHECK(weak_cells[i]->cleared());
+  }
+}
+
+
 #ifdef DEBUG
 TEST(AddInstructionChangesNewSpacePromotion) {
   i::FLAG_allow_natives_syntax = true;
@@ -4320,7 +4850,7 @@
   CcTest::InitializeVM();
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope hscope(isolate);
-  v8::Handle<v8::ObjectTemplate> global =v8::ObjectTemplate::New(isolate);
+  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
   global->Set(v8::String::NewFromUtf8(isolate, "interrupt"),
               v8::FunctionTemplate::New(isolate, RequestInterrupt));
   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
@@ -4333,7 +4863,7 @@
       "eval('function f() {' + locals + 'return function() { return v0; }; }');"
       "interrupt();"  // This triggers a fake stack overflow in f.
       "f()()");
-  CHECK_EQ(42.0, result->ToNumber()->Value());
+  CHECK_EQ(42.0, result->ToNumber(isolate)->Value());
 }
 
 
@@ -4502,6 +5032,63 @@
 }
 
 
+TEST(Regress3631) {
+  i::FLAG_expose_gc = true;
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  IncrementalMarking* marking = CcTest::heap()->incremental_marking();
+  v8::Local<v8::Value> result = CompileRun(
+      "var weak_map = new WeakMap();"
+      "var future_keys = [];"
+      "for (var i = 0; i < 50; i++) {"
+      "  var key = {'k' : i + 0.1};"
+      "  weak_map.set(key, 1);"
+      "  future_keys.push({'x' : i + 0.2});"
+      "}"
+      "weak_map");
+  if (marking->IsStopped()) {
+    marking->Start();
+  }
+  // Incrementally mark the backing store.
+  Handle<JSObject> obj =
+      v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
+  Handle<JSWeakCollection> weak_map(reinterpret_cast<JSWeakCollection*>(*obj));
+  while (!Marking::IsBlack(
+             Marking::MarkBitFrom(HeapObject::cast(weak_map->table()))) &&
+         !marking->IsStopped()) {
+    marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+  }
+  // Stash the backing store in a handle.
+  Handle<Object> save(weak_map->table(), isolate);
+  // The following line will update the backing store.
+  CompileRun(
+      "for (var i = 0; i < 50; i++) {"
+      "  weak_map.set(future_keys[i], i);"
+      "}");
+  heap->incremental_marking()->set_should_hurry(true);
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+}
+
+
+TEST(Regress442710) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  Factory* factory = isolate->factory();
+
+  HandleScope sc(isolate);
+  Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object());
+  Handle<JSArray> array = factory->NewJSArray(2);
+
+  Handle<String> name = factory->InternalizeUtf8String("testArray");
+  JSReceiver::SetProperty(global, name, array, SLOPPY).Check();
+  CompileRun("testArray[0] = 1; testArray[1] = 2; testArray.shift();");
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+}
+
+
 #ifdef DEBUG
 TEST(PathTracer) {
   CcTest::InitializeVM();
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
index ed315ce..dc5404e 100644
--- a/test/cctest/test-lockers.cc
+++ b/test/cctest/test-lockers.cc
@@ -141,6 +141,7 @@
 
   void Join() {
     semaphore_.Wait();
+    thread_.Join();
   }
 
   virtual void Run() = 0;
diff --git a/test/cctest/test-log-stack-tracer.cc b/test/cctest/test-log-stack-tracer.cc
index 334a201..714ad69 100644
--- a/test/cctest/test-log-stack-tracer.cc
+++ b/test/cctest/test-log-stack-tracer.cc
@@ -235,9 +235,9 @@
 
 static void CFuncDoTrace(byte dummy_parameter) {
   Address fp;
-#ifdef __GNUC__
+#if V8_HAS_BUILTIN_FRAME_ADDRESS
   fp = reinterpret_cast<Address>(__builtin_frame_address(0));
-#elif defined _MSC_VER
+#elif V8_CC_MSVC
   // Approximate a frame pointer address. We compile without base pointers,
   // so we can't trust ebp/rbp.
   fp = &dummy_parameter - 2 * sizeof(void*);  // NOLINT
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 482f89f..eee3e13 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -42,6 +42,7 @@
 #include "src/natives.h"
 #include "src/utils.h"
 #include "src/v8threads.h"
+#include "src/version.h"
 #include "src/vm-state-inl.h"
 #include "test/cctest/cctest.h"
 
@@ -477,10 +478,9 @@
         isolate, log.start(), v8::String::kNormalString, log.length());
     initialize_logger.env()->Global()->Set(v8_str("_log"), log_str);
 
-    i::Vector<const unsigned char> source = TestSources::GetScriptsSource();
+    i::Vector<const char> source = TestSources::GetScriptsSource();
     v8::Handle<v8::String> source_str = v8::String::NewFromUtf8(
-        isolate, reinterpret_cast<const char*>(source.start()),
-        v8::String::kNormalString, source.length());
+        isolate, source.start(), v8::String::kNormalString, source.length());
     v8::TryCatch try_catch;
     v8::Handle<v8::Script> script = CompileWithOrigin(source_str, "");
     if (script.IsEmpty()) {
@@ -496,7 +496,7 @@
     }
     // The result either be a "true" literal or problem description.
     if (!result->IsTrue()) {
-      v8::Local<v8::String> s = result->ToString();
+      v8::Local<v8::String> s = result->ToString(isolate);
       i::ScopedVector<char> data(s->Utf8Length() + 1);
       CHECK_NE(NULL, data.start());
       s->WriteUtf8(data.start());
@@ -508,3 +508,23 @@
   }
   isolate->Dispose();
 }
+
+
+TEST(LogVersion) {
+  v8::Isolate* isolate;
+  {
+    ScopedLoggerInitializer initialize_logger;
+    isolate = initialize_logger.isolate();
+    bool exists = false;
+    i::Vector<const char> log(
+        i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true));
+    CHECK(exists);
+    i::EmbeddedVector<char, 100> ref_data;
+    i::SNPrintF(ref_data, "v8-version,%d,%d,%d,%d,%d", i::Version::GetMajor(),
+                i::Version::GetMinor(), i::Version::GetBuild(),
+                i::Version::GetPatch(), i::Version::IsCandidate());
+    CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length()));
+    log.Dispose();
+  }
+  isolate->Dispose();
+}
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index c7d6531..64d995d 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -446,7 +446,7 @@
     bool write_permission = (buffer[position++] == 'w');
     CHECK(buffer[position] == '-' || buffer[position] == 'x');
     bool execute_permission = (buffer[position++] == 'x');
-    CHECK(buffer[position] == '-' || buffer[position] == 'p');
+    CHECK(buffer[position] == 's' || buffer[position] == 'p');
     bool private_mapping = (buffer[position++] == 'p');
     CHECK_EQ(buffer[position++], ' ');
     uintptr_t offset = ReadLong(buffer, &position, 16);
diff --git a/test/cctest/test-object-observe.cc b/test/cctest/test-object-observe.cc
index d208a26..2766a4f 100644
--- a/test/cctest/test-object-observe.cc
+++ b/test/cctest/test-object-observe.cc
@@ -130,6 +130,59 @@
 }
 
 
+TEST(DeliveryCallbackThrows) {
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
+  CompileRun(
+      "var obj = {};"
+      "var ordering = [];"
+      "function observer1() { ordering.push(1); };"
+      "function observer2() { ordering.push(2); };"
+      "function observer_throws() {"
+      "  ordering.push(0);"
+      "  throw new Error();"
+      "  ordering.push(-1);"
+      "};"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer2);"
+      "Object.observe(obj, observer_throws.bind());"
+      "obj.foo = 'bar';");
+  CHECK_EQ(5, CompileRun("ordering.length")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[0]")->Int32Value());
+  CHECK_EQ(1, CompileRun("ordering[1]")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[2]")->Int32Value());
+  CHECK_EQ(2, CompileRun("ordering[3]")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[4]")->Int32Value());
+}
+
+
+TEST(DeliveryChangesMutationInCallback) {
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
+  CompileRun(
+      "var obj = {};"
+      "var ordering = [];"
+      "function observer1(records) {"
+      "  ordering.push(100 + records.length);"
+      "  records.push(11);"
+      "  records.push(22);"
+      "};"
+      "function observer2(records) {"
+      "  ordering.push(200 + records.length);"
+      "  records.push(33);"
+      "  records.push(44);"
+      "};"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, observer2);"
+      "obj.foo = 'bar';");
+  CHECK_EQ(2, CompileRun("ordering.length")->Int32Value());
+  CHECK_EQ(101, CompileRun("ordering[0]")->Int32Value());
+  CHECK_EQ(201, CompileRun("ordering[1]")->Int32Value());
+}
+
+
 TEST(DeliveryOrderingReentrant) {
   HandleScope scope(CcTest::isolate());
   LocalContext context(CcTest::isolate());
@@ -709,3 +762,76 @@
   CcTest::isolate()->ContextDisposedNotification();
   CheckSurvivingGlobalObjectsCount(1);
 }
+
+
+static void ObserverCallback(const FunctionCallbackInfo<Value>& args) {
+  *static_cast<int*>(Handle<External>::Cast(args.Data())->Value()) =
+      Handle<Array>::Cast(args[0])->Length();
+}
+
+
+TEST(ObjectObserveCallsCppFunction) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  LocalContext context(isolate);
+  int numRecordsSent = 0;
+  Handle<Function> observer =
+      Function::New(CcTest::isolate(), ObserverCallback,
+                    External::New(isolate, &numRecordsSent));
+  context->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "observer"),
+                         observer);
+  CompileRun(
+      "var obj = {};"
+      "Object.observe(obj, observer);"
+      "obj.foo = 1;"
+      "obj.bar = 2;");
+  CHECK_EQ(2, numRecordsSent);
+}
+
+
+TEST(ObjectObserveCallsFunctionTemplateInstance) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  LocalContext context(isolate);
+  int numRecordsSent = 0;
+  Handle<FunctionTemplate> tmpl = FunctionTemplate::New(
+      isolate, ObserverCallback, External::New(isolate, &numRecordsSent));
+  context->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "observer"),
+                         tmpl->GetFunction());
+  CompileRun(
+      "var obj = {};"
+      "Object.observe(obj, observer);"
+      "obj.foo = 1;"
+      "obj.bar = 2;");
+  CHECK_EQ(2, numRecordsSent);
+}
+
+
+static void AccessorGetter(Local<String> property,
+                           const PropertyCallbackInfo<Value>& info) {
+  info.GetReturnValue().Set(Integer::New(info.GetIsolate(), 42));
+}
+
+
+static void AccessorSetter(Local<String> property, Local<Value> value,
+                           const PropertyCallbackInfo<void>& info) {
+  info.GetReturnValue().SetUndefined();
+}
+
+
+TEST(APIAccessorsShouldNotNotify) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope handle_scope(isolate);
+  LocalContext context(isolate);
+  Handle<Object> object = Object::New(isolate);
+  object->SetAccessor(String::NewFromUtf8(isolate, "accessor"), &AccessorGetter,
+                      &AccessorSetter);
+  context->Global()->Set(String::NewFromUtf8(isolate, "obj"), object);
+  CompileRun(
+      "var records = null;"
+      "Object.observe(obj, function(r) { records = r });"
+      "obj.accessor = 43;");
+  CHECK(CompileRun("records")->IsNull());
+  CompileRun("Object.defineProperty(obj, 'accessor', { value: 44 });");
+  CHECK(CompileRun("records")->IsNull());
+}
diff --git a/test/cctest/test-ostreams.cc b/test/cctest/test-ostreams.cc
deleted file mode 100644
index c83f96d..0000000
--- a/test/cctest/test-ostreams.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <string.h>
-#include <limits>
-
-#include "include/v8stdint.h"
-#include "src/ostreams.h"
-#include "test/cctest/cctest.h"
-
-using namespace v8::internal;
-
-
-TEST(OStringStreamConstructor) {
-  OStringStream oss;
-  const size_t expected_size = 0;
-  CHECK(expected_size == oss.size());
-  CHECK_GT(oss.capacity(), 0);
-  CHECK_NE(NULL, oss.data());
-  CHECK_EQ("", oss.c_str());
-}
-
-
-#define TEST_STRING            \
-  "Ash nazg durbatuluk, "      \
-  "ash nazg gimbatul, "        \
-  "ash nazg thrakatuluk, "     \
-  "agh burzum-ishi krimpatul."
-
-TEST(OStringStreamGrow) {
-  OStringStream oss;
-  const int repeat = 30;
-  size_t len = strlen(TEST_STRING);
-  for (int i = 0; i < repeat; ++i) {
-    oss.write(TEST_STRING, len);
-  }
-  const char* expected =
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING;
-  const size_t expected_len = len * repeat;
-  CHECK(expected_len == oss.size());
-  CHECK_GT(oss.capacity(), 0);
-  CHECK_EQ(0, strncmp(expected, oss.data(), expected_len));
-  CHECK_EQ(expected, oss.c_str());
-}
-
-
-template <class T>
-static void check(const char* expected, T value) {
-  OStringStream oss;
-  oss << value << " " << hex << value;
-  CHECK_EQ(expected, oss.c_str());
-}
-
-
-TEST(NumericFormatting) {
-  check<bool>("0 0", false);
-  check<bool>("1 1", true);
-
-  check<int16_t>("-12345 cfc7", -12345);
-  check<int16_t>("-32768 8000", std::numeric_limits<int16_t>::min());
-  check<int16_t>("32767 7fff", std::numeric_limits<int16_t>::max());
-
-  check<uint16_t>("34567 8707", 34567);
-  check<uint16_t>("0 0", std::numeric_limits<uint16_t>::min());
-  check<uint16_t>("65535 ffff", std::numeric_limits<uint16_t>::max());
-
-  check<int32_t>("-1234567 ffed2979", -1234567);
-  check<int32_t>("-2147483648 80000000", std::numeric_limits<int32_t>::min());
-  check<int32_t>("2147483647 7fffffff", std::numeric_limits<int32_t>::max());
-
-  check<uint32_t>("3456789 34bf15", 3456789);
-  check<uint32_t>("0 0", std::numeric_limits<uint32_t>::min());
-  check<uint32_t>("4294967295 ffffffff", std::numeric_limits<uint32_t>::max());
-
-  check<int64_t>("-1234567 ffffffffffed2979", -1234567);
-  check<int64_t>("-9223372036854775808 8000000000000000",
-                 std::numeric_limits<int64_t>::min());
-  check<int64_t>("9223372036854775807 7fffffffffffffff",
-                 std::numeric_limits<int64_t>::max());
-
-  check<uint64_t>("3456789 34bf15", 3456789);
-  check<uint64_t>("0 0", std::numeric_limits<uint64_t>::min());
-  check<uint64_t>("18446744073709551615 ffffffffffffffff",
-                  std::numeric_limits<uint64_t>::max());
-
-  check<float>("0 0", 0.0f);
-  check<float>("123 123", 123.0f);
-  check<float>("-0.5 -0.5", -0.5f);
-  check<float>("1.25 1.25", 1.25f);
-  check<float>("0.0625 0.0625", 6.25e-2f);
-
-  check<double>("0 0", 0.0);
-  check<double>("123 123", 123.0);
-  check<double>("-0.5 -0.5", -0.5);
-  check<double>("1.25 1.25", 1.25);
-  check<double>("0.0625 0.0625", 6.25e-2);
-}
-
-
-TEST(CharacterOutput) {
-  check<char>("a a", 'a');
-  check<signed char>("B B", 'B');
-  check<unsigned char>("9 9", '9');
-  check<const char*>("bye bye", "bye");
-
-  OStringStream os;
-  os.put('H').write("ello", 4);
-  CHECK_EQ("Hello", os.c_str());
-}
-
-
-TEST(Manipulators) {
-  OStringStream os;
-  os << 123 << hex << 123 << endl << 123 << dec << 123 << 123;
-  CHECK_EQ("1237b\n7b123123", os.c_str());
-}
-
-
-class MiscStuff {
- public:
-  MiscStuff(int i, double d, const char* s) : i_(i), d_(d), s_(s) { }
-
- private:
-  friend OStream& operator<<(OStream& os, const MiscStuff& m);
-
-  int i_;
-  double d_;
-  const char* s_;
-};
-
-
-OStream& operator<<(OStream& os, const MiscStuff& m) {
-  return os << "{i:" << m.i_ << ", d:" << m.d_ << ", s:'" << m.s_ << "'}";
-}
-
-
-TEST(CustomOutput) {
-  OStringStream os;
-  MiscStuff m(123, 4.5, "Hurz!");
-  os << m;
-  CHECK_EQ("{i:123, d:4.5, s:'Hurz!'}", os.c_str());
-}
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 72f2298..08caeab 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -31,6 +31,8 @@
 
 #include "src/v8.h"
 
+#include "src/ast.h"
+#include "src/ast-numbering.h"
 #include "src/ast-value-factory.h"
 #include "src/compiler.h"
 #include "src/execution.h"
@@ -317,8 +319,8 @@
 
     i::PreParser preparser(&scanner, &log, stack_limit);
     preparser.set_allow_lazy(true);
-    preparser.set_allow_natives_syntax(true);
-    preparser.set_allow_arrow_functions(true);
+    preparser.set_allow_natives(true);
+    preparser.set_allow_harmony_arrow_functions(true);
     i::PreParser::PreParseResult result = preparser.PreParseProgram();
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
     CHECK(!log.HasError());
@@ -452,14 +454,14 @@
   i::PreParser::PreParseResult result = preparser.PreParseProgram();
   CHECK_EQ(i::PreParser::kPreParseSuccess, result);
   i::ScriptData* sd = log.GetScriptData();
-  i::ParseData pd(sd);
-  pd.Initialize();
+  i::ParseData* pd = i::ParseData::FromCachedData(sd);
+  pd->Initialize();
 
   int first_function =
       static_cast<int>(strstr(program, "function") - program);
   int first_lbrace = first_function + i::StrLength("function () ");
   CHECK_EQ('{', program[first_lbrace]);
-  i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
+  i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace);
   CHECK(!entry1.is_valid());
 
   int second_function =
@@ -467,10 +469,11 @@
   int second_lbrace =
       second_function + i::StrLength("function () ");
   CHECK_EQ('{', program[second_lbrace]);
-  i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
+  i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
   CHECK(entry2.is_valid());
   CHECK_EQ('}', program[entry2.end_pos() - 1]);
   delete sd;
+  delete pd;
 }
 
 
@@ -496,7 +499,7 @@
 
   i::PreParser preparser(&scanner, &log, stack_limit);
   preparser.set_allow_lazy(true);
-  preparser.set_allow_arrow_functions(true);
+  preparser.set_allow_harmony_arrow_functions(true);
   i::PreParser::PreParseResult result = preparser.PreParseProgram();
   CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
 }
@@ -917,6 +920,142 @@
 }
 
 
+TEST(ScopeUsesArgumentsSuperThis) {
+  static const struct {
+    const char* prefix;
+    const char* suffix;
+  } surroundings[] = {
+    { "function f() {", "}" },
+    { "var f = () => {", "}" },
+  };
+
+  enum Expected {
+    NONE = 0,
+    ARGUMENTS = 1,
+    SUPER_PROPERTY = 2,
+    SUPER_CONSTRUCTOR_CALL = 4,
+    THIS = 8,
+    INNER_ARGUMENTS = 16,
+    INNER_SUPER_PROPERTY = 32,
+    INNER_SUPER_CONSTRUCTOR_CALL = 64,
+    INNER_THIS = 128
+  };
+
+  static const struct {
+    const char* body;
+    int expected;
+  } source_data[] = {
+        {"", NONE},
+        {"return this", THIS},
+        {"return arguments", ARGUMENTS},
+        {"return super()", SUPER_CONSTRUCTOR_CALL},
+        {"return super.x", SUPER_PROPERTY},
+        {"return arguments[0]", ARGUMENTS},
+        {"return this + arguments[0]", ARGUMENTS | THIS},
+        {"return this + arguments[0] + super.x",
+         ARGUMENTS | SUPER_PROPERTY | THIS},
+        {"return x => this + x", INNER_THIS},
+        {"return x => super() + x", INNER_SUPER_CONSTRUCTOR_CALL},
+        {"this.foo = 42;", THIS},
+        {"this.foo();", THIS},
+        {"if (foo()) { this.f() }", THIS},
+        {"if (foo()) { super.f() }", SUPER_PROPERTY},
+        {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
+        {"while (true) { this.f() }", THIS},
+        {"while (true) { super.f() }", SUPER_PROPERTY},
+        {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
+        // Multiple nesting levels must work as well.
+        {"while (true) { while (true) { while (true) return this } }", THIS},
+        {"while (true) { while (true) { while (true) return super() } }",
+         SUPER_CONSTRUCTOR_CALL},
+        {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
+        {"if (1) { return () => { while (true) new super() } }", NONE},
+        {"if (1) { return () => { while (true) new new super() } }", NONE},
+        // Note that propagation of the inner_uses_this() value does not
+        // cross boundaries of normal functions onto parent scopes.
+        {"return function (x) { return this + x }", NONE},
+        {"return function (x) { return super() + x }", NONE},
+        {"var x = function () { this.foo = 42 };", NONE},
+        {"var x = function () { super.foo = 42 };", NONE},
+        {"if (1) { return function () { while (true) new this() } }", NONE},
+        {"if (1) { return function () { while (true) new super() } }", NONE},
+        {"return function (x) { return () => this }", NONE},
+        {"return function (x) { return () => super() }", NONE},
+        // Flags must be correctly set when using block scoping.
+        {"\"use strict\"; while (true) { let x; this, arguments; }",
+         INNER_ARGUMENTS | INNER_THIS},
+        {"\"use strict\"; while (true) { let x; this, super(), arguments; }",
+         INNER_ARGUMENTS | INNER_SUPER_CONSTRUCTOR_CALL | INNER_THIS},
+        {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
+        {"\"use strict\"; if (foo()) { let x; super.f() }",
+         INNER_SUPER_PROPERTY},
+        {"\"use strict\"; if (1) {"
+         "  let x; return function () { return this + super() + arguments }"
+         "}",
+         NONE},
+    };
+
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+
+  v8::HandleScope handles(CcTest::isolate());
+  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
+  v8::Context::Scope context_scope(context);
+
+  isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
+                                        128 * 1024);
+
+  for (unsigned j = 0; j < arraysize(surroundings); ++j) {
+    for (unsigned i = 0; i < arraysize(source_data); ++i) {
+      int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
+                             i::StrLength(surroundings[j].suffix) +
+                             i::StrLength(source_data[i].body);
+      i::ScopedVector<char> program(kProgramByteSize + 1);
+      i::SNPrintF(program, "%s%s%s", surroundings[j].prefix,
+                  source_data[i].body, surroundings[j].suffix);
+      i::Handle<i::String> source =
+          factory->NewStringFromUtf8(i::CStrVector(program.start()))
+              .ToHandleChecked();
+      i::Handle<i::Script> script = factory->NewScript(source);
+      i::CompilationInfoWithZone info(script);
+      i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
+                                         isolate->heap()->HashSeed(),
+                                         isolate->unicode_cache()};
+      i::Parser parser(&info, &parse_info);
+      parser.set_allow_harmony_arrow_functions(true);
+      parser.set_allow_harmony_classes(true);
+      parser.set_allow_harmony_scoping(true);
+      info.MarkAsGlobal();
+      parser.Parse();
+      CHECK(i::Rewriter::Rewrite(&info));
+      CHECK(i::Scope::Analyze(&info));
+      CHECK(info.function() != NULL);
+
+      i::Scope* script_scope = info.function()->scope();
+      CHECK(script_scope->is_script_scope());
+      CHECK_EQ(1, script_scope->inner_scopes()->length());
+
+      i::Scope* scope = script_scope->inner_scopes()->at(0);
+      CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
+               scope->uses_arguments());
+      CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
+               scope->uses_super_property());
+      CHECK_EQ((source_data[i].expected & SUPER_CONSTRUCTOR_CALL) != 0,
+               scope->uses_super_constructor_call());
+      CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
+      CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
+               scope->inner_uses_arguments());
+      CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
+               scope->inner_uses_super_property());
+      CHECK_EQ((source_data[i].expected & INNER_SUPER_CONSTRUCTOR_CALL) != 0,
+               scope->inner_uses_super_constructor_call());
+      CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
+               scope->inner_uses_this());
+    }
+  }
+}
+
+
 TEST(ScopePositions) {
   v8::internal::FLAG_harmony_scoping = true;
 
@@ -974,11 +1113,10 @@
       "    infunction;\n"
       "  }", "\n"
       "  more;", i::FUNCTION_SCOPE, i::SLOPPY },
-    // TODO(aperez): Change to use i::ARROW_SCOPE when implemented
     { "  start;\n", "(a,b) => a + b", "; more;",
-      i::FUNCTION_SCOPE, i::SLOPPY },
+      i::ARROW_SCOPE, i::SLOPPY },
     { "  start;\n", "(a,b) => { return a+b; }", "\nmore;",
-      i::FUNCTION_SCOPE, i::SLOPPY },
+      i::ARROW_SCOPE, i::SLOPPY },
     { "  start;\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
       i::FUNCTION_SCOPE, i::SLOPPY },
@@ -1137,7 +1275,7 @@
     i::Parser parser(&info, &parse_info);
     parser.set_allow_lazy(true);
     parser.set_allow_harmony_scoping(true);
-    parser.set_allow_arrow_functions(true);
+    parser.set_allow_harmony_arrow_functions(true);
     info.MarkAsGlobal();
     info.SetStrictMode(source_data[i].strict_mode);
     parser.Parse();
@@ -1145,7 +1283,7 @@
 
     // Check scope types and positions.
     i::Scope* scope = info.function()->scope();
-    CHECK(scope->is_global_scope());
+    CHECK(scope->is_script_scope());
     CHECK_EQ(scope->start_position(), 0);
     CHECK_EQ(scope->end_position(), kProgramSize);
     CHECK_EQ(scope->inner_scopes()->length(), 1);
@@ -1211,13 +1349,16 @@
 
 enum ParserFlag {
   kAllowLazy,
-  kAllowNativesSyntax,
+  kAllowNatives,
   kAllowHarmonyScoping,
-  kAllowModules,
+  kAllowHarmonyModules,
   kAllowHarmonyNumericLiterals,
-  kAllowArrowFunctions,
-  kAllowClasses,
-  kAllowHarmonyObjectLiterals
+  kAllowHarmonyArrowFunctions,
+  kAllowHarmonyClasses,
+  kAllowHarmonyObjectLiterals,
+  kAllowHarmonyTemplates,
+  kAllowHarmonySloppy,
+  kAllowHarmonyUnicode
 };
 
 
@@ -1231,15 +1372,19 @@
 void SetParserFlags(i::ParserBase<Traits>* parser,
                     i::EnumSet<ParserFlag> flags) {
   parser->set_allow_lazy(flags.Contains(kAllowLazy));
-  parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
+  parser->set_allow_natives(flags.Contains(kAllowNatives));
   parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
-  parser->set_allow_modules(flags.Contains(kAllowModules));
+  parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules));
   parser->set_allow_harmony_numeric_literals(
       flags.Contains(kAllowHarmonyNumericLiterals));
   parser->set_allow_harmony_object_literals(
       flags.Contains(kAllowHarmonyObjectLiterals));
-  parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions));
-  parser->set_allow_classes(flags.Contains(kAllowClasses));
+  parser->set_allow_harmony_arrow_functions(
+      flags.Contains(kAllowHarmonyArrowFunctions));
+  parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
+  parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
+  parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
+  parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
 }
 
 
@@ -1250,6 +1395,8 @@
   i::Factory* factory = isolate->factory();
 
   uintptr_t stack_limit = isolate->stack_guard()->real_climit();
+  int preparser_materialized_literals = -1;
+  int parser_materialized_literals = -2;
 
   // Preparse the data.
   i::CompleteParserRecorder log;
@@ -1259,7 +1406,8 @@
     i::PreParser preparser(&scanner, &log, stack_limit);
     SetParserFlags(&preparser, flags);
     scanner.Initialize(&stream);
-    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    i::PreParser::PreParseResult result = preparser.PreParseProgram(
+        &preparser_materialized_literals);
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
   }
 
@@ -1278,6 +1426,9 @@
     info.MarkAsGlobal();
     parser.Parse();
     function = info.function();
+    if (function) {
+      parser_materialized_literals = function->materialized_literal_count();
+    }
   }
 
   // Check that preparsing fails iff parsing fails.
@@ -1343,6 +1494,15 @@
         "However, parser and preparser succeeded",
         source->ToCString().get());
     CHECK(false);
+  } else if (preparser_materialized_literals != parser_materialized_literals) {
+    v8::base::OS::Print(
+        "Preparser materialized literals (%d) differ from Parser materialized "
+        "literals (%d) on:\n"
+        "\t%s\n"
+        "However, parser and preparser succeeded",
+        preparser_materialized_literals, parser_materialized_literals,
+        source->ToCString().get());
+    CHECK(false);
   }
 }
 
@@ -1352,7 +1512,9 @@
                     size_t varying_flags_length,
                     ParserSyncTestResult result = kSuccessOrError,
                     const ParserFlag* always_true_flags = NULL,
-                    size_t always_true_flags_length = 0) {
+                    size_t always_true_flags_length = 0,
+                    const ParserFlag* always_false_flags = NULL,
+                    size_t always_false_flags_length = 0) {
   i::Handle<i::String> str =
       CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
   for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
@@ -1365,6 +1527,10 @@
          ++flag_index) {
       flags.Add(always_true_flags[flag_index]);
     }
+    for (size_t flag_index = 0; flag_index < always_false_flags_length;
+         ++flag_index) {
+      flags.Remove(always_false_flags[flag_index]);
+    }
     TestParserSyncWithFlags(str, flags, result);
   }
 }
@@ -1399,7 +1565,7 @@
     "if (false) {} else ;",
     "if (false) {} else {}",
     "if (false) {} else 12",
-    "if (false) ;"
+    "if (false) ;",
     "if (false) {}",
     "if (false) 12",
     "do {} while (false)",
@@ -1419,8 +1585,8 @@
     "with ({}) ;",
     "with ({}) {}",
     "with ({}) 12",
-    "switch ({}) { default: }"
-    "label3: "
+    "switch ({}) { default: }",
+    "label3: ",
     "throw",
     "throw  12",
     "throw\n12",
@@ -1447,16 +1613,6 @@
   CcTest::i_isolate()->stack_guard()->SetStackLimit(
       i::GetCurrentStackPosition() - 128 * 1024);
 
-  static const ParserFlag flags1[] = {
-    kAllowArrowFunctions,
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals,
-    kAllowHarmonyObjectLiterals,
-    kAllowHarmonyScoping,
-    kAllowLazy,
-    kAllowModules,
-  };
-
   for (int i = 0; context_data[i][0] != NULL; ++i) {
     for (int j = 0; statement_data[j] != NULL; ++j) {
       for (int k = 0; termination_data[k] != NULL; ++k) {
@@ -1476,7 +1632,7 @@
             termination_data[k],
             context_data[i][1]);
         CHECK(length == kProgramSize);
-        TestParserSync(program.start(), flags1, arraysize(flags1));
+        TestParserSync(program.start(), NULL, 0);
       }
     }
   }
@@ -1488,7 +1644,7 @@
   TestParserSync("0o1234", flags2, arraysize(flags2));
   TestParserSync("0b1011", flags2, arraysize(flags2));
 
-  static const ParserFlag flags3[] = { kAllowNativesSyntax };
+  static const ParserFlag flags3[] = { kAllowNatives };
   TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
 }
 
@@ -1522,7 +1678,9 @@
                        const ParserFlag* flags = NULL,
                        int flags_len = 0,
                        const ParserFlag* always_true_flags = NULL,
-                       int always_true_flags_len = 0) {
+                       int always_true_len = 0,
+                       const ParserFlag* always_false_flags = NULL,
+                       int always_false_len = 0) {
   v8::HandleScope handles(CcTest::isolate());
   v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
   v8::Context::Scope context_scope(context);
@@ -1530,36 +1688,32 @@
   CcTest::i_isolate()->stack_guard()->SetStackLimit(
       i::GetCurrentStackPosition() - 128 * 1024);
 
+  // Experimental feature flags should not go here; pass the flags as
+  // always_true_flags if the test needs them.
   static const ParserFlag default_flags[] = {
-    kAllowArrowFunctions,
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals,
-    kAllowHarmonyObjectLiterals,
-    kAllowHarmonyScoping,
     kAllowLazy,
-    kAllowModules,
-    kAllowNativesSyntax,
+    kAllowNatives,
   };
   ParserFlag* generated_flags = NULL;
   if (flags == NULL) {
     flags = default_flags;
     flags_len = arraysize(default_flags);
-    if (always_true_flags != NULL) {
-      // Remove always_true_flags from default_flags.
-      CHECK(always_true_flags_len < flags_len);
-      generated_flags = new ParserFlag[flags_len - always_true_flags_len];
+    if (always_true_flags != NULL || always_false_flags != NULL) {
+      // Remove always_true/false_flags from default_flags (if present).
+      CHECK((always_true_flags != NULL) == (always_true_len > 0));
+      CHECK((always_false_flags != NULL) == (always_false_len > 0));
+      generated_flags = new ParserFlag[flags_len + always_true_len];
       int flag_index = 0;
       for (int i = 0; i < flags_len; ++i) {
         bool use_flag = true;
-        for (int j = 0; j < always_true_flags_len; ++j) {
-          if (flags[i] == always_true_flags[j]) {
-            use_flag = false;
-            break;
-          }
+        for (int j = 0; use_flag && j < always_true_len; ++j) {
+          if (flags[i] == always_true_flags[j]) use_flag = false;
+        }
+        for (int j = 0; use_flag && j < always_false_len; ++j) {
+          if (flags[i] == always_false_flags[j]) use_flag = false;
         }
         if (use_flag) generated_flags[flag_index++] = flags[i];
       }
-      CHECK(flag_index == flags_len - always_true_flags_len);
       flags_len = flag_index;
       flags = generated_flags;
     }
@@ -1584,7 +1738,9 @@
                      flags_len,
                      result,
                      always_true_flags,
-                     always_true_flags_len);
+                     always_true_len,
+                     always_false_flags,
+                     always_false_len);
     }
   }
   delete[] generated_flags;
@@ -1691,45 +1847,70 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
 
 
+#define FUTURE_STRICT_RESERVED_WORDS(V) \
+  V(implements)                         \
+  V(interface)                          \
+  V(let)                                \
+  V(package)                            \
+  V(private)                            \
+  V(protected)                          \
+  V(public)                             \
+  V(static)                             \
+  V(yield)
+
+
+#define LIMITED_FUTURE_STRICT_RESERVED_WORDS(V) \
+  V(implements)                                 \
+  V(let)                                        \
+  V(static)                                     \
+  V(yield)
+
+
+#define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
+  "var " #NAME ";",                             \
+  "var foo, " #NAME ";",                        \
+  "try { } catch (" #NAME ") { }",              \
+  "function " #NAME "() { }",                   \
+  "(function " #NAME "() { })",                 \
+  "function foo(" #NAME ") { }",                \
+  "function foo(bar, " #NAME ") { }",           \
+  #NAME " = 1;",                                \
+  #NAME " += 1;",                               \
+  "var foo = " #NAME " = 1;",                   \
+  "++" #NAME ";",                               \
+  #NAME " ++;",
+
+
 TEST(ErrorsFutureStrictReservedWords) {
   // Tests that both preparsing and parsing produce the right kind of errors for
   // using future strict reserved words as identifiers. Without the strict mode,
   // it's ok to use future strict reserved words as identifiers. With the strict
   // mode, it isn't.
   const char* context_data[][2] = {
-    { "\"use strict\";", "" },
     { "function test_func() {\"use strict\"; ", "}"},
     { "() => { \"use strict\"; ", "}" },
     { NULL, NULL }
   };
 
-  const char* statement_data[] = {
-    "var interface;",
-    "var foo, interface;",
-    "try { } catch (interface) { }",
-    "function interface() { }",
-    "function foo(interface) { }",
-    "function foo(bar, interface) { }",
-    "interface = 1;",
-    "var foo = interface = 1;",
-    "++interface;",
-    "interface++;",
-    "var yield = 13;",
+  const char* statement_data[] {
+    LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
-  RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
-                    arraysize(always_flags));
+  RunParserSyncTest(context_data, statement_data, kError);
+  RunParserSyncTest(context_data, statement_data, kError);
 }
 
 
+#undef LIMITED_FUTURE_STRICT_RESERVED_WORDS
+
+
 TEST(NoErrorsFutureStrictReservedWords) {
   const char* context_data[][2] = {
     { "", "" },
@@ -1739,23 +1920,18 @@
   };
 
   const char* statement_data[] = {
-    "var interface;",
-    "var foo, interface;",
-    "try { } catch (interface) { }",
-    "function interface() { }",
-    "function foo(interface) { }",
-    "function foo(bar, interface) { }",
-    "interface = 1;",
-    "var foo = interface = 1;",
-    "++interface;",
-    "interface++;",
-    "var yield = 13;",
+    FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
+
+  static const ParserFlag classes_flags[] = {
+      kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    classes_flags, arraysize(classes_flags));
 }
 
 
@@ -2135,12 +2311,13 @@
     { NULL, NULL }
   };
 
+#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
   const char* statement_data[] = {
     "super: while(true) { break super; }",
-    "interface: while(true) { break interface; }",
-    "yield: while(true) { break yield; }",
+    FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
     NULL
   };
+#undef LABELLED_WHILE
 
   RunParserSyncTest(context_data, statement_data, kError);
 }
@@ -2165,7 +2342,28 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { "() => {", "}" },
+    { NULL, NULL }
+  };
+
+#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
+  const char* statement_data[] {
+    FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
+    NULL
+  };
+#undef LABELLED_WHILE
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -2285,17 +2483,18 @@
     i::ScriptData* sd = NULL;
     info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
     i::Parser::Parse(&info, true);
-    i::ParseData pd(sd);
+    i::ParseData* pd = i::ParseData::FromCachedData(sd);
 
-    if (pd.FunctionCount() != test_cases[i].functions) {
+    if (pd->FunctionCount() != test_cases[i].functions) {
       v8::base::OS::Print(
           "Expected preparse data for program:\n"
           "\t%s\n"
           "to contain %d functions, however, received %d functions.\n",
-          program, test_cases[i].functions, pd.FunctionCount());
+          program, test_cases[i].functions, pd->FunctionCount());
       CHECK(false);
     }
     delete sd;
+    delete pd;
   }
 }
 
@@ -2416,9 +2615,9 @@
     NULL
   };
 
-  // This test requires kAllowNativesSyntax to succeed.
+  // This test requires kAllowNatives to succeed.
   static const ParserFlag always_true_flags[] = {
-    kAllowNativesSyntax
+    kAllowNatives
   };
 
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
@@ -2904,11 +3103,11 @@
   const i::AstRawString* name = avf.GetOneByteString("result");
   i::Handle<i::String> str = name->string();
   CHECK(str->IsInternalizedString());
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   DCHECK(name != NULL);
 
   // Get result from h's function context (that is f's context)
@@ -2951,11 +3150,11 @@
   i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
   avf.Internalize(isolate);
 
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   const i::AstRawString* name_x = avf.GetOneByteString("x");
 
   // Get result from f's function context (that is g's outer context)
@@ -2998,11 +3197,11 @@
   i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
   avf.Internalize(isolate);
 
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   const i::AstRawString* name_x = avf.GetOneByteString("x");
   const i::AstRawString* name_f = avf.GetOneByteString("f");
   const i::AstRawString* name_y = avf.GetOneByteString("y");
@@ -3156,8 +3355,7 @@
           i::Parser parser(&info, &parse_info);
           parser.set_allow_harmony_scoping(true);
           CHECK(parser.Parse());
-          CHECK(i::Rewriter::Rewrite(&info));
-          CHECK(i::Scope::Analyze(&info));
+          CHECK(i::Compiler::Analyze(&info));
           CHECK(info.function() != NULL);
 
           i::Scope* scope = info.function()->scope();
@@ -3304,7 +3502,7 @@
 
   // The test is quite slow, so run it with a reduced set of flags.
   static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
-  static const ParserFlag always_flags[] = { kAllowArrowFunctions };
+  static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions };
   RunParserSyncTest(context_data, statement_data, kError, flags,
                     arraysize(flags), always_flags, arraysize(always_flags));
 }
@@ -3358,7 +3556,7 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3383,7 +3581,7 @@
     "z.super",  // Ok, property lookup.
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3402,7 +3600,7 @@
     "f(super)",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
   RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3585,7 +3783,8 @@
     "class name extends class base {} {}",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyClasses, kAllowHarmonySloppy};
   RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3604,7 +3803,8 @@
     "class name extends class base {} {}",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyClasses, kAllowHarmonySloppy};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3648,8 +3848,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3706,8 +3907,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3737,8 +3939,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3774,8 +3977,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyNumericLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3804,8 +4008,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_name, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3837,8 +4042,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_name, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3855,11 +4061,19 @@
     "static get prototype() {}",
     "static set prototype(_) {}",
     "static *prototype() {}",
+    "static 'prototype'() {}",
+    "static *'prototype'() {}",
+    "static prot\\u006ftype() {}",
+    "static 'prot\\u006ftype'() {}",
+    "static get 'prot\\u006ftype'() {}",
+    "static set 'prot\\u006ftype'(_) {}",
+    "static *'prot\\u006ftype'() {}",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3875,11 +4089,19 @@
     "get constructor() {}",
     "get constructor(_) {}",
     "*constructor() {}",
+    "get 'constructor'() {}",
+    "*'constructor'() {}",
+    "get c\\u006fnstructor() {}",
+    "*c\\u006fnstructor() {}",
+    "get 'c\\u006fnstructor'() {}",
+    "get 'c\\u006fnstructor'(_) {}",
+    "*'c\\u006fnstructor'() {}",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3900,8 +4122,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3909,9 +4132,6 @@
 
 
 TEST(ClassMultipleConstructorErrors) {
-  // We currently do not allow any duplicate properties in class bodies. This
-  // test ensures that when we change that we still throw on duplicate
-  // constructors.
   const char* context_data[][2] = {{"class C {", "}"},
                                    {"(class {", "});"},
                                    {NULL, NULL}};
@@ -3921,17 +4141,16 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
 
 
-// TODO(arv): We should allow duplicate property names.
-// https://code.google.com/p/v8/issues/detail?id=3570
-DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) {
+TEST(ClassMultiplePropertyNamesNoErrors) {
   const char* context_data[][2] = {{"class C {", "}"},
                                    {"(class {", "});"},
                                    {NULL, NULL}};
@@ -3940,11 +4159,14 @@
     "constructor() {}; static constructor() {}",
     "m() {}; static m() {}",
     "m() {}; m() {}",
+    "static m() {}; static m() {}",
+    "get m() {}; set m(_) {}; get m() {}; set m(_) {};",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3963,9 +4185,422 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
+
+
+TEST(ObjectLiteralPropertyShorthandKeywordsError) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {"'use strict'; ({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "break",
+    "case",
+    "catch",
+    "class",
+    "const",
+    "continue",
+    "debugger",
+    "default",
+    "delete",
+    "do",
+    "else",
+    "enum",
+    "export",
+    "extends",
+    "false",
+    "finally",
+    "for",
+    "function",
+    "if",
+    "import",
+    "in",
+    "instanceof",
+    "new",
+    "null",
+    "return",
+    "super",
+    "switch",
+    "this",
+    "throw",
+    "true",
+    "try",
+    "typeof",
+    "var",
+    "void",
+    "while",
+    "with",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandStrictKeywords) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "implements",
+    "interface",
+    "let",
+    "package",
+    "private",
+    "protected",
+    "public",
+    "static",
+    "yield",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+
+  const char* context_strict_data[][2] = {{"'use strict'; ({", "});"},
+                                          {NULL, NULL}};
+  RunParserSyncTest(context_strict_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandError) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {"'use strict'; ({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "1",
+    "1.2",
+    "0",
+    "0.1",
+    "1.0",
+    "1e1",
+    "0x1",
+    "\"s\"",
+    "'s'",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) {
+  const char* context_data[][2] = {{"", ""},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "function* g() { ({yield}); }",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ConstParsingInForIn) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "for(const x = 1; ; ) {}",
+      "for(const x = 1, y = 2;;){}",
+      "for(const x in [1,2,3]) {}",
+      "for(const x of [1,2,3]) {}",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ConstParsingInForInError) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "for(const x,y = 1; ; ) {}",
+      "for(const x = 4 in [1,2,3]) {}",
+      "for(const x = 4, y in [1,2,3]) {}",
+      "for(const x = 4 of [1,2,3]) {}",
+      "for(const x = 4, y of [1,2,3]) {}",
+      "for(const x = 1, y = 2 in []) {}",
+      "for(const x,y in []) {}",
+      "for(const x = 1, y = 2 of []) {}",
+      "for(const x,y of []) {}",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(InvalidUnicodeEscapes) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"'use strict';", ""},
+                                   {NULL, NULL}};
+  const char* data[] = {
+    "var foob\\u123r = 0;",
+    "var \\u123roo = 0;",
+    "\"foob\\u123rr\"",
+    // No escapes allowed in regexp flags
+    "/regex/\\u0069g",
+    "/regex/\\u006g",
+    // Braces gone wrong
+    "var foob\\u{c481r = 0;",
+    "var foob\\uc481}r = 0;",
+    "var \\u{0052oo = 0;",
+    "var \\u0052}oo = 0;",
+    "\"foob\\u{c481r\"",
+    "var foob\\u{}ar = 0;",
+    // Too high value for the unicode escape
+    "\"\\u{110000}\"",
+    // Not an unicode escape
+    "var foob\\v1234r = 0;",
+    "var foob\\U1234r = 0;",
+    "var foob\\v{1234}r = 0;",
+    "var foob\\U{1234}r = 0;",
+    NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(UnicodeEscapes) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"'use strict';", ""},
+                                   {NULL, NULL}};
+  const char* data[] = {
+    // Identifier starting with escape
+    "var \\u0052oo = 0;",
+    "var \\u{0052}oo = 0;",
+    "var \\u{52}oo = 0;",
+    "var \\u{00000000052}oo = 0;",
+    // Identifier with an escape but not starting with an escape
+    "var foob\\uc481r = 0;",
+    "var foob\\u{c481}r = 0;",
+    // String with an escape
+    "\"foob\\uc481r\"",
+    "\"foob\\{uc481}r\"",
+    // This character is a valid unicode character, representable as a surrogate
+    // pair, not representable as 4 hex digits.
+    "\"foo\\u{10e6d}\"",
+    // Max value for the unicode escape
+    "\"\\u{10ffff}\"",
+    NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "``",
+      "`no-subst-template`",
+      "`template-head${a}`",
+      "`${a}`",
+      "`${a}template-tail`",
+      "`template-head${a}template-tail`",
+      "`${a}${b}${c}`",
+      "`a${a}b${b}c${c}`",
+      "`${a}a${b}b${c}c`",
+      "`foo\n\nbar\r\nbaz`",
+      "`foo\n\n${  bar  }\r\nbaz`",
+      "`foo${a /* comment */}`",
+      "`foo${a // comment\n}`",
+      "`foo${a \n}`",
+      "`foo${a \r\n}`",
+      "`foo${a \r}`",
+      "`foo${/* comment */ a}`",
+      "`foo${// comment\na}`",
+      "`foo${\n a}`",
+      "`foo${\r\n a}`",
+      "`foo${\r a}`",
+      "`foo${'a' in a}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanTaggedTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  function tag() {}"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "tag ``",
+      "tag `no-subst-template`",
+      "tag`template-head${a}`",
+      "tag `${a}`",
+      "tag `${a}template-tail`",
+      "tag   `template-head${a}template-tail`",
+      "tag\n`${a}${b}${c}`",
+      "tag\r\n`a${a}b${b}c${c}`",
+      "tag    `${a}a${b}b${c}c`",
+      "tag\t`foo\n\nbar\r\nbaz`",
+      "tag\r`foo\n\n${  bar  }\r\nbaz`",
+      "tag`foo${a /* comment */}`",
+      "tag`foo${a // comment\n}`",
+      "tag`foo${a \n}`",
+      "tag`foo${a \r\n}`",
+      "tag`foo${a \r}`",
+      "tag`foo${/* comment */ a}`",
+      "tag`foo${// comment\na}`",
+      "tag`foo${\n a}`",
+      "tag`foo${\r\n a}`",
+      "tag`foo${\r a}`",
+      "tag`foo${'a' in a}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(TemplateMaterializedLiterals) {
+  const char* context_data[][2] = {
+    {
+      "'use strict';\n"
+      "function tag() {}\n"
+      "var a, b, c;\n"
+      "(", ")"
+    },
+    {NULL, NULL}
+  };
+
+  const char* data[] = {
+    "tag``",
+    "tag`a`",
+    "tag`a${1}b`",
+    "tag`a${1}b${2}c`",
+    "``",
+    "`a`",
+    "`a${1}b`",
+    "`a${1}b${2}c`",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanUnterminatedTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "`no-subst-template",
+      "`template-head${a}",
+      "`${a}template-tail",
+      "`template-head${a}template-tail",
+      "`${a}${b}${c}",
+      "`a${a}b${b}c${c}",
+      "`${a}a${b}b${c}c",
+      "`foo\n\nbar\r\nbaz",
+      "`foo\n\n${  bar  }\r\nbaz",
+      "`foo${a /* comment } */`",
+      "`foo${a /* comment } `*/",
+      "`foo${a // comment}`",
+      "`foo${a \n`",
+      "`foo${a \r\n`",
+      "`foo${a \r`",
+      "`foo${/* comment */ a`",
+      "`foo${// commenta}`",
+      "`foo${\n a`",
+      "`foo${\r\n a`",
+      "`foo${\r a`",
+      "`foo${fn(}`",
+      "`foo${1 if}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(TemplateLiteralsIllegalTokens) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+  const char* data[] = {
+      "`hello\\x`",
+      "`hello\\x${1}`",
+      "`hello${1}\\x`",
+      "`hello${1}\\x${2}`",
+      "`hello\\x\n`",
+      "`hello\\x\n${1}`",
+      "`hello${1}\\x\n`",
+      "`hello${1}\\x\n${2}`",
+      NULL};
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(LexicalScopingSloppyMode) {
+  const char* context_data[][2] = {
+      {"", ""},
+      {"function f() {", "}"},
+      {"{", "}"},
+      {NULL, NULL}};
+  const char* bad_data[] = {
+    "let x = 1;",
+    "for(let x = 1;;){}",
+    "for(let x of []){}",
+    "for(let x in []){}",
+    "class C {}",
+    "class C extends D {}",
+    "(class {})",
+    "(class extends D {})",
+    "(class C {})",
+    "(class C extends D {})",
+    NULL};
+  static const ParserFlag always_true_flags[] = {
+      kAllowHarmonyScoping, kAllowHarmonyClasses};
+  static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy};
+  RunParserSyncTest(context_data, bad_data, kError, NULL, 0,
+                    always_true_flags, arraysize(always_true_flags),
+                    always_false_flags, arraysize(always_false_flags));
+
+  const char* good_data[] = {
+    "let = 1;",
+    "for(let = 1;;){}",
+    NULL};
+  RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0,
+                    always_true_flags, arraysize(always_true_flags),
+                    always_false_flags, arraysize(always_false_flags));
+}
diff --git a/test/cctest/test-platform.cc b/test/cctest/test-platform.cc
index 100a5a7..90926d1 100644
--- a/test/cctest/test-platform.cc
+++ b/test/cctest/test-platform.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/base/build_config.h"
 #include "src/base/platform/platform.h"
 #include "test/cctest/cctest.h"
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index 9d1d52e..4a572c8 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -25,8 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
-#include <stdlib.h>
+#include <cstdlib>
+#include <sstream>
 
 #include "src/v8.h"
 
@@ -103,9 +103,9 @@
       &reader, false, &result, &zone));
   CHECK(result.tree != NULL);
   CHECK(result.error.is_null());
-  OStringStream os;
+  std::ostringstream os;
   result.tree->Print(os, &zone);
-  CHECK_EQ(expected, os.c_str());
+  CHECK_EQ(expected, os.str().c_str());
 }
 
 
@@ -435,11 +435,11 @@
   // Check that we don't allow more than kMaxCapture captures
   const int kMaxCaptures = 1 << 16;  // Must match RegExpParser::kMaxCaptures.
   const char* kTooManyCaptures = "Too many captures";
-  OStringStream os;
+  std::ostringstream os;
   for (int i = 0; i <= kMaxCaptures; i++) {
     os << "()";
   }
-  ExpectError(os.c_str(), kTooManyCaptures);
+  ExpectError(os.str().c_str(), kTooManyCaptures);
 }
 
 
diff --git a/test/cctest/test-sampler-api.cc b/test/cctest/test-sampler-api.cc
new file mode 100644
index 0000000..2f6f92e
--- /dev/null
+++ b/test/cctest/test-sampler-api.cc
@@ -0,0 +1,245 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Tests the sampling API in include/v8.h
+
+#include <map>
+#include <string>
+#include "include/v8.h"
+#include "src/simulator.h"
+#include "test/cctest/cctest.h"
+
+namespace {
+
+class Sample {
+ public:
+  enum { kFramesLimit = 255 };
+
+  Sample() {}
+
+  typedef const void* const* const_iterator;
+  const_iterator begin() const { return data_.start(); }
+  const_iterator end() const { return &data_[data_.length()]; }
+
+  int size() const { return data_.length(); }
+  v8::internal::Vector<void*>& data() { return data_; }
+
+ private:
+  v8::internal::EmbeddedVector<void*, kFramesLimit> data_;
+};
+
+
+#if defined(USE_SIMULATOR)
+class SimulatorHelper {
+ public:
+  inline bool Init(v8::Isolate* isolate) {
+    simulator_ = reinterpret_cast<v8::internal::Isolate*>(isolate)
+                     ->thread_local_top()
+                     ->simulator_;
+    // Check if there is active simulator.
+    return simulator_ != NULL;
+  }
+
+  inline void FillRegisters(v8::RegisterState* state) {
+#if V8_TARGET_ARCH_ARM
+    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
+    state->sp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::sp));
+    state->fp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::r11));
+#elif V8_TARGET_ARCH_ARM64
+    if (simulator_->sp() == 0 || simulator_->fp() == 0) {
+      // It's possible that the simulator is interrupted while it is updating
+      // the sp or fp register. ARM64 simulator does this in two steps:
+      // first setting it to zero and then setting it to a new value.
+      // Bailout if sp/fp doesn't contain the new value.
+      return;
+    }
+    state->pc = reinterpret_cast<void*>(simulator_->pc());
+    state->sp = reinterpret_cast<void*>(simulator_->sp());
+    state->fp = reinterpret_cast<void*>(simulator_->fp());
+#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
+    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
+    state->sp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::sp));
+    state->fp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::fp));
+#endif
+  }
+
+ private:
+  v8::internal::Simulator* simulator_;
+};
+#endif  // USE_SIMULATOR
+
+
+class SamplingTestHelper {
+ public:
+  struct CodeEventEntry {
+    std::string name;
+    const void* code_start;
+    size_t code_len;
+  };
+  typedef std::map<const void*, CodeEventEntry> CodeEntries;
+
+  explicit SamplingTestHelper(const std::string& test_function)
+      : sample_is_taken_(false), isolate_(CcTest::isolate()) {
+    DCHECK_EQ(NULL, instance_);
+    instance_ = this;
+    v8::HandleScope scope(isolate_);
+    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
+    global->Set(v8::String::NewFromUtf8(isolate_, "CollectSample"),
+                v8::FunctionTemplate::New(isolate_, CollectSample));
+    LocalContext env(isolate_, NULL, global);
+    isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+                                     JitCodeEventHandler);
+    v8::Script::Compile(
+        v8::String::NewFromUtf8(isolate_, test_function.c_str()))->Run();
+  }
+
+  ~SamplingTestHelper() {
+    isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
+    instance_ = NULL;
+  }
+
+  Sample& sample() { return sample_; }
+
+  const CodeEventEntry* FindEventEntry(const void* address) {
+    CodeEntries::const_iterator it = code_entries_.upper_bound(address);
+    if (it == code_entries_.begin()) return NULL;
+    const CodeEventEntry& entry = (--it)->second;
+    const void* code_end =
+        static_cast<const uint8_t*>(entry.code_start) + entry.code_len;
+    return address < code_end ? &entry : NULL;
+  }
+
+ private:
+  static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
+    instance_->DoCollectSample();
+  }
+
+  static void JitCodeEventHandler(const v8::JitCodeEvent* event) {
+    instance_->DoJitCodeEventHandler(event);
+  }
+
+  // The JavaScript calls this function when on full stack depth.
+  void DoCollectSample() {
+    v8::RegisterState state;
+#if defined(USE_SIMULATOR)
+    SimulatorHelper simulator_helper;
+    if (!simulator_helper.Init(isolate_)) return;
+    simulator_helper.FillRegisters(&state);
+#else
+    state.pc = NULL;
+    state.fp = &state;
+    state.sp = &state;
+#endif
+    v8::SampleInfo info;
+    isolate_->GetStackSample(state, sample_.data().start(),
+                             static_cast<size_t>(sample_.size()), &info);
+    size_t frames_count = info.frames_count;
+    CHECK_LE(frames_count, static_cast<size_t>(sample_.size()));
+    sample_.data().Truncate(static_cast<int>(frames_count));
+    sample_is_taken_ = true;
+  }
+
+  void DoJitCodeEventHandler(const v8::JitCodeEvent* event) {
+    if (sample_is_taken_) return;
+    switch (event->type) {
+      case v8::JitCodeEvent::CODE_ADDED: {
+        CodeEventEntry entry;
+        entry.name = std::string(event->name.str, event->name.len);
+        entry.code_start = event->code_start;
+        entry.code_len = event->code_len;
+        code_entries_.insert(std::make_pair(entry.code_start, entry));
+        break;
+      }
+      case v8::JitCodeEvent::CODE_MOVED: {
+        CodeEntries::iterator it = code_entries_.find(event->code_start);
+        CHECK(it != code_entries_.end());
+        code_entries_.erase(it);
+        CodeEventEntry entry;
+        entry.name = std::string(event->name.str, event->name.len);
+        entry.code_start = event->new_code_start;
+        entry.code_len = event->code_len;
+        code_entries_.insert(std::make_pair(entry.code_start, entry));
+        break;
+      }
+      case v8::JitCodeEvent::CODE_REMOVED:
+        code_entries_.erase(event->code_start);
+        break;
+      default:
+        break;
+    }
+  }
+
+  Sample sample_;
+  bool sample_is_taken_;
+  v8::Isolate* isolate_;
+  CodeEntries code_entries_;
+
+  static SamplingTestHelper* instance_;
+};
+
+SamplingTestHelper* SamplingTestHelper::instance_;
+
+}  // namespace
+
+
+// A JavaScript function which takes stack depth
+// (minimum value 2) as an argument.
+// When at the bottom of the recursion,
+// the JavaScript code calls into C++ test code,
+// waiting for the sampler to take a sample.
+static const char* test_function =
+    "function func(depth) {"
+    "  if (depth == 2) CollectSample();"
+    "  else return func(depth - 1);"
+    "}";
+
+
+TEST(StackDepthIsConsistent) {
+  SamplingTestHelper helper(std::string(test_function) + "func(8);");
+  CHECK_EQ(8, helper.sample().size());
+}
+
+
+TEST(StackDepthDoesNotExceedMaxValue) {
+  SamplingTestHelper helper(std::string(test_function) + "func(300);");
+  CHECK_EQ(Sample::kFramesLimit, helper.sample().size());
+}
+
+
+// The captured sample should have three pc values.
+// They should fall in the range where the compiled code resides.
+// The expected stack is:
+// bottom of stack [{anon script}, outer, inner] top of stack
+//                              ^      ^       ^
+// sample.stack indices         2      1       0
+TEST(StackFramesConsistent) {
+  // Note: The arguments.callee stuff is there so that the
+  //       functions are not optimized away.
+  const char* test_script =
+      "function test_sampler_api_inner() {"
+      "  CollectSample();"
+      "  return arguments.callee.toString();"
+      "}"
+      "function test_sampler_api_outer() {"
+      "  return test_sampler_api_inner() + arguments.callee.toString();"
+      "}"
+      "test_sampler_api_outer();";
+
+  SamplingTestHelper helper(test_script);
+  Sample& sample = helper.sample();
+  CHECK_EQ(3, sample.size());
+
+  const SamplingTestHelper::CodeEventEntry* entry;
+  entry = helper.FindEventEntry(sample.begin()[0]);
+  CHECK_NE(NULL, entry);
+  CHECK(std::string::npos != entry->name.find("test_sampler_api_inner"));
+
+  entry = helper.FindEventEntry(sample.begin()[1]);
+  CHECK_NE(NULL, entry);
+  CHECK(std::string::npos != entry->name.find("test_sampler_api_outer"));
+}
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index 94b400e..45da250 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -37,7 +37,7 @@
 #include "src/heap/spaces.h"
 #include "src/natives.h"
 #include "src/objects.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/scopeinfo.h"
 #include "src/serialize.h"
 #include "src/snapshot.h"
@@ -114,82 +114,27 @@
 }
 
 
-class FileByteSink : public SnapshotByteSink {
- public:
-  explicit FileByteSink(const char* snapshot_file) {
-    fp_ = v8::base::OS::FOpen(snapshot_file, "wb");
-    file_name_ = snapshot_file;
-    if (fp_ == NULL) {
-      PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
-      exit(1);
-    }
+void WritePayload(const Vector<const byte>& payload, const char* file_name) {
+  FILE* file = v8::base::OS::FOpen(file_name, "wb");
+  if (file == NULL) {
+    PrintF("Unable to write to snapshot file \"%s\"\n", file_name);
+    exit(1);
   }
-  virtual ~FileByteSink() {
-    if (fp_ != NULL) {
-      fclose(fp_);
-    }
+  size_t written = fwrite(payload.begin(), 1, payload.length(), file);
+  if (written != static_cast<size_t>(payload.length())) {
+    i::PrintF("Writing snapshot file failed.. Aborting.\n");
+    exit(1);
   }
-  virtual void Put(byte b, const char* description) {
-    if (fp_ != NULL) {
-      fputc(b, fp_);
-    }
-  }
-  virtual int Position() {
-    return ftell(fp_);
-  }
-  void WriteSpaceUsed(
-      int new_space_used,
-      int pointer_space_used,
-      int data_space_used,
-      int code_space_used,
-      int map_space_used,
-      int cell_space_used,
-      int property_cell_space_used);
-
- private:
-  FILE* fp_;
-  const char* file_name_;
-};
-
-
-void FileByteSink::WriteSpaceUsed(
-      int new_space_used,
-      int pointer_space_used,
-      int data_space_used,
-      int code_space_used,
-      int map_space_used,
-      int cell_space_used,
-      int property_cell_space_used) {
-  int file_name_length = StrLength(file_name_) + 10;
-  Vector<char> name = Vector<char>::New(file_name_length + 1);
-  SNPrintF(name, "%s.size", file_name_);
-  FILE* fp = v8::base::OS::FOpen(name.start(), "w");
-  name.Dispose();
-  fprintf(fp, "new %d\n", new_space_used);
-  fprintf(fp, "pointer %d\n", pointer_space_used);
-  fprintf(fp, "data %d\n", data_space_used);
-  fprintf(fp, "code %d\n", code_space_used);
-  fprintf(fp, "map %d\n", map_space_used);
-  fprintf(fp, "cell %d\n", cell_space_used);
-  fprintf(fp, "property cell %d\n", property_cell_space_used);
-  fclose(fp);
+  fclose(file);
 }
 
 
 static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
-  FileByteSink file(snapshot_file);
-  StartupSerializer ser(isolate, &file);
+  SnapshotByteSink sink;
+  StartupSerializer ser(isolate, &sink);
   ser.Serialize();
-
-  file.WriteSpaceUsed(
-      ser.CurrentAllocationAddress(NEW_SPACE),
-      ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-      ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-      ser.CurrentAllocationAddress(CODE_SPACE),
-      ser.CurrentAllocationAddress(MAP_SPACE),
-      ser.CurrentAllocationAddress(CELL_SPACE),
-      ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
-
+  SnapshotData snapshot_data(sink, ser);
+  WritePayload(snapshot_data.RawData(), snapshot_file);
   return true;
 }
 
@@ -206,7 +151,7 @@
   }
 
   Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
-  internal_isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "serialize");
+  internal_isolate->heap()->CollectAllAvailableGarbage("serialize");
   WriteToFile(internal_isolate, FLAG_testing_serialization_file);
 }
 
@@ -237,51 +182,14 @@
 //----------------------------------------------------------------------------
 // Tests that the heap can be deserialized.
 
-
-static void ReserveSpaceForSnapshot(Deserializer* deserializer,
-                                    const char* file_name) {
-  int file_name_length = StrLength(file_name) + 10;
-  Vector<char> name = Vector<char>::New(file_name_length + 1);
-  SNPrintF(name, "%s.size", file_name);
-  FILE* fp = v8::base::OS::FOpen(name.start(), "r");
-  name.Dispose();
-  int new_size, pointer_size, data_size, code_size, map_size, cell_size,
-      property_cell_size;
-#ifdef _MSC_VER
-  // Avoid warning about unsafe fscanf from MSVC.
-  // Please note that this is only fine if %c and %s are not being used.
-#define fscanf fscanf_s
-#endif
-  CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size));
-  CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size));
-  CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size));
-  CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size));
-  CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size));
-  CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size));
-  CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size));
-#ifdef _MSC_VER
-#undef fscanf
-#endif
-  fclose(fp);
-  deserializer->set_reservation(NEW_SPACE, new_size);
-  deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size);
-  deserializer->set_reservation(OLD_DATA_SPACE, data_size);
-  deserializer->set_reservation(CODE_SPACE, code_size);
-  deserializer->set_reservation(MAP_SPACE, map_size);
-  deserializer->set_reservation(CELL_SPACE, cell_size);
-  deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size);
-}
-
-
 v8::Isolate* InitializeFromFile(const char* snapshot_file) {
   int len;
   byte* str = ReadBytes(snapshot_file, &len);
   if (!str) return NULL;
   v8::Isolate* v8_isolate = NULL;
   {
-    SnapshotByteSource source(str, len);
-    Deserializer deserializer(&source);
-    ReserveSpaceForSnapshot(&deserializer, snapshot_file);
+    SnapshotData snapshot_data(Vector<const byte>(str, len));
+    Deserializer deserializer(&snapshot_data);
     Isolate* isolate = Isolate::NewForTesting();
     v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     v8::Isolate::Scope isolate_scope(v8_isolate);
@@ -440,32 +348,23 @@
       }
       env.Reset();
 
-      FileByteSink startup_sink(startup_name.start());
+      SnapshotByteSink startup_sink;
       StartupSerializer startup_serializer(isolate, &startup_sink);
       startup_serializer.SerializeStrongReferences();
 
-      FileByteSink partial_sink(FLAG_testing_serialization_file);
-      PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
-      p_ser.Serialize(&raw_foo);
+      SnapshotByteSink partial_sink;
+      PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                           &partial_sink);
+      partial_serializer.Serialize(&raw_foo);
+
       startup_serializer.SerializeWeakReferences();
 
-      partial_sink.WriteSpaceUsed(
-          p_ser.CurrentAllocationAddress(NEW_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-          p_ser.CurrentAllocationAddress(CODE_SPACE),
-          p_ser.CurrentAllocationAddress(MAP_SPACE),
-          p_ser.CurrentAllocationAddress(CELL_SPACE),
-          p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      SnapshotData startup_snapshot(startup_sink, startup_serializer);
+      SnapshotData partial_snapshot(partial_sink, partial_serializer);
 
-      startup_sink.WriteSpaceUsed(
-          startup_serializer.CurrentAllocationAddress(NEW_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
-          startup_serializer.CurrentAllocationAddress(CODE_SPACE),
-          startup_serializer.CurrentAllocationAddress(MAP_SPACE),
-          startup_serializer.CurrentAllocationAddress(CELL_SPACE),
-          startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+      WritePayload(startup_snapshot.RawData(), startup_name.start());
+
       startup_name.Dispose();
     }
     v8_isolate->Exit();
@@ -494,9 +393,8 @@
       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
       Object* root;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root);
         CHECK(root->IsString());
       }
@@ -506,9 +404,8 @@
 
       Object* root2;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root2);
         CHECK(root2->IsString());
         CHECK(*root_handle == root2);
@@ -563,32 +460,22 @@
 
       env.Reset();
 
-      FileByteSink startup_sink(startup_name.start());
+      SnapshotByteSink startup_sink;
       StartupSerializer startup_serializer(isolate, &startup_sink);
       startup_serializer.SerializeStrongReferences();
 
-      FileByteSink partial_sink(FLAG_testing_serialization_file);
-      PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
-      p_ser.Serialize(&raw_context);
+      SnapshotByteSink partial_sink;
+      PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                           &partial_sink);
+      partial_serializer.Serialize(&raw_context);
       startup_serializer.SerializeWeakReferences();
 
-      partial_sink.WriteSpaceUsed(
-          p_ser.CurrentAllocationAddress(NEW_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-          p_ser.CurrentAllocationAddress(CODE_SPACE),
-          p_ser.CurrentAllocationAddress(MAP_SPACE),
-          p_ser.CurrentAllocationAddress(CELL_SPACE),
-          p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      SnapshotData startup_snapshot(startup_sink, startup_serializer);
+      SnapshotData partial_snapshot(partial_sink, partial_serializer);
 
-      startup_sink.WriteSpaceUsed(
-          startup_serializer.CurrentAllocationAddress(NEW_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
-          startup_serializer.CurrentAllocationAddress(CODE_SPACE),
-          startup_serializer.CurrentAllocationAddress(MAP_SPACE),
-          startup_serializer.CurrentAllocationAddress(CELL_SPACE),
-          startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+      WritePayload(startup_snapshot.RawData(), startup_name.start());
+
       startup_name.Dispose();
     }
     v8_isolate->Dispose();
@@ -616,9 +503,8 @@
       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
       Object* root;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root);
         CHECK(root->IsContext());
       }
@@ -628,9 +514,8 @@
 
       Object* root2;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root2);
         CHECK(root2->IsContext());
         CHECK(*root_handle != root2);
@@ -786,6 +671,432 @@
 }
 
 
+Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
+                                      Vector<const uint8_t> body,
+                                      Vector<const uint8_t> tail, int repeats) {
+  int source_length = head.length() + body.length() * repeats + tail.length();
+  uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
+  CopyChars(source, head.start(), head.length());
+  for (int i = 0; i < repeats; i++) {
+    CopyChars(source + head.length() + i * body.length(), body.start(),
+              body.length());
+  }
+  CopyChars(source + head.length() + repeats * body.length(), tail.start(),
+            tail.length());
+  return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
+                               source_length);
+}
+
+
+TEST(SerializeToplevelLargeCodeObject) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source =
+      ConstructSource(STATIC_CHAR_VECTOR("var j=1; try { if (j) throw 1;"),
+                      STATIC_CHAR_VECTOR("for(var i=0;i<1;i++)j++;"),
+                      STATIC_CHAR_VECTOR("} catch (e) { j=7; } j"), 10000);
+  Handle<String> source_str =
+      isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  CHECK(isolate->heap()->InSpace(orig->code(), LO_SPACE));
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  int result_int;
+  CHECK(copy_result->ToInt32(&result_int));
+  CHECK_EQ(7, result_int);
+
+  delete cache;
+  source.Dispose();
+}
+
+
+TEST(SerializeToplevelLargeStrings) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* f = isolate->factory();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source_s = ConstructSource(
+      STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"),
+      STATIC_CHAR_VECTOR("\";"), 1000000);
+  Vector<const uint8_t> source_t = ConstructSource(
+      STATIC_CHAR_VECTOR("var t = \""), STATIC_CHAR_VECTOR("uvwxyz"),
+      STATIC_CHAR_VECTOR("\"; s + t"), 999999);
+  Handle<String> source_str =
+      f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
+                       f->NewStringFromOneByte(source_t).ToHandleChecked())
+          .ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
+  Handle<Object> property = JSObject::GetDataProperty(
+      isolate->global_object(), f->NewStringFromAsciiChecked("s"));
+  CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
+  property = JSObject::GetDataProperty(isolate->global_object(),
+                                       f->NewStringFromAsciiChecked("t"));
+  CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
+  // Make sure we do not serialize too much, e.g. include the source string.
+  CHECK_LT(cache->length(), 13000000);
+
+  delete cache;
+  source_s.Dispose();
+  source_t.Dispose();
+}
+
+
+TEST(SerializeToplevelThreeBigStrings) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* f = isolate->factory();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source_a =
+      ConstructSource(STATIC_CHAR_VECTOR("var a = \""), STATIC_CHAR_VECTOR("a"),
+                      STATIC_CHAR_VECTOR("\";"), 700000);
+  Handle<String> source_a_str =
+      f->NewStringFromOneByte(source_a).ToHandleChecked();
+
+  Vector<const uint8_t> source_b =
+      ConstructSource(STATIC_CHAR_VECTOR("var b = \""), STATIC_CHAR_VECTOR("b"),
+                      STATIC_CHAR_VECTOR("\";"), 600000);
+  Handle<String> source_b_str =
+      f->NewStringFromOneByte(source_b).ToHandleChecked();
+
+  Vector<const uint8_t> source_c =
+      ConstructSource(STATIC_CHAR_VECTOR("var c = \""), STATIC_CHAR_VECTOR("c"),
+                      STATIC_CHAR_VECTOR("\";"), 500000);
+  Handle<String> source_c_str =
+      f->NewStringFromOneByte(source_c).ToHandleChecked();
+
+  Handle<String> source_str =
+      f->NewConsString(
+             f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
+             source_c_str).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  USE(Execution::Call(isolate, copy_fun, global, 0, NULL));
+
+  CHECK_EQ(600000 + 700000, CompileRun("(a + b).length")->Int32Value());
+  CHECK_EQ(500000 + 600000, CompileRun("(b + c).length")->Int32Value());
+  Heap* heap = isolate->heap();
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("a")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("b")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("c")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+
+  delete cache;
+  source_a.Dispose();
+  source_b.Dispose();
+  source_c.Dispose();
+}
+
+
+class SerializerOneByteResource
+    : public v8::String::ExternalOneByteStringResource {
+ public:
+  SerializerOneByteResource(const char* data, size_t length)
+      : data_(data), length_(length) {}
+  virtual const char* data() const { return data_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  const char* data_;
+  size_t length_;
+};
+
+
+class SerializerTwoByteResource : public v8::String::ExternalStringResource {
+ public:
+  SerializerTwoByteResource(const char* data, size_t length)
+      : data_(AsciiToTwoByteString(data)), length_(length) {}
+  ~SerializerTwoByteResource() { DeleteArray<const uint16_t>(data_); }
+
+  virtual const uint16_t* data() const { return data_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  const uint16_t* data_;
+  size_t length_;
+};
+
+
+TEST(SerializeToplevelExternalString) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  // Obtain external internalized one-byte string.
+  SerializerOneByteResource one_byte_resource("one_byte", 8);
+  Handle<String> one_byte_string =
+      isolate->factory()->NewStringFromAsciiChecked("one_byte");
+  one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
+  one_byte_string->MakeExternal(&one_byte_resource);
+  CHECK(one_byte_string->IsExternalOneByteString());
+  CHECK(one_byte_string->IsInternalizedString());
+
+  // Obtain external internalized two-byte string.
+  SerializerTwoByteResource two_byte_resource("two_byte", 8);
+  Handle<String> two_byte_string =
+      isolate->factory()->NewStringFromAsciiChecked("two_byte");
+  two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
+  two_byte_string->MakeExternal(&two_byte_resource);
+  CHECK(two_byte_string->IsExternalTwoByteString());
+  CHECK(two_byte_string->IsInternalizedString());
+
+  const char* source =
+      "var o = {}               \n"
+      "o.one_byte = 7;          \n"
+      "o.two_byte = 8;          \n"
+      "o.one_byte + o.two_byte; \n";
+  Handle<String> source_string = isolate->factory()
+                                     ->NewStringFromUtf8(CStrVector(source))
+                                     .ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_string, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_string, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(15.0f, copy_result->Number());
+
+  delete cache;
+}
+
+
+TEST(SerializeToplevelLargeExternalString) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  Factory* f = isolate->factory();
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  // Create a huge external internalized string to use as variable name.
+  Vector<const uint8_t> string =
+      ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"),
+                      STATIC_CHAR_VECTOR(""), 999999);
+  Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
+  SerializerOneByteResource one_byte_resource(
+      reinterpret_cast<const char*>(string.start()), string.length());
+  name = f->InternalizeString(name);
+  name->MakeExternal(&one_byte_resource);
+  CHECK(name->IsExternalOneByteString());
+  CHECK(name->IsInternalizedString());
+  CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
+
+  // Create the source, which is "var <literal> = 42; <literal>".
+  Handle<String> source_str =
+      f->NewConsString(
+             f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
+                 .ToHandleChecked(),
+             f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
+                 .ToHandleChecked()).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(42.0f, copy_result->Number());
+
+  delete cache;
+  string.Dispose();
+}
+
+
+TEST(SerializeToplevelExternalScriptName) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  Factory* f = isolate->factory();
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  const char* source =
+      "var a = [1, 2, 3, 4];"
+      "a.reduce(function(x, y) { return x + y }, 0)";
+
+  Handle<String> source_string =
+      f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
+
+  const SerializerOneByteResource one_byte_resource("one_byte", 8);
+  Handle<String> name =
+      f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
+  CHECK(name->IsExternalOneByteString());
+  CHECK(!name->IsInternalizedString());
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_string, name, 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_string, name, 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(10.0f, copy_result->Number());
+
+  delete cache;
+}
+
+
+static bool toplevel_test_code_event_found = false;
+
+
+static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
+  if (event->type == v8::JitCodeEvent::CODE_ADDED &&
+      memcmp(event->name.str, "Script:~test", 12) == 0) {
+    toplevel_test_code_event_found = true;
+  }
+}
+
+
 TEST(SerializeToplevelIsolates) {
   FLAG_serialize_toplevel = true;
 
@@ -805,6 +1116,7 @@
     v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
         isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
     const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
     // Persist cached data.
     uint8_t* buffer = NewArray<uint8_t>(data->length);
     MemCopy(buffer, data->data, data->length);
@@ -812,11 +1124,14 @@
         buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
 
     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
-    CHECK(result->ToString()->Equals(v8_str("abcdef")));
+    CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
   }
   isolate1->Dispose();
 
   v8::Isolate* isolate2 = v8::Isolate::New();
+  isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+                                   SerializerCodeEventListener);
+  toplevel_test_code_event_found = false;
   {
     v8::Isolate::Scope iscope(isolate2);
     v8::HandleScope scope(isolate2);
@@ -832,8 +1147,125 @@
       script = v8::ScriptCompiler::CompileUnbound(
           isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
     }
+    CHECK(!cache->rejected);
     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
-    CHECK(result->ToString()->Equals(v8_str("abcdef")));
+    CHECK(result->ToString(isolate2)->Equals(v8_str("abcdef")));
+  }
+  DCHECK(toplevel_test_code_event_found);
+  isolate2->Dispose();
+}
+
+
+TEST(SerializeToplevelFlagChange) {
+  FLAG_serialize_toplevel = true;
+
+  const char* source = "function f() { return 'abc'; }; f() + 'def'";
+  v8::ScriptCompiler::CachedData* cache;
+
+  v8::Isolate* isolate1 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate1);
+    v8::HandleScope scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    v8::Context::Scope context_scope(context);
+
+    v8::Local<v8::String> source_str = v8_str(source);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin);
+    v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
+        isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
+    const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
+    // Persist cached data.
+    uint8_t* buffer = NewArray<uint8_t>(data->length);
+    MemCopy(buffer, data->data, data->length);
+    cache = new v8::ScriptCompiler::CachedData(
+        buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
+
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
+  }
+  isolate1->Dispose();
+
+  v8::Isolate* isolate2 = v8::Isolate::New();
+  FLAG_allow_natives_syntax = true;  // Flag change should trigger cache reject.
+  {
+    v8::Isolate::Scope iscope(isolate2);
+    v8::HandleScope scope(isolate2);
+    v8::Local<v8::Context> context = v8::Context::New(isolate2);
+    v8::Context::Scope context_scope(context);
+
+    v8::Local<v8::String> source_str = v8_str(source);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin, cache);
+    v8::ScriptCompiler::CompileUnbound(isolate2, &source,
+                                       v8::ScriptCompiler::kConsumeCodeCache);
+    CHECK(cache->rejected);
+  }
+  isolate2->Dispose();
+}
+
+
+TEST(SerializeWithHarmonyScoping) {
+  FLAG_serialize_toplevel = true;
+  FLAG_harmony_scoping = true;
+
+  const char* source1 = "'use strict'; let x = 'X'";
+  const char* source2 = "'use strict'; let y = 'Y'";
+  const char* source3 = "'use strict'; x + y";
+
+  v8::ScriptCompiler::CachedData* cache;
+
+  v8::Isolate* isolate1 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate1);
+    v8::HandleScope scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    v8::Context::Scope context_scope(context);
+
+    CompileRun(source1);
+    CompileRun(source2);
+
+    v8::Local<v8::String> source_str = v8_str(source3);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin);
+    v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
+        isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
+    const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
+    // Persist cached data.
+    uint8_t* buffer = NewArray<uint8_t>(data->length);
+    MemCopy(buffer, data->data, data->length);
+    cache = new v8::ScriptCompiler::CachedData(
+        buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
+
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate1)->Equals(v8_str("XY")));
+  }
+  isolate1->Dispose();
+
+  v8::Isolate* isolate2 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate2);
+    v8::HandleScope scope(isolate2);
+    v8::Local<v8::Context> context = v8::Context::New(isolate2);
+    v8::Context::Scope context_scope(context);
+
+    // Reverse order of prior running scripts.
+    CompileRun(source2);
+    CompileRun(source1);
+
+    v8::Local<v8::String> source_str = v8_str(source3);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin, cache);
+    v8::Local<v8::UnboundScript> script;
+    {
+      DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
+      script = v8::ScriptCompiler::CompileUnbound(
+          isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
+    }
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate2)->Equals(v8_str("XY")));
   }
   isolate2->Dispose();
 }
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index d09c128..a84b867 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -27,6 +27,7 @@
 
 #include <stdlib.h>
 
+#include "src/base/platform/platform.h"
 #include "src/snapshot.h"
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
@@ -212,11 +213,17 @@
   TestMemoryAllocatorScope test_allocator_scope(isolate, memory_allocator);
   CodeRange* code_range = new CodeRange(isolate);
   const size_t code_range_size = 4 * MB;
-  if (!code_range->SetUp(code_range_size)) return;
+  if (!code_range->SetUp(
+          code_range_size +
+          RoundUp(v8::base::OS::CommitPageSize() * kReservedCodeRangePages,
+                  MemoryChunk::kAlignment) +
+          v8::internal::MemoryAllocator::CodePageAreaSize())) {
+    return;
+  }
   Address address;
   size_t size;
-  address = code_range->AllocateRawMemory(code_range_size - MB,
-                                          code_range_size - MB, &size);
+  address = code_range->AllocateRawMemory(code_range_size - 2 * MB,
+                                          code_range_size - 2 * MB, &size);
   CHECK(address != NULL);
   Address null_address;
   size_t null_size;
@@ -450,3 +457,55 @@
   // No large objects required to perform the above steps.
   CHECK(isolate->heap()->lo_space()->IsEmpty());
 }
+
+
+static inline void FillCurrentPage(v8::internal::NewSpace* space) {
+  int new_linear_size = static_cast<int>(*space->allocation_limit_address() -
+                                         *space->allocation_top_address());
+  if (new_linear_size == 0) return;
+  v8::internal::AllocationResult allocation =
+      space->AllocateRaw(new_linear_size);
+  v8::internal::FreeListNode* node =
+      v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+  node->set_size(space->heap(), new_linear_size);
+}
+
+
+UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) {
+  FLAG_target_semi_space_size = 2;
+  if (FLAG_optimize_for_size) return;
+
+  v8::Isolate* isolate = v8::Isolate::New();
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope(isolate);
+    v8::Context::New(isolate)->Enter();
+
+    Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
+
+    NewSpace* new_space = i_isolate->heap()->new_space();
+
+    // This test doesn't work if we start with a non-default new space
+    // configuration.
+    if (new_space->InitialTotalCapacity() == Page::kPageSize) {
+      CHECK(new_space->CommittedMemory() == new_space->InitialTotalCapacity());
+
+      // Fill up the first (and only) page of the semi space.
+      FillCurrentPage(new_space);
+
+      // Try to allocate out of the new space. A new page should be added and
+      // the
+      // allocation should succeed.
+      v8::internal::AllocationResult allocation = new_space->AllocateRaw(80);
+      CHECK(!allocation.IsRetry());
+      CHECK(new_space->CommittedMemory() == 2 * Page::kPageSize);
+
+      // Turn the allocation into a proper object so isolate teardown won't
+      // crash.
+      v8::internal::FreeListNode* node =
+          v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+      node->set_size(new_space->heap(), 80);
+    }
+  }
+  isolate->Dispose();
+}
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index ef13c4d..d1f23f7 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -37,6 +37,7 @@
 #include "src/api.h"
 #include "src/factory.h"
 #include "src/objects.h"
+#include "src/unicode-decoder.h"
 #include "test/cctest/cctest.h"
 
 // Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry
@@ -356,10 +357,10 @@
 
 void AccumulateStatsWithOperator(
     ConsString* cons_string, ConsStringStats* stats) {
-  ConsStringIteratorOp op(cons_string);
+  ConsStringIterator iter(cons_string);
   String* string;
   int offset;
-  while (NULL != (string = op.Next(&offset))) {
+  while (NULL != (string = iter.Next(&offset))) {
     // Accumulate stats.
     CHECK_EQ(0, offset);
     stats->leaves_++;
@@ -523,13 +524,10 @@
 }
 
 
-static ConsStringIteratorOp cons_string_iterator_op_1;
-static ConsStringIteratorOp cons_string_iterator_op_2;
-
 static void Traverse(Handle<String> s1, Handle<String> s2) {
   int i = 0;
-  StringCharacterStream character_stream_1(*s1, &cons_string_iterator_op_1);
-  StringCharacterStream character_stream_2(*s2, &cons_string_iterator_op_2);
+  StringCharacterStream character_stream_1(*s1);
+  StringCharacterStream character_stream_2(*s2);
   while (character_stream_1.HasMore()) {
     CHECK(character_stream_2.HasMore());
     uint16_t c = character_stream_1.GetNext();
@@ -545,8 +543,8 @@
 
 static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
   int i = 0;
-  StringCharacterStream character_stream_1(*s1, &cons_string_iterator_op_1);
-  StringCharacterStream character_stream_2(*s2, &cons_string_iterator_op_2);
+  StringCharacterStream character_stream_1(*s1);
+  StringCharacterStream character_stream_2(*s2);
   while (character_stream_1.HasMore() && i < chars) {
     CHECK(character_stream_2.HasMore());
     uint16_t c = character_stream_1.GetNext();
@@ -615,10 +613,8 @@
     if (offset < 0) offset = 0;
     // Want to test the offset == length case.
     if (offset > length) offset = length;
-    StringCharacterStream flat_stream(
-        flat_string, &cons_string_iterator_op_1, offset);
-    StringCharacterStream cons_stream(
-        cons_string, &cons_string_iterator_op_2, offset);
+    StringCharacterStream flat_stream(flat_string, offset);
+    StringCharacterStream cons_stream(cons_string, offset);
     for (int i = offset; i < length; i++) {
       uint16_t c = flat_string->Get(i);
       CHECK(flat_stream.HasMore());
@@ -634,14 +630,11 @@
 
 static inline void PrintStats(const ConsStringGenerationData& data) {
 #ifdef DEBUG
-printf(
-    "%s: [%d], %s: [%d], %s: [%d], %s: [%d], %s: [%d], %s: [%d]\n",
-    "leaves", data.stats_.leaves_,
-    "empty", data.stats_.empty_leaves_,
-    "chars", data.stats_.chars_,
-    "lefts", data.stats_.left_traversals_,
-    "rights", data.stats_.right_traversals_,
-    "early_terminations", data.early_terminations_);
+  printf("%s: [%u], %s: [%u], %s: [%u], %s: [%u], %s: [%u], %s: [%u]\n",
+         "leaves", data.stats_.leaves_, "empty", data.stats_.empty_leaves_,
+         "chars", data.stats_.chars_, "lefts", data.stats_.left_traversals_,
+         "rights", data.stats_.right_traversals_, "early_terminations",
+         data.early_terminations_);
 #endif
 }
 
@@ -1027,11 +1020,13 @@
   // into a two-byte external string.  Check that JSON.stringify works.
   v8::HandleScope handle_scope(CcTest::isolate());
   v8::Handle<v8::String> underlying =
-      CompileRun("var underlying = 'abcdefghijklmnopqrstuvwxyz';"
-                 "underlying")->ToString();
-  v8::Handle<v8::String> slice =
-      CompileRun("var slice = underlying.slice(1);"
-                 "slice")->ToString();
+      CompileRun(
+          "var underlying = 'abcdefghijklmnopqrstuvwxyz';"
+          "underlying")->ToString(CcTest::isolate());
+  v8::Handle<v8::String> slice = CompileRun(
+                                     "var slice = '';"
+                                     "slice = underlying.slice(1);"
+                                     "slice")->ToString(CcTest::isolate());
   CHECK(v8::Utils::OpenHandle(*slice)->IsSlicedString());
   CHECK(v8::Utils::OpenHandle(*underlying)->IsSeqOneByteString());
 
@@ -1089,7 +1084,7 @@
     CHECK_EQ(results[i]->IsNumber(), result->IsNumber());
     if (result->IsNumber()) {
       CHECK_EQ(Object::ToSmi(isolate, results[i]).ToHandleChecked()->value(),
-               result->ToInt32()->Value());
+               result->ToInt32(CcTest::isolate())->Value());
     }
   }
 }
@@ -1189,7 +1184,7 @@
   v8::Local<v8::Value> result;
   Handle<String> string;
   const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
-  const char* slice = "var slice = str.slice(1,-1); slice";
+  const char* slice = "var slice = ''; slice = str.slice(1,-1); slice";
   const char* slice_from_slice = "slice.slice(1,-1);";
 
   CompileRun(init);
@@ -1292,6 +1287,42 @@
 }
 
 
+namespace {
+
+int* global_use_counts = NULL;
+
+void MockUseCounterCallback(v8::Isolate* isolate,
+                            v8::Isolate::UseCounterFeature feature) {
+  ++global_use_counts[feature];
+}
+}
+
+
+TEST(CountBreakIterator) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
+  global_use_counts = use_counts;
+  CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
+  CHECK_EQ(0, use_counts[v8::Isolate::kBreakIterator]);
+  v8::Local<v8::Value> result = CompileRun(
+      "(function() {"
+      "  if (!this.Intl) return 0;"
+      "  var iterator = Intl.v8BreakIterator(['en']);"
+      "  iterator.adoptText('Now is the time');"
+      "  iterator.next();"
+      "  return iterator.next();"
+      "})();");
+  CHECK(result->IsNumber());
+  int uses = result->ToInt32(CcTest::isolate())->Value() == 0 ? 0 : 1;
+  CHECK_EQ(uses, use_counts[v8::Isolate::kBreakIterator]);
+  // Make sure GC cleans up the break iterator, so we don't get a memory leak
+  // reported by ASAN.
+  CcTest::isolate()->LowMemoryNotification();
+}
+
+
 TEST(StringReplaceAtomTwoByteResult) {
   CcTest::InitializeVM();
   v8::HandleScope scope(CcTest::isolate());
diff --git a/test/cctest/test-transitions.cc b/test/cctest/test-transitions.cc
new file mode 100644
index 0000000..6bcdb35
--- /dev/null
+++ b/test/cctest/test-transitions.cc
@@ -0,0 +1,301 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+#include <utility>
+
+#include "src/v8.h"
+
+#include "src/compilation-cache.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+
+
+//
+// Helper functions.
+//
+
+static void ConnectTransition(Handle<Map> parent,
+                              Handle<TransitionArray> transitions,
+                              Handle<Map> child) {
+  if (!parent->HasTransitionArray() || *transitions != parent->transitions()) {
+    parent->set_transitions(*transitions);
+  }
+  child->SetBackPointer(*parent);
+}
+
+
+static void CheckPropertyDetailsFieldsConsistency(PropertyType type,
+                                                  PropertyKind kind,
+                                                  PropertyLocation location) {
+  int type_value = PropertyDetails::TypeField::encode(type);
+  int kind_location_value = PropertyDetails::KindField::encode(kind) |
+                            PropertyDetails::LocationField::encode(location);
+  CHECK_EQ(type_value, kind_location_value);
+}
+
+
+TEST(PropertyDetailsFieldsConsistency) {
+  CheckPropertyDetailsFieldsConsistency(FIELD, DATA, IN_OBJECT);
+  CheckPropertyDetailsFieldsConsistency(CONSTANT, DATA, IN_DESCRIPTOR);
+  CheckPropertyDetailsFieldsConsistency(ACCESSOR_FIELD, ACCESSOR, IN_OBJECT);
+  CheckPropertyDetailsFieldsConsistency(CALLBACKS, ACCESSOR, IN_DESCRIPTOR);
+}
+
+
+TEST(TransitionArray_SimpleFieldTransitions) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<String> name1 = factory->InternalizeUtf8String("foo");
+  Handle<String> name2 = factory->InternalizeUtf8String("bar");
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  Handle<Map> map1 =
+      Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+  Handle<Map> map2 =
+      Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  int transition;
+  transitions =
+      transitions->Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map1);
+  CHECK(transitions->IsSimpleTransition());
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(TransitionArray::kSimpleTransitionIndex, transition);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transitions =
+      transitions->Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map2);
+  CHECK(transitions->IsFullTransitionArray());
+
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transition = transitions->Search(DATA, *name2, attributes);
+  CHECK_EQ(*name2, transitions->GetKey(transition));
+  CHECK_EQ(*map2, transitions->GetTarget(transition));
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_FullFieldTransitions) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<String> name1 = factory->InternalizeUtf8String("foo");
+  Handle<String> name2 = factory->InternalizeUtf8String("bar");
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  Handle<Map> map1 =
+      Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+  Handle<Map> map2 =
+      Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  int transition;
+  transitions = transitions->Insert(map0, name1, map1, PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map1);
+  CHECK(transitions->IsFullTransitionArray());
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transitions = transitions->Insert(map0, name2, map2, PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map2);
+  CHECK(transitions->IsFullTransitionArray());
+
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transition = transitions->Search(DATA, *name2, attributes);
+  CHECK_EQ(*name2, transitions->GetKey(transition));
+  CHECK_EQ(*map2, transitions->GetTarget(transition));
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_DifferentFieldNames) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  const int PROPS_COUNT = 10;
+  Handle<String> names[PROPS_COUNT];
+  Handle<Map> maps[PROPS_COUNT];
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    names[i] = name;
+    maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    int transition = transitions->Search(DATA, *names[i], attributes);
+    CHECK_EQ(*names[i], transitions->GetKey(transition));
+    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
+  STATIC_ASSERT(ATTRS_COUNT == 8);
+  Handle<Map> attr_maps[ATTRS_COUNT];
+  Handle<String> name = factory->InternalizeUtf8String("foo");
+
+  // Add transitions for same field name but different attributes.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    attr_maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  // Ensure that transitions for |name| field are valid.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    int transition = transitions->Search(DATA, *name, attributes);
+    CHECK_EQ(*name, transitions->GetKey(transition));
+    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  const int PROPS_COUNT = 10;
+  Handle<String> names[PROPS_COUNT];
+  Handle<Map> maps[PROPS_COUNT];
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  // Some number of fields.
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), NONE,
+                           Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    names[i] = name;
+    maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
+  STATIC_ASSERT(ATTRS_COUNT == 8);
+  Handle<Map> attr_maps[ATTRS_COUNT];
+  Handle<String> name = factory->InternalizeUtf8String("foo");
+
+  // Add transitions for same field name but different attributes.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    attr_maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  // Ensure that transitions for |name| field are valid.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    int transition = transitions->Search(DATA, *name, attributes);
+    CHECK_EQ(*name, transitions->GetKey(transition));
+    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
+  }
+
+  // Ensure that info about the other fields still valid.
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    int transition = transitions->Search(DATA, *names[i], NONE);
+    CHECK_EQ(*names[i], transitions->GetKey(transition));
+    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc
index 0cd2472..ebef527 100644
--- a/test/cctest/test-types.cc
+++ b/test/cctest/test-types.cc
@@ -8,12 +8,27 @@
 #include "src/isolate-inl.h"
 #include "src/types.h"
 #include "test/cctest/cctest.h"
+#include "test/cctest/types-fuzz.h"
 
 using namespace v8::internal;
 
+
 // Testing auxiliaries (breaking the Type abstraction).
+
+
+static bool IsInteger(double x) {
+  return nearbyint(x) == x && !i::IsMinusZero(x);  // Allows for infinities.
+}
+
+
+static bool IsInteger(i::Object* x) {
+  return x->IsNumber() && IsInteger(x->Number());
+}
+
+
 typedef uint32_t bitset;
 
+
 struct ZoneRep {
   typedef void* Struct;
 
@@ -76,262 +91,6 @@
 };
 
 
-template<class Type, class TypeHandle, class Region>
-class Types {
- public:
-  Types(Region* region, Isolate* isolate)
-      : region_(region), rng_(isolate->random_number_generator()) {
-    #define DECLARE_TYPE(name, value) \
-      name = Type::name(region); \
-      types.push_back(name);
-    PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
-    #undef DECLARE_TYPE
-
-    object_map = isolate->factory()->NewMap(
-        JS_OBJECT_TYPE, JSObject::kHeaderSize);
-    array_map = isolate->factory()->NewMap(
-        JS_ARRAY_TYPE, JSArray::kSize);
-    number_map = isolate->factory()->NewMap(
-        HEAP_NUMBER_TYPE, HeapNumber::kSize);
-    uninitialized_map = isolate->factory()->uninitialized_map();
-    ObjectClass = Type::Class(object_map, region);
-    ArrayClass = Type::Class(array_map, region);
-    NumberClass = Type::Class(number_map, region);
-    UninitializedClass = Type::Class(uninitialized_map, region);
-
-    maps.push_back(object_map);
-    maps.push_back(array_map);
-    maps.push_back(uninitialized_map);
-    for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) {
-      types.push_back(Type::Class(*it, region));
-    }
-
-    smi = handle(Smi::FromInt(666), isolate);
-    signed32 = isolate->factory()->NewHeapNumber(0x40000000);
-    object1 = isolate->factory()->NewJSObjectFromMap(object_map);
-    object2 = isolate->factory()->NewJSObjectFromMap(object_map);
-    array = isolate->factory()->NewJSArray(20);
-    uninitialized = isolate->factory()->uninitialized_value();
-    SmiConstant = Type::Constant(smi, region);
-    Signed32Constant = Type::Constant(signed32, region);
-    ObjectConstant1 = Type::Constant(object1, region);
-    ObjectConstant2 = Type::Constant(object2, region);
-    ArrayConstant = Type::Constant(array, region);
-    UninitializedConstant = Type::Constant(uninitialized, region);
-
-    values.push_back(smi);
-    values.push_back(signed32);
-    values.push_back(object1);
-    values.push_back(object2);
-    values.push_back(array);
-    values.push_back(uninitialized);
-    for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) {
-      types.push_back(Type::Constant(*it, region));
-    }
-
-    integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY));
-    integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY));
-    integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10)));
-    integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10)));
-    for (int i = 0; i < 10; ++i) {
-      double x = rng_->NextInt();
-      integers.push_back(isolate->factory()->NewNumber(x));
-      x *= rng_->NextInt();
-      if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
-    }
-
-    NumberArray = Type::Array(Number, region);
-    StringArray = Type::Array(String, region);
-    AnyArray = Type::Array(Any, region);
-
-    SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region);
-    NumberFunction1 = Type::Function(Number, Number, region);
-    NumberFunction2 = Type::Function(Number, Number, Number, region);
-    MethodFunction = Type::Function(String, Object, 0, region);
-
-    for (int i = 0; i < 30; ++i) {
-      types.push_back(Fuzz());
-    }
-  }
-
-  Handle<i::Map> object_map;
-  Handle<i::Map> array_map;
-  Handle<i::Map> number_map;
-  Handle<i::Map> uninitialized_map;
-
-  Handle<i::Smi> smi;
-  Handle<i::HeapNumber> signed32;
-  Handle<i::JSObject> object1;
-  Handle<i::JSObject> object2;
-  Handle<i::JSArray> array;
-  Handle<i::Oddball> uninitialized;
-
-  #define DECLARE_TYPE(name, value) TypeHandle name;
-  BITSET_TYPE_LIST(DECLARE_TYPE)
-  #undef DECLARE_TYPE
-
-  TypeHandle ObjectClass;
-  TypeHandle ArrayClass;
-  TypeHandle NumberClass;
-  TypeHandle UninitializedClass;
-
-  TypeHandle SmiConstant;
-  TypeHandle Signed32Constant;
-  TypeHandle ObjectConstant1;
-  TypeHandle ObjectConstant2;
-  TypeHandle ArrayConstant;
-  TypeHandle UninitializedConstant;
-
-  TypeHandle NumberArray;
-  TypeHandle StringArray;
-  TypeHandle AnyArray;
-
-  TypeHandle SignedFunction1;
-  TypeHandle NumberFunction1;
-  TypeHandle NumberFunction2;
-  TypeHandle MethodFunction;
-
-  typedef std::vector<TypeHandle> TypeVector;
-  typedef std::vector<Handle<i::Map> > MapVector;
-  typedef std::vector<Handle<i::Object> > ValueVector;
-
-  TypeVector types;
-  MapVector maps;
-  ValueVector values;
-  ValueVector integers;  // "Integer" values used for range limits.
-
-  TypeHandle Of(Handle<i::Object> value) {
-    return Type::Of(value, region_);
-  }
-
-  TypeHandle NowOf(Handle<i::Object> value) {
-    return Type::NowOf(value, region_);
-  }
-
-  TypeHandle Class(Handle<i::Map> map) {
-    return Type::Class(map, region_);
-  }
-
-  TypeHandle Constant(Handle<i::Object> value) {
-    return Type::Constant(value, region_);
-  }
-
-  TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) {
-    return Type::Range(min, max, region_);
-  }
-
-  TypeHandle Context(TypeHandle outer) {
-    return Type::Context(outer, region_);
-  }
-
-  TypeHandle Array1(TypeHandle element) {
-    return Type::Array(element, region_);
-  }
-
-  TypeHandle Function0(TypeHandle result, TypeHandle receiver) {
-    return Type::Function(result, receiver, 0, region_);
-  }
-
-  TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) {
-    TypeHandle type = Type::Function(result, receiver, 1, region_);
-    type->AsFunction()->InitParameter(0, arg);
-    return type;
-  }
-
-  TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) {
-    return Type::Function(result, arg1, arg2, region_);
-  }
-
-  TypeHandle Union(TypeHandle t1, TypeHandle t2) {
-    return Type::Union(t1, t2, region_);
-  }
-  TypeHandle Intersect(TypeHandle t1, TypeHandle t2) {
-    return Type::Intersect(t1, t2, region_);
-  }
-
-  template<class Type2, class TypeHandle2>
-  TypeHandle Convert(TypeHandle2 t) {
-    return Type::template Convert<Type2>(t, region_);
-  }
-
-  TypeHandle Random() {
-    return types[rng_->NextInt(static_cast<int>(types.size()))];
-  }
-
-  TypeHandle Fuzz(int depth = 4) {
-    switch (rng_->NextInt(depth == 0 ? 3 : 20)) {
-      case 0: {  // bitset
-        int n = 0
-        #define COUNT_BITSET_TYPES(type, value) + 1
-        PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES)
-        #undef COUNT_BITSET_TYPES
-        ;
-        int i = rng_->NextInt(n);
-        #define PICK_BITSET_TYPE(type, value) \
-          if (i-- == 0) return Type::type(region_);
-        PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE)
-        #undef PICK_BITSET_TYPE
-        UNREACHABLE();
-      }
-      case 1: {  // class
-        int i = rng_->NextInt(static_cast<int>(maps.size()));
-        return Type::Class(maps[i], region_);
-      }
-      case 2: {  // constant
-        int i = rng_->NextInt(static_cast<int>(values.size()));
-        return Type::Constant(values[i], region_);
-      }
-      case 3: {  // range
-        int i = rng_->NextInt(static_cast<int>(integers.size()));
-        int j = rng_->NextInt(static_cast<int>(integers.size()));
-        i::Handle<i::Object> min = integers[i];
-        i::Handle<i::Object> max = integers[j];
-        if (min->Number() > max->Number()) std::swap(min, max);
-        return Type::Range(min, max, region_);
-      }
-      case 4: {  // context
-        int depth = rng_->NextInt(3);
-        TypeHandle type = Type::Internal(region_);
-        for (int i = 0; i < depth; ++i) type = Type::Context(type, region_);
-        return type;
-      }
-      case 5: {  // array
-        TypeHandle element = Fuzz(depth / 2);
-        return Type::Array(element, region_);
-      }
-      case 6:
-      case 7: {  // function
-        TypeHandle result = Fuzz(depth / 2);
-        TypeHandle receiver = Fuzz(depth / 2);
-        int arity = rng_->NextInt(3);
-        TypeHandle type = Type::Function(result, receiver, arity, region_);
-        for (int i = 0; i < type->AsFunction()->Arity(); ++i) {
-          TypeHandle parameter = Fuzz(depth / 2);
-          type->AsFunction()->InitParameter(i, parameter);
-        }
-        return type;
-      }
-      default: {  // union
-        int n = rng_->NextInt(10);
-        TypeHandle type = None;
-        for (int i = 0; i < n; ++i) {
-          TypeHandle operand = Fuzz(depth - 1);
-          type = Type::Union(type, operand, region_);
-        }
-        return type;
-      }
-    }
-    UNREACHABLE();
-  }
-
-  Region* region() { return region_; }
-
- private:
-  Region* region_;
-  v8::base::RandomNumberGenerator* rng_;
-};
-
-
 template<class Type, class TypeHandle, class Region, class Rep>
 struct Tests : Rep {
   typedef Types<Type, TypeHandle, Region> TypesInstance;
@@ -535,39 +294,55 @@
     CHECK(T.Constant(fac->NewNumber(0))->Is(T.UnsignedSmall));
     CHECK(T.Constant(fac->NewNumber(1))->Is(T.UnsignedSmall));
     CHECK(T.Constant(fac->NewNumber(0x3fffffff))->Is(T.UnsignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-1))->Is(T.OtherSignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.OtherSignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.OtherSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-1))->Is(T.NegativeSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.NegativeSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.NegativeSignedSmall));
     if (SmiValuesAre31Bits()) {
-      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.NonNegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall));
+      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.NonNegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSigned32));
+      CHECK(
+          !T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 1))
+                 ->Is(T.NegativeSignedSmall));
     } else {
       CHECK(SmiValuesAre32Bits());
       CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall));
       CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall));
-      CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31));
-      CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSignedSmall));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSignedSmall));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSignedSmall));
-      CHECK(!T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32));
-      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32));
-      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.NonNegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.NonNegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff - 1))
+                ->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSigned32));
+      CHECK(
+          T.Constant(fac->NewNumber(-0x7fffffff - 1))->Is(T.NegativeSigned32));
     }
-    CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.OtherUnsigned32));
-    CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.OtherUnsigned32));
-    CHECK(T.Constant(fac->NewNumber(0xffffffffu+1.0))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-0x7fffffff-2.0))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.Unsigned32));
+    CHECK(!T.Constant(fac->NewNumber(0x80000000u))->Is(T.NonNegativeSigned32));
+    CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.Unsigned32));
+    CHECK(!T.Constant(fac->NewNumber(0xffffffffu))->Is(T.NonNegativeSigned32));
+    CHECK(T.Constant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(0.1))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-10.1))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(10e60))->Is(T.Integral32));
     CHECK(T.Constant(fac->NewNumber(-1.0*0.0))->Is(T.MinusZero));
     CHECK(T.Constant(fac->NewNumber(v8::base::OS::nan_value()))->Is(T.NaN));
-    CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.Integral32));
   }
 
   void Range() {
@@ -598,11 +373,11 @@
     // Range(min1, max1) = Range(min2, max2) <=> min1 = min2 /\ max1 = max2
     for (ValueIterator i1 = T.integers.begin();
         i1 != T.integers.end(); ++i1) {
-      for (ValueIterator j1 = T.integers.begin();
+      for (ValueIterator j1 = i1;
           j1 != T.integers.end(); ++j1) {
         for (ValueIterator i2 = T.integers.begin();
             i2 != T.integers.end(); ++i2) {
-          for (ValueIterator j2 = T.integers.begin();
+          for (ValueIterator j2 = i2;
               j2 != T.integers.end(); ++j2) {
             i::Handle<i::Object> min1 = *i1;
             i::Handle<i::Object> max1 = *j1;
@@ -619,6 +394,33 @@
     }
   }
 
+  void Context() {
+    // Constructor
+    for (int i = 0; i < 20; ++i) {
+      TypeHandle type = T.Random();
+      TypeHandle context = T.Context(type);
+      CHECK(context->Iscontext());
+    }
+
+    // Attributes
+    for (int i = 0; i < 20; ++i) {
+      TypeHandle type = T.Random();
+      TypeHandle context = T.Context(type);
+      CheckEqual(type, context->AsContext()->Outer());
+    }
+
+    // Functionality & Injectivity: Context(T1) = Context(T2) iff T1 = T2
+    for (int i = 0; i < 20; ++i) {
+      for (int j = 0; j < 20; ++j) {
+        TypeHandle type1 = T.Random();
+        TypeHandle type2 = T.Random();
+        TypeHandle context1 = T.Context(type1);
+        TypeHandle context2 = T.Context(type2);
+        CHECK(Equal(context1, context2) == Equal(type1, type2));
+      }
+    }
+  }
+
   void Array() {
     // Constructor
     for (int i = 0; i < 20; ++i) {
@@ -803,6 +605,66 @@
     }
   }
 
+  void MinMax() {
+    Factory* fac = isolate->factory();
+
+    // If b is regular numeric bitset, then Range(b->Min(), b->Max())->Is(b).
+    // TODO(neis): Need to ignore representation for this to be true.
+    /*
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (this->IsBitset(type) && type->Is(T.Number) &&
+          !type->Is(T.None) && !type->Is(T.NaN)) {
+        TypeHandle range = T.Range(
+            isolate->factory()->NewNumber(type->Min()),
+            isolate->factory()->NewNumber(type->Max()));
+        CHECK(range->Is(type));
+      }
+    }
+    */
+
+    // If b is regular numeric bitset, then b->Min() and b->Max() are integers.
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (this->IsBitset(type) && type->Is(T.Number) && !type->Is(T.NaN)) {
+        CHECK(IsInteger(type->Min()) && IsInteger(type->Max()));
+      }
+    }
+
+    // If b1 and b2 are regular numeric bitsets with b1->Is(b2), then
+    // b1->Min() >= b2->Min() and b1->Max() <= b2->Max().
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (this->IsBitset(type1) && type1->Is(type2) && type2->Is(T.Number) &&
+            !type1->Is(T.NaN) && !type2->Is(T.NaN)) {
+          CHECK(type1->Min() >= type2->Min());
+          CHECK(type1->Max() <= type2->Max());
+        }
+      }
+    }
+
+    // Lub(Range(x,y))->Min() <= x and y <= Lub(Range(x,y))->Max()
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsRange()) {
+        TypeHandle lub = Rep::BitsetType::New(
+            Rep::BitsetType::Lub(type), T.region());
+        CHECK(lub->Min() <= type->Min() && type->Max() <= lub->Max());
+      }
+    }
+
+    // Rangification: If T->Is(Range(-inf,+inf)) and !T->Is(None), then
+    // T->Is(Range(T->Min(), T->Max())).
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(!(type->Is(T.Integer) && !type->Is(T.None)) ||
+            type->Is(T.Range(fac->NewNumber(type->Min()),
+                             fac->NewNumber(type->Max()))));
+    }
+  }
+
   void BitsetGlb() {
     // Lower: (T->BitsetGlb())->Is(T)
     for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
@@ -871,7 +733,7 @@
     }
   }
 
-  void Is() {
+  void Is1() {
     // Least Element (Bottom): None->Is(T)
     for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
       TypeHandle type = *it;
@@ -923,6 +785,26 @@
       }
     }
 
+    // (In-)Compatibilities.
+    for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) {
+      for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) {
+        TypeHandle type1 = *i;
+        TypeHandle type2 = *j;
+        CHECK(!type1->Is(type2) || this->IsBitset(type2) ||
+              this->IsUnion(type2) || this->IsUnion(type1) ||
+              (type1->IsClass() && type2->IsClass()) ||
+              (type1->IsConstant() && type2->IsConstant()) ||
+              (type1->IsConstant() && type2->IsRange()) ||
+              (type1->IsRange() && type2->IsRange()) ||
+              (type1->IsContext() && type2->IsContext()) ||
+              (type1->IsArray() && type2->IsArray()) ||
+              (type1->IsFunction() && type2->IsFunction()) ||
+              type1->Equals(T.None));
+      }
+    }
+  }
+
+  void Is2() {
     // Class(M1)->Is(Class(M2)) iff M1 = M2
     for (MapIterator mt1 = T.maps.begin(); mt1 != T.maps.end(); ++mt1) {
       for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) {
@@ -934,26 +816,14 @@
       }
     }
 
-    // Constant(V1)->Is(Constant(V2)) iff V1 = V2
-    for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) {
-      for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) {
-        Handle<i::Object> value1 = *vt1;
-        Handle<i::Object> value2 = *vt2;
-        TypeHandle const_type1 = T.Constant(value1);
-        TypeHandle const_type2 = T.Constant(value2);
-        CHECK(const_type1->Is(const_type2) == (*value1 == *value2));
-      }
-    }
-
-    // Range(min1, max1)->Is(Range(min2, max2)) iff
-    // min1 >= min2 /\ max1 <= max2
+    // Range(X1, Y1)->Is(Range(X2, Y2)) iff X1 >= X2 /\ Y1 <= Y2
     for (ValueIterator i1 = T.integers.begin();
         i1 != T.integers.end(); ++i1) {
-      for (ValueIterator j1 = T.integers.begin();
+      for (ValueIterator j1 = i1;
           j1 != T.integers.end(); ++j1) {
         for (ValueIterator i2 = T.integers.begin();
              i2 != T.integers.end(); ++i2) {
-          for (ValueIterator j2 = T.integers.begin();
+          for (ValueIterator j2 = i2;
                j2 != T.integers.end(); ++j2) {
             i::Handle<i::Object> min1 = *i1;
             i::Handle<i::Object> max1 = *j1;
@@ -964,13 +834,24 @@
             TypeHandle type1 = T.Range(min1, max1);
             TypeHandle type2 = T.Range(min2, max2);
             CHECK(type1->Is(type2) ==
-                (min2->Number() <= min1->Number() &&
+                (min1->Number() >= min2->Number() &&
                  max1->Number() <= max2->Number()));
           }
         }
       }
     }
 
+    // Constant(V1)->Is(Constant(V2)) iff V1 = V2
+    for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) {
+      for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) {
+        Handle<i::Object> value1 = *vt1;
+        Handle<i::Object> value2 = *vt2;
+        TypeHandle const_type1 = T.Constant(value1);
+        TypeHandle const_type2 = T.Constant(value2);
+        CHECK(const_type1->Is(const_type2) == (*value1 == *value2));
+      }
+    }
+
     // Context(T1)->Is(Context(T2)) iff T1 = T2
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1007,25 +888,45 @@
       }
     }
 
-    // (In-)Compatibilities.
-    for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) {
-      for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) {
-        TypeHandle type1 = *i;
-        TypeHandle type2 = *j;
-        CHECK(!type1->Is(type2) || this->IsBitset(type2) ||
-              this->IsUnion(type2) || this->IsUnion(type1) ||
-              (type1->IsClass() && type2->IsClass()) ||
-              (type1->IsConstant() && type2->IsConstant()) ||
-              (type1->IsConstant() && type2->IsRange()) ||
-              (type1->IsRange() && type2->IsRange()) ||
-              (type1->IsContext() && type2->IsContext()) ||
-              (type1->IsArray() && type2->IsArray()) ||
-              (type1->IsFunction() && type2->IsFunction()) ||
-              type1->Equals(T.None));
+
+    // Range-specific subtyping
+
+    // If IsInteger(v) then Constant(v)->Is(Range(v, v)).
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsConstant() && IsInteger(*type->AsConstant()->Value())) {
+        CHECK(type->Is(
+            T.Range(type->AsConstant()->Value(), type->AsConstant()->Value())));
       }
     }
 
-    // Basic types
+    // If Constant(x)->Is(Range(min,max)) then IsInteger(v) and min <= x <= max.
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (type1->IsConstant() && type2->IsRange() && type1->Is(type2)) {
+          double x = type1->AsConstant()->Value()->Number();
+          double min = type2->AsRange()->Min()->Number();
+          double max = type2->AsRange()->Max()->Number();
+          CHECK(IsInteger(x) && min <= x && x <= max);
+        }
+      }
+    }
+
+    // Lub(Range(x,y))->Is(T.Union(T.Integral32, T.OtherNumber))
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsRange()) {
+        TypeHandle lub = Rep::BitsetType::New(
+            Rep::BitsetType::Lub(type), T.region());
+        CHECK(lub->Is(T.PlainNumber));
+      }
+    }
+
+
+    // Subtyping between concrete basic types
+
     CheckUnordered(T.Boolean, T.Null);
     CheckUnordered(T.Undefined, T.Null);
     CheckUnordered(T.Boolean, T.Undefined);
@@ -1049,12 +950,12 @@
 
     CheckSub(T.Object, T.Receiver);
     CheckSub(T.Array, T.Object);
-    CheckSub(T.Function, T.Object);
     CheckSub(T.Proxy, T.Receiver);
     CheckUnordered(T.Object, T.Proxy);
-    CheckUnordered(T.Array, T.Function);
 
-    // Structural types
+
+    // Subtyping between concrete structural types
+
     CheckSub(T.ObjectClass, T.Object);
     CheckSub(T.ArrayClass, T.Object);
     CheckSub(T.ArrayClass, T.Array);
@@ -1086,7 +987,7 @@
     CheckSub(T.NumberArray, T.Object);
     CheckUnordered(T.StringArray, T.AnyArray);
 
-    CheckSub(T.MethodFunction, T.Function);
+    CheckSub(T.MethodFunction, T.Object);
     CheckSub(T.NumberFunction1, T.Object);
     CheckUnordered(T.SignedFunction1, T.NumberFunction1);
     CheckUnordered(T.NumberFunction1, T.NumberFunction2);
@@ -1372,10 +1273,8 @@
     CheckDisjoint(T.InternalizedString, T.Symbol);
     CheckOverlap(T.Object, T.Receiver);
     CheckOverlap(T.Array, T.Object);
-    CheckOverlap(T.Function, T.Object);
     CheckOverlap(T.Proxy, T.Receiver);
     CheckDisjoint(T.Object, T.Proxy);
-    CheckDisjoint(T.Array, T.Function);
 
     // Structural types
     CheckOverlap(T.ObjectClass, T.Object);
@@ -1399,7 +1298,7 @@
     CheckOverlap(T.NumberArray, T.Array);
     CheckDisjoint(T.NumberArray, T.AnyArray);
     CheckDisjoint(T.NumberArray, T.StringArray);
-    CheckOverlap(T.MethodFunction, T.Function);
+    CheckOverlap(T.MethodFunction, T.Object);
     CheckDisjoint(T.SignedFunction1, T.NumberFunction1);
     CheckDisjoint(T.SignedFunction1, T.NumberFunction2);
     CheckDisjoint(T.NumberFunction1, T.NumberFunction2);
@@ -1443,7 +1342,9 @@
     }
 
     // Associativity: Union(T1, Union(T2, T3)) = Union(Union(T1, T2), T3)
-    // This does NOT hold!
+    // This does NOT hold!  For example:
+    // (Unsigned32 \/ Range(0,5)) \/ Range(-5,0) = Unsigned32 \/ Range(-5,0)
+    // Unsigned32 \/ (Range(0,5) \/ Range(-5,0)) = Unsigned32 \/ Range(-5,5)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1483,7 +1384,9 @@
     }
 
     // Monotonicity: T1->Is(T2) implies Union(T1, T3)->Is(Union(T2, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Range(-5,-1) <= Signed32
+    // Range(-5,-1) \/ Range(1,5) = Range(-5,5) </= Signed32 \/ Range(1,5)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1502,8 +1405,10 @@
 
   void Union2() {
     // Monotonicity: T1->Is(T3) and T2->Is(T3) implies Union(T1, T2)->Is(T3)
-    // This does NOT hold.  TODO(neis): Could fix this by splitting
-    // OtherNumber into a negative and a positive part.
+    // This does NOT hold.  For example:
+    // Range(-2^33, -2^33) <= OtherNumber
+    // Range(2^33, 2^33) <= OtherNumber
+    // Range(-2^33, 2^33) </= OtherNumber
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1523,7 +1428,7 @@
     // Monotonicity: T1->Is(T2) or T1->Is(T3) implies T1->Is(Union(T2, T3))
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
-        for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
+        for (TypeIterator it3 = it2; it3 != T.types.end(); ++it3) {
           TypeHandle type1 = *it1;
           TypeHandle type2 = *it2;
           TypeHandle type3 = *it3;
@@ -1563,11 +1468,11 @@
     CheckDisjoint(T.Union(T.NumberArray, T.String), T.Number);
 
     // Bitset-function
-    CHECK(this->IsBitset(T.Union(T.MethodFunction, T.Function)));
+    CHECK(this->IsBitset(T.Union(T.MethodFunction, T.Object)));
     CHECK(this->IsUnion(T.Union(T.NumberFunction1, T.Number)));
 
-    CheckEqual(T.Union(T.MethodFunction, T.Function), T.Function);
-    CheckUnordered(T.Union(T.NumberFunction1, T.String), T.Function);
+    CheckEqual(T.Union(T.MethodFunction, T.Object), T.Object);
+    CheckUnordered(T.Union(T.NumberFunction1, T.String), T.Object);
     CheckOverlap(T.Union(T.NumberFunction2, T.String), T.Object);
     CheckDisjoint(T.Union(T.NumberFunction1, T.String), T.Number);
 
@@ -1635,7 +1540,7 @@
     CheckEqual(
         T.Union(T.NumberFunction1, T.NumberFunction2),
         T.Union(T.NumberFunction2, T.NumberFunction1));
-    CheckSub(T.Union(T.SignedFunction1, T.MethodFunction), T.Function);
+    CheckSub(T.Union(T.SignedFunction1, T.MethodFunction), T.Object);
 
     // Union-union
     CheckEqual(
@@ -1685,7 +1590,11 @@
 
     // Associativity:
     // Intersect(T1, Intersect(T2, T3)) = Intersect(Intersect(T1, T2), T3)
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // (Class(..stringy1..) /\ Class(..stringy2..)) /\ Constant(..string..) =
+    // None
+    // Class(..stringy1..) /\ (Class(..stringy2..) /\ Constant(..string..)) =
+    // Constant(..string..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1704,7 +1613,11 @@
     */
 
     // Join: Intersect(T1, T2)->Is(T1) and Intersect(T1, T2)->Is(T2)
-    // This does NOT hold.  Not even the disjunction.
+    // This does NOT hold.  For example:
+    // Class(..stringy..) /\ Constant(..string..) = Constant(..string..)
+    // Currently, not even the disjunction holds:
+    // Class(Internal/TaggedPtr) /\ (Any/Untagged \/ Context(..)) =
+    // Class(Internal/TaggedPtr) \/ Context(..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1728,7 +1641,10 @@
     }
 
     // Monotonicity: T1->Is(T2) implies Intersect(T1, T3)->Is(Intersect(T2, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Class(OtherObject/TaggedPtr) <= Any/TaggedPtr
+    // Class(OtherObject/TaggedPtr) /\ Any/UntaggedInt1 = Class(..)
+    // Any/TaggedPtr /\ Any/UntaggedInt1 = None
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1745,7 +1661,10 @@
     */
 
     // Monotonicity: T1->Is(T3) or T2->Is(T3) implies Intersect(T1, T2)->Is(T3)
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Class(..stringy..) <= Class(..stringy..)
+    // Class(..stringy..) /\ Constant(..string..) = Constant(..string..)
+    // Constant(..string..) </= Class(..stringy..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1762,8 +1681,6 @@
     */
 
     // Monotonicity: T1->Is(T2) and T1->Is(T3) implies T1->Is(Intersect(T2, T3))
-    // This does NOT hold.
-    /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
         for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
@@ -1776,7 +1693,6 @@
         }
       }
     }
-    */
 
     // Bitset-class
     CheckEqual(T.Intersect(T.ObjectClass, T.Object), T.ObjectClass);
@@ -1785,11 +1701,11 @@
 
     // Bitset-array
     CheckEqual(T.Intersect(T.NumberArray, T.Object), T.NumberArray);
-    CheckEqual(T.Intersect(T.AnyArray, T.Function), T.None);
+    CheckEqual(T.Intersect(T.AnyArray, T.Proxy), T.None);
 
     // Bitset-function
     CheckEqual(T.Intersect(T.MethodFunction, T.Object), T.MethodFunction);
-    CheckEqual(T.Intersect(T.NumberFunction1, T.Array), T.None);
+    CheckEqual(T.Intersect(T.NumberFunction1, T.Proxy), T.None);
 
     // Bitset-union
     CheckEqual(
@@ -1880,7 +1796,11 @@
 
   void Distributivity() {
     // Union(T1, Intersect(T2, T3)) = Intersect(Union(T1, T2), Union(T1, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Untagged \/ (Untagged /\ Class(../Tagged)) = Untagged \/ Class(../Tagged)
+    // (Untagged \/ Untagged) /\ (Untagged \/ Class(../Tagged)) =
+    // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged
+    // because Untagged <= Untagged \/ Class(../Tagged)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1900,7 +1820,10 @@
     */
 
     // Intersect(T1, Union(T2, T3)) = Union(Intersect(T1, T2), Intersect(T1,T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged
+    // (Untagged /\ Untagged) \/ (Untagged /\ Class(../Tagged)) =
+    // Untagged \/ Class(../Tagged)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1920,6 +1843,32 @@
     */
   }
 
+  void GetRange() {
+    // GetRange(Range(a, b)) = Range(a, b).
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      TypeHandle type1 = *it1;
+      if (type1->IsRange()) {
+        typename Type::RangeType* range = type1->GetRange();
+        CHECK(type1->Min() == range->Min()->Number());
+        CHECK(type1->Max() == range->Max()->Number());
+      }
+    }
+
+    // GetRange(Union(Constant(x), Range(min,max))) == Range(min, max).
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (type1->IsConstant() && type2->IsRange()) {
+          TypeHandle u = T.Union(type1, type2);
+
+          CHECK(type2->Min() == u->GetRange()->Min()->Number());
+          CHECK(type2->Max() == u->GetRange()->Max()->Number());
+        }
+      }
+    }
+  }
+
   template<class Type2, class TypeHandle2, class Region2, class Rep2>
   void Convert() {
     Types<Type2, TypeHandle2, Region2> T2(
@@ -2012,6 +1961,13 @@
 }
 
 
+TEST(MinMax) {
+  CcTest::InitializeVM();
+  ZoneTests().MinMax();
+  HeapTests().MinMax();
+}
+
+
 TEST(BitsetGlb) {
   CcTest::InitializeVM();
   ZoneTests().BitsetGlb();
@@ -2026,10 +1982,17 @@
 }
 
 
-TEST(Is) {
+TEST(Is1) {
   CcTest::InitializeVM();
-  ZoneTests().Is();
-  HeapTests().Is();
+  ZoneTests().Is1();
+  HeapTests().Is1();
+}
+
+
+TEST(Is2) {
+  CcTest::InitializeVM();
+  ZoneTests().Is2();
+  HeapTests().Is2();
 }
 
 
@@ -2098,13 +2061,18 @@
 }
 
 
-/*
 TEST(Distributivity) {
   CcTest::InitializeVM();
   ZoneTests().Distributivity();
   HeapTests().Distributivity();
 }
-*/
+
+
+TEST(GetRange) {
+  CcTest::InitializeVM();
+  ZoneTests().GetRange();
+  HeapTests().GetRange();
+}
 
 
 TEST(Convert) {
diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc
new file mode 100644
index 0000000..a12bf47
--- /dev/null
+++ b/test/cctest/test-unboxed-doubles.cc
@@ -0,0 +1,1162 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+#include <utility>
+
+#include "src/v8.h"
+
+#include "src/compilation-cache.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "src/ic/ic.h"
+#include "src/macro-assembler.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::base;
+using namespace v8::internal;
+
+#if (V8_DOUBLE_FIELDS_UNBOXING)
+
+
+static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
+  if (obj->IsUnboxedDoubleField(field_index)) {
+    return obj->RawFastDoublePropertyAt(field_index);
+  } else {
+    Object* value = obj->RawFastPropertyAt(field_index);
+    DCHECK(value->IsMutableHeapNumber());
+    return HeapNumber::cast(value)->value();
+  }
+}
+
+const int kNumberOfBits = 32;
+
+
+enum TestPropertyKind {
+  PROP_CONSTANT,
+  PROP_SMI,
+  PROP_DOUBLE,
+  PROP_TAGGED,
+  PROP_KIND_NUMBER
+};
+
+static Representation representations[PROP_KIND_NUMBER] = {
+    Representation::None(), Representation::Smi(), Representation::Double(),
+    Representation::Tagged()};
+
+
+static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate,
+                                                     TestPropertyKind* props,
+                                                     int kPropsCount) {
+  Factory* factory = isolate->factory();
+
+  Handle<String> func_name = factory->InternalizeUtf8String("func");
+  Handle<JSFunction> func = factory->NewFunction(func_name);
+
+  Handle<DescriptorArray> descriptors =
+      DescriptorArray::Allocate(isolate, 0, kPropsCount);
+
+  int next_field_offset = 0;
+  for (int i = 0; i < kPropsCount; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+
+    TestPropertyKind kind = props[i];
+
+    if (kind == PROP_CONSTANT) {
+      ConstantDescriptor d(name, func, NONE);
+      descriptors->Append(&d);
+
+    } else {
+      FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
+      next_field_offset += f.GetDetails().field_width_in_words();
+      descriptors->Append(&f);
+    }
+  }
+  return descriptors;
+}
+
+
+TEST(LayoutDescriptorBasicFast) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
+
+  CHECK(!layout_desc->IsSlowLayout());
+  CHECK(layout_desc->IsFastPointerLayout());
+  CHECK_EQ(kSmiValueSize, layout_desc->capacity());
+
+  for (int i = 0; i < kSmiValueSize + 13; i++) {
+    CHECK_EQ(true, layout_desc->IsTagged(i));
+  }
+  CHECK_EQ(true, layout_desc->IsTagged(-1));
+  CHECK_EQ(true, layout_desc->IsTagged(-12347));
+  CHECK_EQ(true, layout_desc->IsTagged(15635));
+  CHECK(layout_desc->IsFastPointerLayout());
+
+  for (int i = 0; i < kSmiValueSize; i++) {
+    layout_desc = layout_desc->SetTaggedForTesting(i, false);
+    CHECK_EQ(false, layout_desc->IsTagged(i));
+    layout_desc = layout_desc->SetTaggedForTesting(i, true);
+    CHECK_EQ(true, layout_desc->IsTagged(i));
+  }
+  CHECK(layout_desc->IsFastPointerLayout());
+
+  int sequence_length;
+  CHECK_EQ(true, layout_desc->IsTagged(0, std::numeric_limits<int>::max(),
+                                       &sequence_length));
+  CHECK_EQ(std::numeric_limits<int>::max(), sequence_length);
+
+  CHECK_EQ(true, layout_desc->IsTagged(0, 7, &sequence_length));
+  CHECK_EQ(7, sequence_length);
+}
+
+
+TEST(LayoutDescriptorBasicSlow) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    // All properties tagged.
+    props[i] = PROP_TAGGED;
+  }
+
+  {
+    Handle<DescriptorArray> descriptors =
+        CreateDescriptorArray(isolate, props, kPropsCount);
+
+    Handle<Map> map = Map::Create(isolate, kPropsCount);
+
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK_EQ(kSmiValueSize, layout_descriptor->capacity());
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  props[0] = PROP_DOUBLE;
+  props[kPropsCount - 1] = PROP_DOUBLE;
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    int inobject_properties = kPropsCount - 1;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+    // Should be fast as the only double property is the first one.
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK(!layout_descriptor->IsFastPointerLayout());
+
+    CHECK_EQ(false, layout_descriptor->IsTagged(0));
+    for (int i = 1; i < kPropsCount; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    int inobject_properties = kPropsCount;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(layout_descriptor->IsSlowLayout());
+    CHECK(!layout_descriptor->IsFastPointerLayout());
+    CHECK(layout_descriptor->capacity() > kSmiValueSize);
+
+    CHECK_EQ(false, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(kPropsCount - 1));
+    for (int i = 1; i < kPropsCount - 1; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+    // Here we have truly slow layout descriptor, so play with the bits.
+    CHECK_EQ(true, layout_descriptor->IsTagged(-1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(-12347));
+    CHECK_EQ(true, layout_descriptor->IsTagged(15635));
+
+    LayoutDescriptor* layout_desc = *layout_descriptor;
+    // Play with the bits but leave it in consistent state with map at the end.
+    for (int i = 1; i < kPropsCount - 1; i++) {
+      layout_desc = layout_desc->SetTaggedForTesting(i, false);
+      CHECK_EQ(false, layout_desc->IsTagged(i));
+      layout_desc = layout_desc->SetTaggedForTesting(i, true);
+      CHECK_EQ(true, layout_desc->IsTagged(i));
+    }
+    CHECK(layout_desc->IsSlowLayout());
+    CHECK(!layout_desc->IsFastPointerLayout());
+
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+}
+
+
+static void TestLayoutDescriptorQueries(int layout_descriptor_length,
+                                        int* bit_flip_positions,
+                                        int max_sequence_length) {
+  Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::NewForTesting(
+      CcTest::i_isolate(), layout_descriptor_length);
+  layout_descriptor_length = layout_descriptor->capacity();
+  LayoutDescriptor* layout_desc = *layout_descriptor;
+
+  {
+    // Fill in the layout descriptor.
+    int cur_bit_flip_index = 0;
+    bool tagged = true;
+    for (int i = 0; i < layout_descriptor_length; i++) {
+      if (i == bit_flip_positions[cur_bit_flip_index]) {
+        tagged = !tagged;
+        ++cur_bit_flip_index;
+        CHECK(i < bit_flip_positions[cur_bit_flip_index]);  // check test data
+      }
+      layout_desc = layout_desc->SetTaggedForTesting(i, tagged);
+    }
+  }
+
+  if (layout_desc->IsFastPointerLayout()) {
+    return;
+  }
+
+  {
+    // Check queries.
+    int cur_bit_flip_index = 0;
+    bool tagged = true;
+    for (int i = 0; i < layout_descriptor_length; i++) {
+      if (i == bit_flip_positions[cur_bit_flip_index]) {
+        tagged = !tagged;
+        ++cur_bit_flip_index;
+      }
+      CHECK_EQ(tagged, layout_desc->IsTagged(i));
+
+      int next_bit_flip_position = bit_flip_positions[cur_bit_flip_index];
+      int expected_sequence_length;
+      if (next_bit_flip_position < layout_desc->capacity()) {
+        expected_sequence_length = next_bit_flip_position - i;
+      } else {
+        expected_sequence_length = tagged ? std::numeric_limits<int>::max()
+                                          : (layout_desc->capacity() - i);
+      }
+      expected_sequence_length =
+          Min(expected_sequence_length, max_sequence_length);
+      int sequence_length;
+      CHECK_EQ(tagged,
+               layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
+      CHECK(sequence_length > 0);
+
+      CHECK_EQ(expected_sequence_length, sequence_length);
+    }
+
+    int sequence_length;
+    CHECK_EQ(true,
+             layout_desc->IsTagged(layout_descriptor_length,
+                                   max_sequence_length, &sequence_length));
+    CHECK_EQ(max_sequence_length, sequence_length);
+  }
+}
+
+
+static void TestLayoutDescriptorQueriesFast(int max_sequence_length) {
+  {
+    LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
+    int sequence_length;
+    for (int i = 0; i < kNumberOfBits; i++) {
+      CHECK_EQ(true,
+               layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
+      CHECK(sequence_length > 0);
+      CHECK_EQ(max_sequence_length, sequence_length);
+    }
+  }
+
+  {
+    int bit_flip_positions[] = {1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kNumberOfBits + 1];
+    for (int i = 0; i <= kNumberOfBits; i++) {
+      bit_flip_positions[i] = i;
+    }
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {3, 7, 8, 10, 15, 21, 30, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0,  1,  2,  3,  5,  7,  9,
+                                12, 15, 18, 22, 26, 29, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+}
+
+
+TEST(LayoutDescriptorQueriesFastLimited7) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(7);
+}
+
+
+TEST(LayoutDescriptorQueriesFastLimited13) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(13);
+}
+
+
+TEST(LayoutDescriptorQueriesFastUnlimited) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(std::numeric_limits<int>::max());
+}
+
+
+static void TestLayoutDescriptorQueriesSlow(int max_sequence_length) {
+  {
+    int bit_flip_positions[] = {10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = i;
+    }
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {3,  7,  8,  10, 15,  21,   30,
+                                37, 54, 80, 99, 383, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0,   10,  20,  30,  50,  70,  90,
+                                120, 150, 180, 220, 260, 290, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    int cur = 0;
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = cur;
+      cur = (cur + 1) * 2;
+    }
+    CHECK(cur < 10000);
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    int cur = 3;
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = cur;
+      cur = (cur + 1) * 2;
+    }
+    CHECK(cur < 10000);
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited7) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(7);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited13) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(13);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited42) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(42);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowUnlimited) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(std::numeric_limits<int>::max());
+}
+
+
+TEST(LayoutDescriptorCreateNewFast) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  TestPropertyKind props[] = {
+      PROP_CONSTANT,
+      PROP_TAGGED,  // field #0
+      PROP_CONSTANT,
+      PROP_DOUBLE,  // field #1
+      PROP_CONSTANT,
+      PROP_TAGGED,  // field #2
+      PROP_CONSTANT,
+  };
+  const int kPropsCount = arraysize(props);
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    Handle<Map> map = Map::Create(isolate, 0);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 1);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 2);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK_EQ(true, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(2));
+    CHECK_EQ(true, layout_descriptor->IsTagged(125));
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+}
+
+
+TEST(LayoutDescriptorCreateNewSlow) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    Handle<Map> map = Map::Create(isolate, 0);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 1);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 2);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK_EQ(true, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(2));
+    CHECK_EQ(true, layout_descriptor->IsTagged(125));
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    int inobject_properties = kPropsCount / 2;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(layout_descriptor->IsSlowLayout());
+    for (int i = 0; i < inobject_properties; i++) {
+      // PROP_DOUBLE has index 1 among FIELD properties.
+      const bool tagged = (i % (PROP_KIND_NUMBER - 1)) != 1;
+      CHECK_EQ(tagged, layout_descriptor->IsTagged(i));
+    }
+    // Every property after inobject_properties must be tagged.
+    for (int i = inobject_properties; i < kPropsCount; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+    // Now test LayoutDescriptor::cast_gc_safe().
+    Handle<LayoutDescriptor> layout_descriptor_copy =
+        LayoutDescriptor::New(map, descriptors, kPropsCount);
+
+    LayoutDescriptor* layout_desc = *layout_descriptor;
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
+    CHECK(layout_descriptor->IsFixedTypedArrayBase());
+    // Now make it look like a forwarding pointer to layout_descriptor_copy.
+    MapWord map_word = layout_desc->map_word();
+    CHECK(!map_word.IsForwardingAddress());
+    layout_desc->set_map_word(
+        MapWord::FromForwardingAddress(*layout_descriptor_copy));
+    CHECK(layout_desc->map_word().IsForwardingAddress());
+    CHECK_EQ(*layout_descriptor_copy,
+             LayoutDescriptor::cast_gc_safe(layout_desc));
+
+    // Restore it back.
+    layout_desc->set_map_word(map_word);
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
+  }
+}
+
+
+static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
+    Isolate* isolate, int inobject_properties, TestPropertyKind* props,
+    int kPropsCount) {
+  Factory* factory = isolate->factory();
+
+  Handle<String> func_name = factory->InternalizeUtf8String("func");
+  Handle<JSFunction> func = factory->NewFunction(func_name);
+
+  Handle<DescriptorArray> descriptors =
+      DescriptorArray::Allocate(isolate, 0, kPropsCount);
+
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+  map->InitializeDescriptors(*descriptors,
+                             LayoutDescriptor::FastPointerLayout());
+
+  int next_field_offset = 0;
+  for (int i = 0; i < kPropsCount; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+
+    Handle<LayoutDescriptor> layout_descriptor;
+    TestPropertyKind kind = props[i];
+    if (kind == PROP_CONSTANT) {
+      ConstantDescriptor d(name, func, NONE);
+      layout_descriptor = LayoutDescriptor::Append(map, d.GetDetails());
+      descriptors->Append(&d);
+
+    } else {
+      FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
+      int field_width_in_words = f.GetDetails().field_width_in_words();
+      next_field_offset += field_width_in_words;
+      layout_descriptor = LayoutDescriptor::Append(map, f.GetDetails());
+      descriptors->Append(&f);
+
+      int field_index = f.GetDetails().field_index();
+      bool is_inobject = field_index < map->inobject_properties();
+      for (int bit = 0; bit < field_width_in_words; bit++) {
+        CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
+                 !layout_descriptor->IsTagged(field_index + bit));
+      }
+      CHECK(layout_descriptor->IsTagged(next_field_offset));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+  }
+  Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  return layout_descriptor;
+}
+
+
+TEST(LayoutDescriptorAppend) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+}
+
+
+TEST(LayoutDescriptorAppendAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  {
+    // Ensure layout descriptor switches into slow mode at the right moment.
+    layout_descriptor =
+        TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize);
+    CHECK(!layout_descriptor->IsSlowLayout());
+
+    layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
+                                                   kSmiValueSize + 1);
+    CHECK(layout_descriptor->IsSlowLayout());
+  }
+}
+
+
+static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull(
+    Isolate* isolate, int inobject_properties,
+    Handle<DescriptorArray> descriptors, int number_of_descriptors) {
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+  Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New(
+      map, descriptors, descriptors->number_of_descriptors());
+
+  int nof = 0;
+  bool switched_to_slow_mode = false;
+
+  for (int i = 0; i < number_of_descriptors; i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+
+    // This method calls LayoutDescriptor::AppendIfFastOrUseFull() internally
+    // and does all the required map-descriptors related book keeping.
+    map = Map::CopyInstallDescriptorsForTesting(map, i, descriptors,
+                                                full_layout_descriptor);
+
+    LayoutDescriptor* layout_desc = map->layout_descriptor();
+
+    if (layout_desc->IsSlowLayout()) {
+      switched_to_slow_mode = true;
+      CHECK_EQ(*full_layout_descriptor, layout_desc);
+    } else {
+      CHECK(!switched_to_slow_mode);
+      if (details.type() == FIELD) {
+        nof++;
+        int field_index = details.field_index();
+        int field_width_in_words = details.field_width_in_words();
+
+        bool is_inobject = field_index < map->inobject_properties();
+        for (int bit = 0; bit < field_width_in_words; bit++) {
+          CHECK_EQ(is_inobject && details.representation().IsDouble(),
+                   !layout_desc->IsTagged(field_index + bit));
+        }
+        CHECK(layout_desc->IsTagged(field_index + field_width_in_words));
+      }
+    }
+    DCHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
+  }
+
+  Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
+                                             isolate);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  return layout_descriptor;
+}
+
+
+TEST(LayoutDescriptorAppendIfFastOrUseFull) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 0, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 13, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize * 2, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kPropsCount, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+}
+
+
+TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 0, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 13, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize + 1, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize * 2, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kPropsCount, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  {
+    // Ensure layout descriptor switches into slow mode at the right moment.
+    layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+        isolate, kPropsCount, descriptors, kSmiValueSize);
+    CHECK(!layout_descriptor->IsSlowLayout());
+
+    layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+        isolate, kPropsCount, descriptors, kSmiValueSize + 1);
+    CHECK(layout_descriptor->IsSlowLayout());
+  }
+}
+
+
+TEST(Regress436816) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  Handle<Map> map = Map::Create(isolate, kPropsCount);
+  Handle<LayoutDescriptor> layout_descriptor =
+      LayoutDescriptor::New(map, descriptors, kPropsCount);
+  map->InitializeDescriptors(*descriptors, *layout_descriptor);
+
+  Handle<JSObject> object = factory->NewJSObjectFromMap(map, TENURED);
+
+  Address fake_address = reinterpret_cast<Address>(~kHeapObjectTagMask);
+  HeapObject* fake_object = HeapObject::FromAddress(fake_address);
+  CHECK(fake_object->IsHeapObject());
+
+  double boom_value = bit_cast<double>(fake_object);
+  for (int i = 0; i < kPropsCount; i++) {
+    FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+    CHECK(map->IsUnboxedDoubleField(index));
+    object->RawFastDoublePropertyAtPut(index, boom_value);
+  }
+  CHECK(object->HasFastProperties());
+  CHECK(!object->map()->HasFastPointerLayout());
+
+  Handle<Map> normalized_map =
+      Map::Normalize(map, KEEP_INOBJECT_PROPERTIES, "testing");
+  JSObject::MigrateToMap(object, normalized_map);
+  CHECK(!object->HasFastProperties());
+  CHECK(object->map()->HasFastPointerLayout());
+
+  // Trigger GCs and heap verification.
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+}
+
+
+TEST(DoScavenge) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  CompileRun(
+      "function A() {"
+      "  this.x = 42.5;"
+      "  this.o = {};"
+      "};"
+      "var o = new A();");
+
+  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+
+  Handle<Object> obj_value =
+      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
+  CHECK(obj_value->IsJSObject());
+  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+
+  {
+    // Ensure the object is properly set up.
+    Map* map = obj->map();
+    DescriptorArray* descriptors = map->instance_descriptors();
+    CHECK(map->NumberOfOwnDescriptors() == 2);
+    CHECK(descriptors->GetDetails(0).representation().IsDouble());
+    CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
+    FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
+    CHECK(field_index.is_inobject() && field_index.is_double());
+    CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
+    CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
+  }
+  CHECK(isolate->heap()->new_space()->Contains(*obj));
+
+  // Trigger GCs so that the newly allocated object moves to old gen.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
+
+  // Create temp object in the new space.
+  Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
+  CHECK(isolate->heap()->new_space()->Contains(*temp));
+
+  // Construct a double value that looks like a pointer to the new space object
+  // and store it into the obj.
+  Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
+  double boom_value = bit_cast<double>(fake_object);
+
+  FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
+  Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
+  obj->FastPropertyAtPut(field_index, *boom_number);
+
+  // Now the object moves to old gen and it has a double field that looks like
+  // a pointer to a from semi-space.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
+
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
+
+  CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
+}
+
+
+static void TestLayoutDescriptorHelper(Isolate* isolate,
+                                       int inobject_properties,
+                                       Handle<DescriptorArray> descriptors,
+                                       int number_of_descriptors) {
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+  Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
+      map, descriptors, descriptors->number_of_descriptors());
+  map->InitializeDescriptors(*descriptors, *layout_descriptor);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+  LayoutDescriptorHelper helper(*map);
+  bool all_fields_tagged = true;
+
+  int instance_size = map->instance_size();
+
+  int end_offset = instance_size * 2;
+  int first_non_tagged_field_offset = end_offset;
+  for (int i = 0; i < number_of_descriptors; i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+    if (details.type() != FIELD) continue;
+    FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+    if (!index.is_inobject()) continue;
+    all_fields_tagged &= !details.representation().IsDouble();
+    bool expected_tagged = !index.is_double();
+    if (!expected_tagged) {
+      first_non_tagged_field_offset =
+          Min(first_non_tagged_field_offset, index.offset());
+    }
+
+    int end_of_region_offset;
+    CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
+    CHECK_EQ(expected_tagged, helper.IsTagged(index.offset(), instance_size,
+                                              &end_of_region_offset));
+    CHECK(end_of_region_offset > 0);
+    CHECK(end_of_region_offset % kPointerSize == 0);
+    CHECK(end_of_region_offset <= instance_size);
+
+    for (int offset = index.offset(); offset < end_of_region_offset;
+         offset += kPointerSize) {
+      CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
+    }
+    if (end_of_region_offset < instance_size) {
+      CHECK_EQ(!expected_tagged, helper.IsTagged(end_of_region_offset));
+    } else {
+      CHECK_EQ(true, helper.IsTagged(end_of_region_offset));
+    }
+  }
+
+  for (int offset = 0; offset < JSObject::kHeaderSize; offset += kPointerSize) {
+    // Header queries
+    CHECK_EQ(true, helper.IsTagged(offset));
+    int end_of_region_offset;
+    CHECK_EQ(true, helper.IsTagged(offset, end_offset, &end_of_region_offset));
+    CHECK_EQ(first_non_tagged_field_offset, end_of_region_offset);
+
+    // Out of bounds queries
+    CHECK_EQ(true, helper.IsTagged(offset + instance_size));
+  }
+
+  CHECK_EQ(all_fields_tagged, helper.all_fields_tagged());
+}
+
+
+TEST(LayoutDescriptorHelperMixed) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(LayoutDescriptorHelperAllTagged) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_TAGGED;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(LayoutDescriptorHelperAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(StoreBufferScanOnScavenge) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  CompileRun(
+      "function A() {"
+      "  this.x = 42.5;"
+      "  this.o = {};"
+      "};"
+      "var o = new A();");
+
+  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+
+  Handle<Object> obj_value =
+      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
+  CHECK(obj_value->IsJSObject());
+  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+
+  {
+    // Ensure the object is properly set up.
+    Map* map = obj->map();
+    DescriptorArray* descriptors = map->instance_descriptors();
+    CHECK(map->NumberOfOwnDescriptors() == 2);
+    CHECK(descriptors->GetDetails(0).representation().IsDouble());
+    CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
+    FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
+    CHECK(field_index.is_inobject() && field_index.is_double());
+    CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
+    CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
+  }
+  CHECK(isolate->heap()->new_space()->Contains(*obj));
+
+  // Trigger GCs so that the newly allocated object moves to old gen.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
+
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
+
+  // Create temp object in the new space.
+  Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
+  CHECK(isolate->heap()->new_space()->Contains(*temp));
+
+  // Construct a double value that looks like a pointer to the new space object
+  // and store it into the obj.
+  Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
+  double boom_value = bit_cast<double>(fake_object);
+
+  FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
+  Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
+  obj->FastPropertyAtPut(field_index, *boom_number);
+
+  // Enforce scan on scavenge for the obj's page.
+  MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
+  chunk->set_scan_on_scavenge(true);
+
+  // Trigger GCs and force evacuation. Should not crash there.
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
+}
+
+#endif
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index 9ea8b2b..05a12f5 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -76,6 +76,47 @@
 }
 
 
+TEST(BitSetComputer) {
+  typedef BitSetComputer<bool, 1, kSmiValueSize, uint32_t> BoolComputer;
+  CHECK_EQ(0, BoolComputer::word_count(0));
+  CHECK_EQ(1, BoolComputer::word_count(8));
+  CHECK_EQ(2, BoolComputer::word_count(50));
+  CHECK_EQ(0, BoolComputer::index(0, 8));
+  CHECK_EQ(100, BoolComputer::index(100, 8));
+  CHECK_EQ(1, BoolComputer::index(0, 40));
+  uint32_t data = 0;
+  data = BoolComputer::encode(data, 1, true);
+  data = BoolComputer::encode(data, 4, true);
+  CHECK_EQ(true, BoolComputer::decode(data, 1));
+  CHECK_EQ(true, BoolComputer::decode(data, 4));
+  CHECK_EQ(false, BoolComputer::decode(data, 0));
+  CHECK_EQ(false, BoolComputer::decode(data, 2));
+  CHECK_EQ(false, BoolComputer::decode(data, 3));
+
+  // Lets store 2 bits per item with 3000 items and verify the values are
+  // correct.
+  typedef BitSetComputer<unsigned char, 2, 8, unsigned char> TwoBits;
+  const int words = 750;
+  CHECK_EQ(words, TwoBits::word_count(3000));
+  const int offset = 10;
+  Vector<unsigned char> buffer = Vector<unsigned char>::New(offset + words);
+  memset(buffer.start(), 0, sizeof(unsigned char) * buffer.length());
+  for (int i = 0; i < words; i++) {
+    const int index = TwoBits::index(offset, i);
+    unsigned char data = buffer[index];
+    data = TwoBits::encode(data, i, i % 4);
+    buffer[index] = data;
+  }
+
+  for (int i = 0; i < words; i++) {
+    const int index = TwoBits::index(offset, i);
+    unsigned char data = buffer[index];
+    CHECK_EQ(i % 4, TwoBits::decode(data, i));
+  }
+  buffer.Dispose();
+}
+
+
 TEST(SNPrintF) {
   // Make sure that strings that are truncated because of too small
   // buffers are zero-terminated anyway.
@@ -222,8 +263,6 @@
 }
 
 
-// TODO(svenpanne) Unconditionally test this when our infrastructure is fixed.
-#if !V8_OS_NACL
 TEST(CPlusPlus11Features) {
   struct S {
     bool x;
@@ -256,4 +295,3 @@
     j += 11;
   }
 }
-#endif
diff --git a/test/cctest/test-weakmaps.cc b/test/cctest/test-weakmaps.cc
index bb412a8..6c19cb8 100644
--- a/test/cctest/test-weakmaps.cc
+++ b/test/cctest/test-weakmaps.cc
@@ -97,19 +97,20 @@
   }
   CHECK(!global_handles->IsWeak(key.location()));
 
-  // Put entry into weak map.
+  // Put two chained entries into weak map.
   {
     HandleScope scope(isolate);
-    PutIntoWeakMap(weakmap,
-                   Handle<JSObject>(JSObject::cast(*key)),
-                   Handle<Smi>(Smi::FromInt(23), isolate));
+    Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    Handle<JSObject> object = factory->NewJSObjectFromMap(map);
+    PutIntoWeakMap(weakmap, Handle<JSObject>(JSObject::cast(*key)), object);
+    PutIntoWeakMap(weakmap, object, Handle<Smi>(Smi::FromInt(23), isolate));
   }
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
 
   // Force a full GC.
   heap->CollectAllGarbage(false);
   CHECK_EQ(0, NumberOfWeakCalls);
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
   CHECK_EQ(
       0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
 
@@ -128,14 +129,14 @@
   // weak references whereas the second one will also clear weak maps.
   heap->CollectAllGarbage(false);
   CHECK_EQ(1, NumberOfWeakCalls);
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
   CHECK_EQ(
       0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
   heap->CollectAllGarbage(false);
   CHECK_EQ(1, NumberOfWeakCalls);
   CHECK_EQ(0, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
-  CHECK_EQ(
-      1, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
+  CHECK_EQ(2,
+           ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
 }
 
 
diff --git a/test/cctest/trace-extension.cc b/test/cctest/trace-extension.cc
index 8f390e4..0a1ff87 100644
--- a/test/cctest/trace-extension.cc
+++ b/test/cctest/trace-extension.cc
@@ -91,7 +91,8 @@
   // sp is only used to define stack high bound
   regs.sp =
       reinterpret_cast<Address>(trace_env.sample) - 10240;
-  trace_env.sample->Init(CcTest::i_isolate(), regs);
+  trace_env.sample->Init(CcTest::i_isolate(), regs,
+                         TickSample::kSkipCEntryFrame);
 }
 
 
diff --git a/test/cctest/types-fuzz.h b/test/cctest/types-fuzz.h
new file mode 100644
index 0000000..4eac64c
--- /dev/null
+++ b/test/cctest/types-fuzz.h
@@ -0,0 +1,311 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_TEST_CCTEST_TYPES_H_
+#define V8_TEST_CCTEST_TYPES_H_
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+
+
+template<class Type, class TypeHandle, class Region>
+class Types {
+ public:
+  Types(Region* region, Isolate* isolate)
+      : region_(region), rng_(isolate->random_number_generator()) {
+    #define DECLARE_TYPE(name, value) \
+      name = Type::name(region);      \
+      types.push_back(name);
+    PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
+    #undef DECLARE_TYPE
+
+    object_map = isolate->factory()->NewMap(
+        JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    array_map = isolate->factory()->NewMap(
+        JS_ARRAY_TYPE, JSArray::kSize);
+    number_map = isolate->factory()->NewMap(
+        HEAP_NUMBER_TYPE, HeapNumber::kSize);
+    uninitialized_map = isolate->factory()->uninitialized_map();
+    ObjectClass = Type::Class(object_map, region);
+    ArrayClass = Type::Class(array_map, region);
+    NumberClass = Type::Class(number_map, region);
+    UninitializedClass = Type::Class(uninitialized_map, region);
+
+    maps.push_back(object_map);
+    maps.push_back(array_map);
+    maps.push_back(uninitialized_map);
+    for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) {
+      types.push_back(Type::Class(*it, region));
+    }
+
+    smi = handle(Smi::FromInt(666), isolate);
+    signed32 = isolate->factory()->NewHeapNumber(0x40000000);
+    object1 = isolate->factory()->NewJSObjectFromMap(object_map);
+    object2 = isolate->factory()->NewJSObjectFromMap(object_map);
+    array = isolate->factory()->NewJSArray(20);
+    uninitialized = isolate->factory()->uninitialized_value();
+    SmiConstant = Type::Constant(smi, region);
+    Signed32Constant = Type::Constant(signed32, region);
+    ObjectConstant1 = Type::Constant(object1, region);
+    ObjectConstant2 = Type::Constant(object2, region);
+    ArrayConstant = Type::Constant(array, region);
+    UninitializedConstant = Type::Constant(uninitialized, region);
+
+    values.push_back(smi);
+    values.push_back(signed32);
+    values.push_back(object1);
+    values.push_back(object2);
+    values.push_back(array);
+    values.push_back(uninitialized);
+    for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) {
+      types.push_back(Type::Constant(*it, region));
+    }
+
+    integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY));
+    integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY));
+    integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10)));
+    integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10)));
+    for (int i = 0; i < 10; ++i) {
+      double x = rng_->NextInt();
+      integers.push_back(isolate->factory()->NewNumber(x));
+      x *= rng_->NextInt();
+      if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
+    }
+
+    Integer = Type::Range(isolate->factory()->NewNumber(-V8_INFINITY),
+                          isolate->factory()->NewNumber(+V8_INFINITY), region);
+
+    NumberArray = Type::Array(Number, region);
+    StringArray = Type::Array(String, region);
+    AnyArray = Type::Array(Any, region);
+
+    SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region);
+    NumberFunction1 = Type::Function(Number, Number, region);
+    NumberFunction2 = Type::Function(Number, Number, Number, region);
+    MethodFunction = Type::Function(String, Object, 0, region);
+
+    for (int i = 0; i < 30; ++i) {
+      types.push_back(Fuzz());
+    }
+  }
+
+  Handle<i::Map> object_map;
+  Handle<i::Map> array_map;
+  Handle<i::Map> number_map;
+  Handle<i::Map> uninitialized_map;
+
+  Handle<i::Smi> smi;
+  Handle<i::HeapNumber> signed32;
+  Handle<i::JSObject> object1;
+  Handle<i::JSObject> object2;
+  Handle<i::JSArray> array;
+  Handle<i::Oddball> uninitialized;
+
+  #define DECLARE_TYPE(name, value) TypeHandle name;
+  PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
+  #undef DECLARE_TYPE
+
+  TypeHandle ObjectClass;
+  TypeHandle ArrayClass;
+  TypeHandle NumberClass;
+  TypeHandle UninitializedClass;
+
+  TypeHandle SmiConstant;
+  TypeHandle Signed32Constant;
+  TypeHandle ObjectConstant1;
+  TypeHandle ObjectConstant2;
+  TypeHandle ArrayConstant;
+  TypeHandle UninitializedConstant;
+
+  TypeHandle Integer;
+
+  TypeHandle NumberArray;
+  TypeHandle StringArray;
+  TypeHandle AnyArray;
+
+  TypeHandle SignedFunction1;
+  TypeHandle NumberFunction1;
+  TypeHandle NumberFunction2;
+  TypeHandle MethodFunction;
+
+  typedef std::vector<TypeHandle> TypeVector;
+  typedef std::vector<Handle<i::Map> > MapVector;
+  typedef std::vector<Handle<i::Object> > ValueVector;
+
+  TypeVector types;
+  MapVector maps;
+  ValueVector values;
+  ValueVector integers;  // "Integer" values used for range limits.
+
+  TypeHandle Of(Handle<i::Object> value) {
+    return Type::Of(value, region_);
+  }
+
+  TypeHandle NowOf(Handle<i::Object> value) {
+    return Type::NowOf(value, region_);
+  }
+
+  TypeHandle Class(Handle<i::Map> map) {
+    return Type::Class(map, region_);
+  }
+
+  TypeHandle Constant(Handle<i::Object> value) {
+    return Type::Constant(value, region_);
+  }
+
+  TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) {
+    return Type::Range(min, max, region_);
+  }
+
+  TypeHandle Context(TypeHandle outer) {
+    return Type::Context(outer, region_);
+  }
+
+  TypeHandle Array1(TypeHandle element) {
+    return Type::Array(element, region_);
+  }
+
+  TypeHandle Function0(TypeHandle result, TypeHandle receiver) {
+    return Type::Function(result, receiver, 0, region_);
+  }
+
+  TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) {
+    TypeHandle type = Type::Function(result, receiver, 1, region_);
+    type->AsFunction()->InitParameter(0, arg);
+    return type;
+  }
+
+  TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) {
+    return Type::Function(result, arg1, arg2, region_);
+  }
+
+  TypeHandle Union(TypeHandle t1, TypeHandle t2) {
+    return Type::Union(t1, t2, region_);
+  }
+  TypeHandle Intersect(TypeHandle t1, TypeHandle t2) {
+    return Type::Intersect(t1, t2, region_);
+  }
+
+  template<class Type2, class TypeHandle2>
+  TypeHandle Convert(TypeHandle2 t) {
+    return Type::template Convert<Type2>(t, region_);
+  }
+
+  TypeHandle Random() {
+    return types[rng_->NextInt(static_cast<int>(types.size()))];
+  }
+
+  TypeHandle Fuzz(int depth = 4) {
+    switch (rng_->NextInt(depth == 0 ? 3 : 20)) {
+      case 0: {  // bitset
+        #define COUNT_BITSET_TYPES(type, value) + 1
+        int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES);
+        #undef COUNT_BITSET_TYPES
+        // Pick a bunch of named bitsets and return their intersection.
+        TypeHandle result = Type::Any(region_);
+        for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) {
+          int j = rng_->NextInt(n);
+          #define PICK_BITSET_TYPE(type, value) \
+            if (j-- == 0) { \
+              TypeHandle tmp = Type::Intersect( \
+                  result, Type::type(region_), region_); \
+              if (tmp->Is(Type::None()) && i != 0) { \
+                break; \
+              } else { \
+                result = tmp; \
+                continue; \
+              } \
+            }
+          PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE)
+          #undef PICK_BITSET_TYPE
+        }
+        return result;
+      }
+      case 1: {  // class
+        int i = rng_->NextInt(static_cast<int>(maps.size()));
+        return Type::Class(maps[i], region_);
+      }
+      case 2: {  // constant
+        int i = rng_->NextInt(static_cast<int>(values.size()));
+        return Type::Constant(values[i], region_);
+      }
+      case 3: {  // range
+        int i = rng_->NextInt(static_cast<int>(integers.size()));
+        int j = rng_->NextInt(static_cast<int>(integers.size()));
+        i::Handle<i::Object> min = integers[i];
+        i::Handle<i::Object> max = integers[j];
+        if (min->Number() > max->Number()) std::swap(min, max);
+        return Type::Range(min, max, region_);
+      }
+      case 4: {  // context
+        int depth = rng_->NextInt(3);
+        TypeHandle type = Type::Internal(region_);
+        for (int i = 0; i < depth; ++i) type = Type::Context(type, region_);
+        return type;
+      }
+      case 5: {  // array
+        TypeHandle element = Fuzz(depth / 2);
+        return Type::Array(element, region_);
+      }
+      case 6:
+      case 7: {  // function
+        TypeHandle result = Fuzz(depth / 2);
+        TypeHandle receiver = Fuzz(depth / 2);
+        int arity = rng_->NextInt(3);
+        TypeHandle type = Type::Function(result, receiver, arity, region_);
+        for (int i = 0; i < type->AsFunction()->Arity(); ++i) {
+          TypeHandle parameter = Fuzz(depth / 2);
+          type->AsFunction()->InitParameter(i, parameter);
+        }
+        return type;
+      }
+      default: {  // union
+        int n = rng_->NextInt(10);
+        TypeHandle type = None;
+        for (int i = 0; i < n; ++i) {
+          TypeHandle operand = Fuzz(depth - 1);
+          type = Type::Union(type, operand, region_);
+        }
+        return type;
+      }
+    }
+    UNREACHABLE();
+  }
+
+  Region* region() { return region_; }
+
+ private:
+  Region* region_;
+  v8::base::RandomNumberGenerator* rng_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif
diff --git a/test/compiler-unittests/compiler-unittests.status b/test/compiler-unittests/compiler-unittests.status
deleted file mode 100644
index d439913..0000000
--- a/test/compiler-unittests/compiler-unittests.status
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-[
-]
diff --git a/test/fuzz-natives/base.js b/test/fuzz-natives/base.js
deleted file mode 100644
index d1f721d..0000000
--- a/test/fuzz-natives/base.js
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Flags: --allow-natives-syntax
-
-// TODO(jkummerow): There are many ways to improve these tests, e.g.:
-// - more variance in randomized inputs
-// - better time complexity management
-// - better code readability and documentation of intentions.
-
-var RUN_WITH_ALL_ARGUMENT_ENTRIES = false;
-var kOnManyArgumentsRemove = 5;
-
-function makeArguments() {
-  var result = [ ];
-  result.push(17);
-  result.push(-31);
-  result.push(new Array(100));
-  var a = %NormalizeElements([]);
-  a.length = 100003;
-  result.push(a);
-  result.push(Number.MIN_VALUE);
-  result.push("whoops");
-  result.push("x");
-  result.push({"x": 1, "y": 2});
-  var slowCaseObj = {"a": 3, "b": 4, "c": 5};
-  delete slowCaseObj.c;
-  result.push(slowCaseObj);
-  result.push(function () { return 8; });
-  return result;
-}
-
-var kArgObjects = makeArguments().length;
-
-function makeFunction(name, argc) {
-  var args = [];
-  for (var i = 0; i < argc; i++)
-    args.push("x" + i);
-  var argsStr = args.join(", ");
-  return new Function(argsStr,
-                      "return %" + name + "(" + argsStr + ");");
-}
-
-function testArgumentCount(name, argc) {
-  for (var i = 0; i < 10; i++) {
-    var func = null;
-    try {
-      func = makeFunction(name, i);
-    } catch (e) {
-      if (e != "SyntaxError: Illegal access") throw e;
-    }
-    if (func === null && i == argc) {
-      throw "unexpected exception";
-    }
-    var args = [ ];
-    for (var j = 0; j < i; j++)
-      args.push(0);
-    try {
-      func.apply(void 0, args);
-    } catch (e) {
-      // we don't care what happens as long as we don't crash
-    }
-  }
-}
-
-function testArgumentTypes(name, argc) {
-  var type = 0;
-  var hasMore = true;
-  var func = makeFunction(name, argc);
-  while (hasMore) {
-    var argPool = makeArguments();
-    // When we have 5 or more arguments we lower the amount of tests cases
-    // by randomly removing kOnManyArgumentsRemove entries
-    var numArguments = RUN_WITH_ALL_ARGUMENT_ENTRIES ?
-      kArgObjects : kArgObjects - kOnManyArgumentsRemove;
-    if (kArgObjects >= 5 && !RUN_WITH_ALL_ARGUMENT_ENTRIES) {
-      for (var i = 0; i < kOnManyArgumentsRemove; i++) {
-        var rand = Math.floor(Math.random() * (kArgObjects - i));
-        argPool.splice(rand, 1);
-      }
-    }
-    var current = type;
-    hasMore = false;
-    var argList = [ ];
-    for (var i = 0; i < argc; i++) {
-      var index = current % numArguments;
-      current = (current / numArguments) << 0;
-      if (index != (numArguments - 1))
-        hasMore = true;
-      argList.push(argPool[index]);
-    }
-    try {
-      func.apply(void 0, argList);
-    } catch (e) {
-      // we don't care what happens as long as we don't crash
-    }
-    type++;
-  }
-}
-
-testArgumentCount(NAME, ARGC);
-testArgumentTypes(NAME, ARGC);
diff --git a/test/fuzz-natives/fuzz-natives.status b/test/fuzz-natives/fuzz-natives.status
deleted file mode 100644
index c81188a..0000000
--- a/test/fuzz-natives/fuzz-natives.status
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-[
-[ALWAYS, {
-  # These are designed to crash:
-  "Abort": [SKIP],
-  "AbortJS": [SKIP],
-  "SystemBreak": [SKIP],
-  "_DebugBreakInOptimizedCode": [SKIP],
-
-  # varargs.
-  "Call": [SKIP],
-  "_CallFunction": [SKIP],
-
-  # Implemented in the parser, not callable.
-  "IS_VAR": [SKIP],
-
-  # Compile-time ASSERTs.
-  "_DateField": [SKIP],
-  "_GetFromCache": [SKIP],
-
-  # Riddled with ASSERTs.
-  "CompileForOnStackReplacement": [SKIP],
-
-  # Too slow for fuzzing.
-  "SetAllocationTimeout": [SKIP],
-
-  # TODO(jkummerow): Fix these and un-blacklist them!
-  "CreateDateTimeFormat": [SKIP],
-  "CreateNumberFormat": [SKIP],
-
-  # TODO(danno): Fix these internal function that are only callable form stubs
-  # and un-blacklist them!
-  "CompileLazy": [SKIP],
-  "NotifyDeoptimized": [SKIP],
-  "NotifyStubFailure": [SKIP],
-  "NewSloppyArguments": [SKIP],
-  "NewStrictArguments": [SKIP],
-  "ArrayConstructor": [SKIP],
-  "InternalArrayConstructor": [SKIP],
-  "FinalizeInstanceSize": [SKIP],
-  "PromoteScheduledException": [SKIP],
-  "NewFunctionContext": [SKIP],
-  "PushWithContext": [SKIP],
-  "PushCatchContext": [SKIP],
-  "PushModuleContext": [SKIP],
-  "LoadLookupSlot": [SKIP],
-  "LoadLookupSlotNoReferenceError": [SKIP],
-  "ResolvePossiblyDirectEval": [SKIP],
-  "ForInInit": [SKIP],
-  "ForInNext": [SKIP],
-
-  # TODO(jkummerow): Figure out what to do about inlined functions.
-  "_GeneratorNext": [SKIP],
-  "_GeneratorThrow": [SKIP],
-  "_GetCachedArrayIndex": [SKIP],
-  "_HasCachedArrayIndex": [SKIP],
-  "_IsStringWrapperSafeForDefaultValueOf": [SKIP],
-  "_OneByteSeqStringSetChar": [SKIP],
-  "_RegExpConstructResult": [SKIP],
-  "_TwoByteSeqStringSetChar": [SKIP],
-
-  # These are slow.
-  "DebugEvaluate": [PASS, SLOW],
-  "DebugReferencedBy": [PASS, SLOW],
-  "SetAccessorProperty": [PASS, SLOW],
-  "SetScopeVariableValue": [PASS, SLOW],
-}]  # ALWAYS
-]
diff --git a/test/fuzz-natives/testcfg.py b/test/fuzz-natives/testcfg.py
deleted file mode 100644
index 5e00b40..0000000
--- a/test/fuzz-natives/testcfg.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-
-from testrunner.local import commands
-from testrunner.local import testsuite
-from testrunner.local import utils
-from testrunner.objects import testcase
-
-class FuzzNativesTestSuite(testsuite.TestSuite):
-
-  def __init__(self, name, root):
-    super(FuzzNativesTestSuite, self).__init__(name, root)
-
-  def ListTests(self, context):
-    shell = os.path.abspath(os.path.join(context.shell_dir, self.shell()))
-    if utils.IsWindows():
-      shell += ".exe"
-    output = commands.Execute(
-        context.command_prefix +
-        [shell, "--allow-natives-syntax", "-e",
-         "try { var natives = %ListNatives();"
-         "  for (var n in natives) { print(natives[n]); }"
-         "} catch(e) {}"] +
-        context.extra_flags)
-    if output.exit_code != 0:
-      print output.stdout
-      print output.stderr
-      assert False, "Failed to get natives list."
-    tests = []
-    for line in output.stdout.strip().split():
-      try:
-        (name, argc) = line.split(",")
-        flags = ["--allow-natives-syntax",
-                 "-e", "var NAME = '%s', ARGC = %s;" % (name, argc)]
-        test = testcase.TestCase(self, name, flags)
-        tests.append(test)
-      except:
-        # Work-around: If parsing didn't work, it might have been due to output
-        # caused by other d8 flags.
-        pass
-    return tests
-
-  def GetFlagsForTestCase(self, testcase, context):
-    name = testcase.path
-    basefile = os.path.join(self.root, "base.js")
-    return testcase.flags + [basefile] + context.mode_flags
-
-def GetSuite(name, root):
-  return FuzzNativesTestSuite(name, root)
diff --git a/test/heap-unittests/heap-unittests.status b/test/heap-unittests/heap-unittests.status
deleted file mode 100644
index d439913..0000000
--- a/test/heap-unittests/heap-unittests.status
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-[
-]
diff --git a/test/intl/general/smp-identifier.js b/test/intl/general/smp-identifier.js
new file mode 100644
index 0000000..8a8d2e6
--- /dev/null
+++ b/test/intl/general/smp-identifier.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function toSurrogatePair(c) {
+  return String.fromCharCode(((c - 0x10000) >>> 10) & 0x3FF | 0xD800) +
+         String.fromCharCode(c & 0x3FF | 0xDC00);
+}
+
+function testIdStart(c, is_id_start) {
+  var source = "var " + toSurrogatePair(c);
+  print(source);
+  if (is_id_start) {
+    assertDoesNotThrow(source);
+  } else {
+    assertThrows(source);
+  }
+}
+
+function testIdPart(c, is_id_start) {
+  var source = "var v" + toSurrogatePair(c);
+  print(source);
+  if (is_id_start) {
+    assertDoesNotThrow(source);
+  } else {
+    assertThrows(source);
+  }
+}
+
+[0x10403, 0x1043C, 0x16F9C, 0x10048, 0x1014D].forEach(function(c) {
+  testIdStart(c, true);
+  testIdPart(c, true);
+});
+
+[0x101FD, 0x11002, 0x104A9].forEach(function(c) {
+  testIdStart(c, false);
+  testIdPart(c, true);
+});
+
+[0x10111, 0x1F4A9].forEach(function(c) {
+  testIdStart(c, false);
+  testIdPart(c, false);
+});
diff --git a/test/js-perf-test/Classes/default-constructor.js b/test/js-perf-test/Classes/default-constructor.js
new file mode 100644
index 0000000..49dcaa6
--- /dev/null
+++ b/test/js-perf-test/Classes/default-constructor.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+'use strict';
+
+var DefaultConstructorBenchmark = new BenchmarkSuite('DefaultConstructor',
+    [100], [
+      new Benchmark('NoSuperClass', false, false, 0, NoSuperClass),
+      new Benchmark('WithSuperClass', false, false, 0, WithSuperClass),
+      new Benchmark('WithSuperClassArguments', false, false, 0,
+                    WithSuperClassArguments),
+    ]);
+
+
+class BaseClass {}
+
+
+class DerivedClass extends BaseClass {}
+
+
+function NoSuperClass() {
+  return new BaseClass();
+}
+
+
+function WithSuperClass() {
+  return new DerivedClass();
+}
+
+
+function WithSuperClassArguments() {
+  return new DerivedClass(0, 1, 2, 3, 4);
+}
diff --git a/test/perf-test/Collections/run.js b/test/js-perf-test/Classes/run.js
similarity index 78%
copy from test/perf-test/Collections/run.js
copy to test/js-perf-test/Classes/run.js
index cfd1aef..5d48b32 100644
--- a/test/perf-test/Collections/run.js
+++ b/test/js-perf-test/Classes/run.js
@@ -3,17 +3,15 @@
 // found in the LICENSE file.
 
 
-load('base.js');
-load('map.js');
-load('set.js');
-load('weakmap.js');
-load('weakset.js');
+load('../base.js');
+load('super.js');
+load('default-constructor.js');
 
 
 var success = true;
 
 function PrintResult(name, result) {
-  print(name + '-Collections(Score): ' + result);
+  print(name + '-Classes(Score): ' + result);
 }
 
 
diff --git a/test/js-perf-test/Classes/super.js b/test/js-perf-test/Classes/super.js
new file mode 100644
index 0000000..a9ec766
--- /dev/null
+++ b/test/js-perf-test/Classes/super.js
@@ -0,0 +1,59 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+'use strict';
+
+var SuperBenchmark = new BenchmarkSuite('Super', [100], [
+     new Benchmark('SuperMethodCall', false, false, 0, SuperMethodCall),
+     new Benchmark('SuperGetterCall', false, false, 0, SuperGetterCall),
+     new Benchmark('SuperSetterCall', false, false, 0, SuperSetterCall),
+]);
+
+
+function Base() { }
+Base.prototype = {
+  constructor: Base,
+  get x() {
+    return this._x++;
+  },
+  set x(v) {
+    this._x += v;
+    return this._x;
+  }
+}
+
+Base.prototype.f = function() {
+  return this._x++;
+}.toMethod(Base.prototype);
+
+function Derived() {
+  this._x = 1;
+}
+Derived.prototype = Object.create(Base.prototype);
+Object.setPrototypeOf(Derived, Base);
+
+Derived.prototype.SuperCall = function() {
+  return super.f();
+}.toMethod(Derived.prototype);
+
+Derived.prototype.GetterCall = function() {
+  return super.x;
+}.toMethod(Derived.prototype);
+
+Derived.prototype.SetterCall = function() {
+  return super.x = 5;
+}.toMethod(Derived.prototype);
+
+var derived = new Derived();
+
+function SuperMethodCall() {
+  return derived.SuperCall();
+}
+
+function SuperGetterCall() {
+  return derived.GetterCall();
+}
+
+function SuperSetterCall() {
+  return derived.SetterCall();
+}
diff --git a/test/js-perf-test/Collections/common.js b/test/js-perf-test/Collections/common.js
new file mode 100644
index 0000000..3ea3933
--- /dev/null
+++ b/test/js-perf-test/Collections/common.js
@@ -0,0 +1,31 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var N = 10;
+var keys;
+
+
+function SetupSmiKeys() {
+  keys = new Array(N * 2);
+  for (var i = 0; i < N * 2; i++) {
+    keys[i] = i;
+  }
+}
+
+
+function SetupStringKeys() {
+  keys = new Array(N * 2);
+  for (var i = 0; i < N * 2; i++) {
+    keys[i] = 's' + i;
+  }
+}
+
+
+function SetupObjectKeys() {
+  keys = new Array(N * 2);
+  for (var i = 0; i < N * 2; i++) {
+    keys[i] = {};
+  }
+}
diff --git a/test/js-perf-test/Collections/map.js b/test/js-perf-test/Collections/map.js
new file mode 100644
index 0000000..4f55798
--- /dev/null
+++ b/test/js-perf-test/Collections/map.js
@@ -0,0 +1,217 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var MapSmiBenchmark = new BenchmarkSuite('Map-Smi', [1000], [
+  new Benchmark('Set', false, false, 0, MapSetSmi, MapSetupSmiBase, MapTearDown),
+  new Benchmark('Has', false, false, 0, MapHasSmi, MapSetupSmi, MapTearDown),
+  new Benchmark('Get', false, false, 0, MapGetSmi, MapSetupSmi, MapTearDown),
+  new Benchmark('Delete', false, false, 0, MapDeleteSmi, MapSetupSmi, MapTearDown),
+]);
+
+
+var MapStringBenchmark = new BenchmarkSuite('Map-String', [1000], [
+  new Benchmark('Set', false, false, 0, MapSetString, MapSetupStringBase, MapTearDown),
+  new Benchmark('Has', false, false, 0, MapHasString, MapSetupString, MapTearDown),
+  new Benchmark('Get', false, false, 0, MapGetString, MapSetupString, MapTearDown),
+  new Benchmark('Delete', false, false, 0, MapDeleteString, MapSetupString, MapTearDown),
+]);
+
+
+var MapObjectBenchmark = new BenchmarkSuite('Map-Object', [1000], [
+  new Benchmark('Set', false, false, 0, MapSetObject, MapSetupObjectBase, MapTearDown),
+  new Benchmark('Has', false, false, 0, MapHasObject, MapSetupObject, MapTearDown),
+  new Benchmark('Get', false, false, 0, MapGetObject, MapSetupObject, MapTearDown),
+  new Benchmark('Delete', false, false, 0, MapDeleteObject, MapSetupObject, MapTearDown),
+]);
+
+
+var MapIterationBenchmark = new BenchmarkSuite('Map-Iteration', [1000], [
+  new Benchmark('ForEach', false, false, 0, MapForEach, MapSetupSmi, MapTearDown),
+]);
+
+
+var map;
+
+
+function MapSetupSmiBase() {
+  SetupSmiKeys();
+  map = new Map;
+}
+
+
+function MapSetupSmi() {
+  MapSetupSmiBase();
+  MapSetSmi();
+}
+
+
+function MapSetupStringBase() {
+  SetupStringKeys();
+  map = new Map;
+}
+
+
+function MapSetupString() {
+  MapSetupStringBase();
+  MapSetString();
+}
+
+
+function MapSetupObjectBase() {
+  SetupObjectKeys();
+  map = new Map;
+}
+
+
+function MapSetupObject() {
+  MapSetupObjectBase();
+  MapSetObject();
+}
+
+
+function MapTearDown() {
+  map = null;
+}
+
+
+function MapSetSmi() {
+  for (var i = 0; i < N; i++) {
+    map.set(keys[i], i);
+  }
+}
+
+
+function MapHasSmi() {
+  for (var i = 0; i < N; i++) {
+    if (!map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapGetSmi() {
+  for (var i = 0; i < N; i++) {
+    if (map.get(keys[i]) !== i) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.get(keys[i]) !== undefined) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapDeleteSmi() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    map.delete(keys[i]);
+  }
+}
+
+
+function MapSetString() {
+  for (var i = 0; i < N; i++) {
+    map.set(keys[i], i);
+  }
+}
+
+
+function MapHasString() {
+  for (var i = 0; i < N; i++) {
+    if (!map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapGetString() {
+  for (var i = 0; i < N; i++) {
+    if (map.get(keys[i]) !== i) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.get(keys[i]) !== undefined) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapDeleteString() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    map.delete(keys[i]);
+  }
+}
+
+
+function MapSetObject() {
+  for (var i = 0; i < N; i++) {
+    map.set(keys[i], i);
+  }
+}
+
+
+function MapHasObject() {
+  for (var i = 0; i < N; i++) {
+    if (!map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapGetObject() {
+  for (var i = 0; i < N; i++) {
+    if (map.get(keys[i]) !== i) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (map.get(keys[i]) !== undefined) {
+      throw new Error();
+    }
+  }
+}
+
+
+function MapDeleteObject() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    map.delete(keys[i]);
+  }
+}
+
+
+function MapForEach() {
+  map.forEach(function(v, k) {
+    if (v !== k) {
+      throw new Error();
+    }
+  });
+}
diff --git a/test/perf-test/Collections/run.js b/test/js-perf-test/Collections/run.js
similarity index 94%
rename from test/perf-test/Collections/run.js
rename to test/js-perf-test/Collections/run.js
index cfd1aef..50f1ee1 100644
--- a/test/perf-test/Collections/run.js
+++ b/test/js-perf-test/Collections/run.js
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 
 
-load('base.js');
+load('../base.js');
+load('common.js');
 load('map.js');
 load('set.js');
 load('weakmap.js');
diff --git a/test/js-perf-test/Collections/set.js b/test/js-perf-test/Collections/set.js
new file mode 100644
index 0000000..3be27f5
--- /dev/null
+++ b/test/js-perf-test/Collections/set.js
@@ -0,0 +1,172 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+var SetSmiBenchmark = new BenchmarkSuite('Set-Smi', [1000], [
+  new Benchmark('Set', false, false, 0, SetAddSmi, SetSetupSmiBase, SetTearDown),
+  new Benchmark('Has', false, false, 0, SetHasSmi, SetSetupSmi, SetTearDown),
+  new Benchmark('Delete', false, false, 0, SetDeleteSmi, SetSetupSmi, SetTearDown),
+]);
+
+
+var SetStringBenchmark = new BenchmarkSuite('Set-String', [1000], [
+  new Benchmark('Set', false, false, 0, SetAddString, SetSetupStringBase, SetTearDown),
+  new Benchmark('Has', false, false, 0, SetHasString, SetSetupString, SetTearDown),
+  new Benchmark('Delete', false, false, 0, SetDeleteString, SetSetupString, SetTearDown),
+]);
+
+
+var SetObjectBenchmark = new BenchmarkSuite('Set-Object', [1000], [
+  new Benchmark('Set', false, false, 0, SetAddObject, SetSetupObjectBase, SetTearDown),
+  new Benchmark('Has', false, false, 0, SetHasObject, SetSetupObject, SetTearDown),
+  new Benchmark('Delete', false, false, 0, SetDeleteObject, SetSetupObject, SetTearDown),
+]);
+
+
+var SetIterationBenchmark = new BenchmarkSuite('Set-Iteration', [1000], [
+  new Benchmark('ForEach', false, false, 0, SetForEach, SetSetupSmi, SetTearDown),
+]);
+
+
+var set;
+
+
+function SetSetupSmiBase() {
+  SetupSmiKeys();
+  set = new Set;
+}
+
+
+function SetSetupSmi() {
+  SetSetupSmiBase();
+  SetAddSmi();
+}
+
+
+function SetSetupStringBase() {
+  SetupStringKeys();
+  set = new Set;
+}
+
+
+function SetSetupString() {
+  SetSetupStringBase();
+  SetAddString();
+}
+
+
+function SetSetupObjectBase() {
+  SetupObjectKeys();
+  set = new Set;
+}
+
+
+function SetSetupObject() {
+  SetSetupObjectBase();
+  SetAddObject();
+}
+
+
+function SetTearDown() {
+  set = null;
+}
+
+
+function SetAddSmi() {
+  for (var i = 0; i < N; i++) {
+    set.add(keys[i], i);
+  }
+}
+
+
+function SetHasSmi() {
+  for (var i = 0; i < N; i++) {
+    if (!set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function SetDeleteSmi() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    set.delete(keys[i]);
+  }
+}
+
+
+function SetAddString() {
+  for (var i = 0; i < N; i++) {
+    set.add(keys[i], i);
+  }
+}
+
+
+function SetHasString() {
+  for (var i = 0; i < N; i++) {
+    if (!set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function SetDeleteString() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    set.delete(keys[i]);
+  }
+}
+
+
+function SetAddObject() {
+  for (var i = 0; i < N; i++) {
+    set.add(keys[i], i);
+  }
+}
+
+
+function SetHasObject() {
+  for (var i = 0; i < N; i++) {
+    if (!set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+  for (var i = N; i < 2 * N; i++) {
+    if (set.has(keys[i])) {
+      throw new Error();
+    }
+  }
+}
+
+
+function SetDeleteObject() {
+  // This is run more than once per setup so we will end up deleting items
+  // more than once. Therefore, we do not the return value of delete.
+  for (var i = 0; i < N; i++) {
+    set.delete(keys[i]);
+  }
+}
+
+
+function SetForEach() {
+  set.forEach(function(v, k) {
+    if (v !== k) {
+      throw new Error();
+    }
+  });
+}
diff --git a/test/perf-test/Collections/weakmap.js b/test/js-perf-test/Collections/weakmap.js
similarity index 88%
rename from test/perf-test/Collections/weakmap.js
rename to test/js-perf-test/Collections/weakmap.js
index 8736dfd..9aa265f 100644
--- a/test/perf-test/Collections/weakmap.js
+++ b/test/js-perf-test/Collections/weakmap.js
@@ -4,7 +4,8 @@
 
 
 var MapBenchmark = new BenchmarkSuite('WeakMap', [1000], [
-  new Benchmark('Set', false, false, 0, WeakMapSet),
+  new Benchmark('Set', false, false, 0, WeakMapSet, WeakMapSetupBase,
+      WeakMapTearDown),
   new Benchmark('Has', false, false, 0, WeakMapHas, WeakMapSetup,
       WeakMapTearDown),
   new Benchmark('Get', false, false, 0, WeakMapGet, WeakMapSetup,
@@ -15,20 +16,17 @@
 
 
 var wm;
-var N = 10;
-var keys = [];
 
 
-for (var i = 0; i < N * 2; i++) {
-  keys[i] = {};
+function WeakMapSetupBase() {
+  SetupObjectKeys();
+  wm = new WeakMap;
 }
 
 
 function WeakMapSetup() {
-  wm = new WeakMap;
-  for (var i = 0; i < N; i++) {
-    wm.set(keys[i], i);
-  }
+  WeakMapSetupBase();
+  WeakMapSet();
 }
 
 
@@ -38,8 +36,9 @@
 
 
 function WeakMapSet() {
-  WeakMapSetup();
-  WeakMapTearDown();
+  for (var i = 0; i < N; i++) {
+    wm.set(keys[i], i);
+  }
 }
 
 
diff --git a/test/perf-test/Collections/weakset.js b/test/js-perf-test/Collections/weakset.js
similarity index 85%
rename from test/perf-test/Collections/weakset.js
rename to test/js-perf-test/Collections/weakset.js
index a7d0f3d..2936477 100644
--- a/test/perf-test/Collections/weakset.js
+++ b/test/js-perf-test/Collections/weakset.js
@@ -4,7 +4,8 @@
 
 
 var SetBenchmark = new BenchmarkSuite('WeakSet', [1000], [
-  new Benchmark('Add', false, false, 0, WeakSetAdd),
+  new Benchmark('Add', false, false, 0, WeakSetAdd, WeakSetSetupBase,
+      WeakSetTearDown),
   new Benchmark('Has', false, false, 0, WeakSetHas, WeakSetSetup,
       WeakSetTearDown),
   new Benchmark('Delete', false, false, 0, WeakSetDelete, WeakSetSetup,
@@ -13,20 +14,17 @@
 
 
 var ws;
-var N = 10;
-var keys = [];
 
 
-for (var i = 0; i < N * 2; i++) {
-  keys[i] = {};
+function WeakSetSetupBase() {
+  SetupObjectKeys();
+  ws = new WeakSet;
 }
 
 
 function WeakSetSetup() {
-  ws = new WeakSet;
-  for (var i = 0; i < N; i++) {
-    ws.add(keys[i]);
-  }
+  WeakSetSetupBase();
+  WeakSetAdd();
 }
 
 
@@ -36,8 +34,9 @@
 
 
 function WeakSetAdd() {
-  WeakSetSetup();
-  WeakSetTearDown();
+  for (var i = 0; i < N; i++) {
+    ws.add(keys[i]);
+  }
 }
 
 
diff --git a/test/js-perf-test/Iterators/forof.js b/test/js-perf-test/Iterators/forof.js
new file mode 100644
index 0000000..1877ebe
--- /dev/null
+++ b/test/js-perf-test/Iterators/forof.js
@@ -0,0 +1,94 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+new BenchmarkSuite('ForOf', [1000], [
+  new Benchmark('ArrayValues', false, false, 0,
+                ForOf, ForOfArraySetup, ForOfTearDown),
+  new Benchmark('ArrayKeys', false, false, 0,
+                ForOf, ForOfArrayKeysSetup, ForOfTearDown),
+  new Benchmark('ArrayEntries', false, false, 0,
+                ForOf, ForOfArrayEntriesSetup, ForOfTearDown),
+  new Benchmark('Uint8Array', false, false, 0,
+                ForOf, ForOfUint8ArraySetup, ForOfTearDown),
+  new Benchmark('Float64Array', false, false, 0,
+                ForOf, ForOfFloat64ArraySetup, ForOfTearDown),
+  new Benchmark('String', false, false, 0,
+                ForOf, ForOfStringSetup, ForOfTearDown),
+]);
+
+
+var iterable;
+var N = 100;
+var expected, result;
+
+
+function ForOfArraySetupHelper(constructor) {
+  iterable = new constructor(N);
+  for (var i = 0; i < N; i++) iterable[i] = i;
+  expected = N - 1;
+}
+
+
+function ForOfArraySetup() {
+  ForOfArraySetupHelper(Array);
+  // Default iterator is values().
+}
+
+
+function ForOfArrayKeysSetup() {
+  ForOfArraySetupHelper(Array);
+  iterable = iterable.keys();
+}
+
+
+function ForOfArrayEntriesSetup() {
+  ForOfArraySetupHelper(Array);
+  iterable = iterable.entries();
+  expected = [N-1, N-1];
+}
+
+
+function ForOfUint8ArraySetup() {
+  ForOfArraySetupHelper(Uint8Array);
+}
+
+
+function ForOfFloat64ArraySetup() {
+  ForOfArraySetupHelper(Float64Array);
+}
+
+
+function ForOfStringSetup() {
+  iterable = "abcdefhijklmnopqrstuvwxyzABCDEFHIJKLMNOPQRSTUVWXYZ0123456789";
+  expected = "9";
+}
+
+
+function Equals(expected, actual) {
+  if (expected === actual) return true;
+  if (typeof expected !== typeof actual) return false;
+  if (typeof expected !== 'object') return false;
+  for (var k of Object.keys(expected)) {
+    if (!(k in actual)) return false;
+    if (!Equals(expected[k], actual[k])) return false;
+  }
+  for (var k of Object.keys(actual)) {
+    if (!(k in expected)) return false;
+  }
+  return true;
+}
+
+function ForOfTearDown() {
+  iterable = null;
+  if (!Equals(expected, result)) {
+    throw new Error("Bad result: " + result);
+  }
+}
+
+
+function ForOf() {
+  for (var x of iterable) {
+    result = x;
+  }
+}
diff --git a/test/perf-test/Collections/run.js b/test/js-perf-test/Iterators/run.js
similarity index 78%
copy from test/perf-test/Collections/run.js
copy to test/js-perf-test/Iterators/run.js
index cfd1aef..ff4897f 100644
--- a/test/perf-test/Collections/run.js
+++ b/test/js-perf-test/Iterators/run.js
@@ -3,17 +3,14 @@
 // found in the LICENSE file.
 
 
-load('base.js');
-load('map.js');
-load('set.js');
-load('weakmap.js');
-load('weakset.js');
+load('../base.js');
+load('forof.js');
 
 
 var success = true;
 
 function PrintResult(name, result) {
-  print(name + '-Collections(Score): ' + result);
+  print(name + '-Iterators(Score): ' + result);
 }
 
 
diff --git a/test/js-perf-test/JSTests.json b/test/js-perf-test/JSTests.json
new file mode 100644
index 0000000..0a99ad4
--- /dev/null
+++ b/test/js-perf-test/JSTests.json
@@ -0,0 +1,86 @@
+{
+  "name": "JSTests",
+  "run_count": 5,
+  "run_count_android_arm": 3,
+  "run_count_android_arm64": 3,
+  "units": "score",
+  "total": true,
+  "resources": ["base.js"],
+  "tests": [
+    {
+      "name": "Classes",
+      "path": ["Classes"],
+      "main": "run.js",
+      "resources": ["super.js", "default-constructor.js"],
+      "flags": ["--harmony-classes"],
+      "results_regexp": "^%s\\-Classes\\(Score\\): (.+)$",
+      "tests": [
+        {"name": "Super"},
+        {"name": "DefaultConstructor"}
+      ]
+    },
+    {
+      "name": "Collections",
+      "path": ["Collections"],
+      "main": "run.js",
+      "resources": [
+        "common.js",
+        "map.js",
+        "run.js",
+        "set.js",
+        "weakmap.js",
+        "weakset.js"
+      ],
+      "results_regexp": "^%s\\-Collections\\(Score\\): (.+)$",
+      "tests": [
+        {"name": "Map-Smi"},
+        {"name": "Map-String"},
+        {"name": "Map-Object"},
+        {"name": "Map-Iteration"},
+        {"name": "Set-Smi"},
+        {"name": "Set-String"},
+        {"name": "Set-Object"},
+        {"name": "Set-Iteration"},
+        {"name": "WeakMap"},
+        {"name": "WeakSet"}
+      ]
+    },
+    {
+      "name": "Iterators",
+      "path": ["Iterators"],
+      "main": "run.js",
+      "resources": ["forof.js"],
+      "results_regexp": "^%s\\-Iterators\\(Score\\): (.+)$",
+      "tests": [
+        {"name": "ForOf"}
+      ]
+    },
+    {
+      "name": "Strings",
+      "path": ["Strings"],
+      "main": "run.js",
+      "resources": ["harmony-string.js"],
+      "flags": ["--harmony-strings"],
+      "results_regexp": "^%s\\-Strings\\(Score\\): (.+)$",
+      "tests": [
+        {"name": "StringFunctions"}
+      ]
+    },
+    {
+      "name": "Templates",
+      "path": ["Templates"],
+      "main": "run.js",
+      "resources": ["templates.js"],
+      "flags": ["--harmony-templates"],
+      "run_count": 5,
+      "units": "score",
+      "results_regexp": "^%s\\-Templates\\(Score\\): (.+)$",
+      "total": true,
+      "tests": [
+        {"name": "Untagged"},
+        {"name": "LargeUntagged"},
+        {"name": "Tagged"}
+      ]
+    }
+  ]
+}
diff --git a/test/js-perf-test/Strings/harmony-string.js b/test/js-perf-test/Strings/harmony-string.js
new file mode 100644
index 0000000..c2eac4e
--- /dev/null
+++ b/test/js-perf-test/Strings/harmony-string.js
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+new BenchmarkSuite('StringFunctions', [1000], [
+  new Benchmark('StringRepeat', false, false, 0,
+                Repeat, RepeatSetup, RepeatTearDown),
+  new Benchmark('StringStartsWith', false, false, 0,
+                StartsWith, WithSetup, WithTearDown),
+  new Benchmark('StringEndsWith', false, false, 0,
+                EndsWith, WithSetup, WithTearDown),
+  new Benchmark('StringIncludes', false, false, 0,
+                Includes, IncludesSetup, WithTearDown),
+  new Benchmark('StringFromCodePoint', false, false, 0,
+                FromCodePoint, FromCodePointSetup, FromCodePointTearDown),
+  new Benchmark('StringCodePointAt', false, false, 0,
+                CodePointAt, CodePointAtSetup, CodePointAtTearDown),
+]);
+
+
+var result;
+
+var stringRepeatSource = "abc";
+
+function RepeatSetup() {
+  result = undefined;
+}
+
+function Repeat() {
+  result = stringRepeatSource.repeat(500);
+}
+
+function RepeatTearDown() {
+  var expected = "";
+  for(var i = 0; i < 1000; i++) {
+    expected += stringRepeatSource;
+  }
+  return result === expected;
+}
+
+
+var str;
+var substr;
+
+function WithSetup() {
+  str = "abc".repeat(500);
+  substr = "abc".repeat(200);
+  result = undefined;
+}
+
+function WithTearDown() {
+  return !!result;
+}
+
+function StartsWith() {
+  result = str.startsWith(substr);
+}
+
+function EndsWith() {
+  result = str.endsWith(substr);
+}
+
+function IncludesSetup() {
+  str = "def".repeat(100) + "abc".repeat(100) + "qqq".repeat(100);
+  substr = "abc".repeat(100);
+}
+
+function Includes() {
+  result = str.includes(substr);
+}
+
+var MAX_CODE_POINT = 0xFFFFF;
+
+function FromCodePointSetup() {
+  result = new Array(MAX_CODE_POINT + 1);
+}
+
+function FromCodePoint() {
+  for (var i = 0; i <= MAX_CODE_POINT; i++) {
+    result[i] = String.fromCodePoint(i);
+  }
+}
+
+function FromCodePointTearDown() {
+  for (var i = 0; i <= MAX_CODE_POINT; i++) {
+    if (i !== result[i].codePointAt(0)) return false;
+  }
+  return true;
+}
+
+
+var allCodePoints;
+
+function CodePointAtSetup() {
+  allCodePoints = new Array(MAX_CODE_POINT + 1);
+  for (var i = 0; i <= MAX_CODE_POINT; i++) {
+    allCodePoints = String.fromCodePoint(i);
+  }
+  result = undefined;
+}
+
+function CodePointAt() {
+  result = 0;
+  for (var i = 0; i <= MAX_CODE_POINT; i++) {
+    result += allCodePoints.codePointAt(i);
+  }
+}
+
+function CodePointAtTearDown() {
+  return result === MAX_CODE_POINT * (MAX_CODE_POINT + 1) / 2;
+}
diff --git a/test/perf-test/Collections/run.js b/test/js-perf-test/Strings/run.js
similarity index 78%
copy from test/perf-test/Collections/run.js
copy to test/js-perf-test/Strings/run.js
index cfd1aef..79ca26e 100644
--- a/test/perf-test/Collections/run.js
+++ b/test/js-perf-test/Strings/run.js
@@ -3,17 +3,14 @@
 // found in the LICENSE file.
 
 
-load('base.js');
-load('map.js');
-load('set.js');
-load('weakmap.js');
-load('weakset.js');
+load('../base.js');
+load('harmony-string.js');
 
 
 var success = true;
 
 function PrintResult(name, result) {
-  print(name + '-Collections(Score): ' + result);
+  print(name + '-Strings(Score): ' + result);
 }
 
 
diff --git a/test/perf-test/Collections/run.js b/test/js-perf-test/Templates/run.js
similarity index 78%
copy from test/perf-test/Collections/run.js
copy to test/js-perf-test/Templates/run.js
index cfd1aef..73f1edd 100644
--- a/test/perf-test/Collections/run.js
+++ b/test/js-perf-test/Templates/run.js
@@ -3,17 +3,14 @@
 // found in the LICENSE file.
 
 
-load('base.js');
-load('map.js');
-load('set.js');
-load('weakmap.js');
-load('weakset.js');
+load('../base.js');
+load('templates.js');
 
 
 var success = true;
 
 function PrintResult(name, result) {
-  print(name + '-Collections(Score): ' + result);
+  print(name + '-Templates(Score): ' + result);
 }
 
 
diff --git a/test/js-perf-test/Templates/templates.js b/test/js-perf-test/Templates/templates.js
new file mode 100644
index 0000000..4034ce7
--- /dev/null
+++ b/test/js-perf-test/Templates/templates.js
@@ -0,0 +1,87 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+new BenchmarkSuite('Untagged', [1000], [
+  new Benchmark('Untagged-Simple', false, false, 0,
+                Untagged, UntaggedSetup, UntaggedTearDown),
+]);
+
+new BenchmarkSuite('LargeUntagged', [1000], [
+  new Benchmark('Untagged-Large', false, false, 0,
+                UntaggedLarge, UntaggedLargeSetup, UntaggedLargeTearDown),
+]);
+
+new BenchmarkSuite('Tagged', [1000], [
+  new Benchmark('TaggedRawSimple', false, false, 0,
+                TaggedRaw, TaggedRawSetup, TaggedRawTearDown),
+]);
+
+var result;
+var SUBJECT = 'Bob';
+var TARGET = 'Mary';
+var OBJECT = 'apple';
+
+function UntaggedSetup() {
+  result = undefined;
+}
+
+function Untagged() {
+  result = `${SUBJECT} gives ${TARGET} an ${OBJECT}.`;
+}
+
+function UntaggedTearDown() {
+  var expected = '' + SUBJECT + ' gives ' + TARGET + ' an ' + OBJECT + '.';
+  return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
+
+function UntaggedLargeSetup() {
+  result = undefined;
+}
+
+function UntaggedLarge() {
+  result = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
+ aliquam, elit euismod vestibulum ${0}lacinia, arcu odio sagittis mauris, id
+ blandit dolor felis pretium nisl. Maecenas porttitor, nunc ut accumsan mollis,
+ arcu metus rutrum arcu, ${1}ut varius dolor lorem nec risus. Integer convallis
+ tristique ante, non pretium ante suscipit at. Sed egestas massa enim, convallis
+ fermentum neque vehicula ac. Donec imperdiet a tortor ac semper. Morbi accumsan
+ quam nec erat viverra iaculis. ${2}Donec a scelerisque cras amet.`;
+}
+
+function UntaggedLargeTearDown() {
+  var expected = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
+      "Vivamus\n aliquam, elit euismod vestibulum " + 0 + "lacinia, arcu odio" +
+      " sagittis mauris, id\n blandit dolor felis pretium nisl. Maecenas " +
+      "porttitor, nunc ut accumsan mollis,\n arcu metus rutrum arcu, " + 1 +
+      "ut varius dolor lorem nec risus. Integer convallis\n tristique ante, " +
+      "non pretium ante suscipit at. Sed egestas massa enim, convallis\n " +
+      "fermentum neque vehicula ac. Donec imperdiet a tortor ac semper. Morbi" +
+      " accumsan\n quam nec erat viverra iaculis. " + 2 + "Donec a " +
+      "scelerisque cras amet.";
+  return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
+
+
+function TaggedRawSetup() {
+  result = undefined;
+}
+
+function TaggedRaw() {
+  result = String.raw `${SUBJECT} gives ${TARGET} an ${OBJECT} \ud83c\udf4f.`;
+}
+
+function TaggedRawTearDown() {
+  var expected =
+      '' + SUBJECT + ' gives ' + TARGET + ' an ' + OBJECT + ' \\ud83c\\udf4f.';
+  return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
diff --git a/test/perf-test/Collections/base.js b/test/js-perf-test/base.js
similarity index 100%
rename from test/perf-test/Collections/base.js
rename to test/js-perf-test/base.js
diff --git a/test/libplatform-unittests/libplatform-unittests.status b/test/libplatform-unittests/libplatform-unittests.status
deleted file mode 100644
index d439913..0000000
--- a/test/libplatform-unittests/libplatform-unittests.status
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2014 the V8 project authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-[
-]
diff --git a/test/message/single-function-literal.js b/test/message/single-function-literal.js
index 96d3bd6..fd73491 100644
--- a/test/message/single-function-literal.js
+++ b/test/message/single-function-literal.js
@@ -27,6 +27,6 @@
 
 // Flags: --allow-natives-syntax
 var single_function_good = "(function() { return 5; })";
-%CompileString(single_function_good, true);
+%CompileString(single_function_good, true, 0);
 var single_function_bad = "(function() { return 5; })();";
-%CompileString(single_function_bad, true);
+%CompileString(single_function_bad, true, 0);
diff --git a/test/message/super-constructor-extra-statement.js b/test/message/super-constructor-extra-statement.js
new file mode 100644
index 0000000..e8ffe2d
--- /dev/null
+++ b/test/message/super-constructor-extra-statement.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-classes
+'use strict';
+
+class C {
+  constructor() {
+    var x;
+    super(x);
+  }
+}
+
+var c = new C();
diff --git a/test/message/super-constructor-extra-statement.out b/test/message/super-constructor-extra-statement.out
new file mode 100644
index 0000000..cbe1e07
--- /dev/null
+++ b/test/message/super-constructor-extra-statement.out
@@ -0,0 +1,8 @@
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported.
+    var x;
+    
+TypeError: A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported.
+    at *%(basename)s:15:9
diff --git a/test/message/super-constructor.js b/test/message/super-constructor.js
new file mode 100644
index 0000000..430dc58
--- /dev/null
+++ b/test/message/super-constructor.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-classes
+'use strict';
+
+class C {
+  constructor() {
+    super(this.x);
+  }
+}
+
+var c = new C();
diff --git a/test/message/super-constructor.out b/test/message/super-constructor.out
new file mode 100644
index 0000000..bc3a699
--- /dev/null
+++ b/test/message/super-constructor.out
@@ -0,0 +1,8 @@
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:10: TypeError: A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported.
+    super(this.x);
+     
+TypeError: A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported.
+    at *%(basename)s:14:9
diff --git a/test/message/testcfg.py b/test/message/testcfg.py
index b472f9c..5d6ab84 100644
--- a/test/message/testcfg.py
+++ b/test/message/testcfg.py
@@ -75,6 +75,7 @@
   def _IgnoreLine(self, string):
     """Ignore empty lines, valgrind output, Android output."""
     if not string: return True
+    if not string.strip(): return True
     return (string.startswith("==") or string.startswith("**") or
             string.startswith("ANDROID") or
             # These five patterns appear in normal Native Client output.
diff --git a/test/mjsunit/array-iteration.js b/test/mjsunit/array-iteration.js
index d11f984..1324074 100644
--- a/test/mjsunit/array-iteration.js
+++ b/test/mjsunit/array-iteration.js
@@ -68,6 +68,23 @@
   assertEquals(3, count);
   for (var i in a) assertEquals(2, a[i]);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].filter(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].filter(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].filter(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 
@@ -109,6 +126,23 @@
   a.forEach(function(n) { count++; });
   assertEquals(1, count);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].forEach(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].forEach(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].forEach(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 
@@ -149,6 +183,23 @@
   assertTrue(a.every(function(n) { count++; return n == 2; }));
   assertEquals(2, count);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].every(function() { a.push(this); return true; }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].every(function() { a.push(this); return true; }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].every(function() { 'use strict'; a.push(this); return true; }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 //
@@ -186,6 +237,23 @@
   a = a.map(function(n) { return 2*n; });
   for (var i in a) assertEquals(4, a[i]);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].map(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].map(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].map(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 //
@@ -224,4 +292,21 @@
   assertTrue(a.some(function(n) { count++; return n == 2; }));
   assertEquals(2, count);
 
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].some(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].some(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].some(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
diff --git a/test/mjsunit/array-methods-read-only-length.js b/test/mjsunit/array-methods-read-only-length.js
new file mode 100644
index 0000000..2943b16
--- /dev/null
+++ b/test/mjsunit/array-methods-read-only-length.js
@@ -0,0 +1,166 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function testAdd(mode) {
+  var a = [];
+  Object.defineProperty(a, "length", { writable : false});
+
+  function check(f) {
+    assertThrows(function() { f(a) }, TypeError);
+    assertFalse(0 in a);
+    assertEquals(0, a.length);
+  }
+
+  function push(a) {
+    a.push(3);
+  }
+
+  if (mode == "fast properties") %ToFastProperties(a);
+
+  check(push);
+  check(push);
+  check(push);
+  %OptimizeFunctionOnNextCall(push);
+  check(push);
+
+  function unshift(a) {
+    a.unshift(3);
+  }
+
+  check(unshift);
+  check(unshift);
+  check(unshift);
+  %OptimizeFunctionOnNextCall(unshift);
+  check(unshift);
+
+  function splice(a) {
+    a.splice(0, 0, 3);
+  }
+
+  check(splice);
+  check(splice);
+  check(splice);
+  %OptimizeFunctionOnNextCall(splice);
+  check(splice);
+}
+
+testAdd("fast properties");
+
+testAdd("normalized");
+
+function testRemove(a, mode) {
+  Object.defineProperty(a, "length", { writable : false});
+
+  function check(f) {
+    assertThrows(function() { f(a) }, TypeError);
+    assertEquals(3, a.length);
+  }
+
+  if (mode == "fast properties") %ToFastProperties(a);
+
+  function pop(a) {
+    a.pop();
+  }
+
+  check(pop);
+  check(pop);
+  check(pop);
+  %OptimizeFunctionOnNextCall(pop);
+  check(pop);
+
+  function shift(a) {
+    a.shift();
+  }
+
+  check(shift);
+  check(shift);
+  check(shift);
+  %OptimizeFunctionOnNextCall(shift);
+  check(shift);
+
+  function splice(a) {
+    a.splice(0, 1);
+  }
+
+  check(splice);
+  check(splice);
+  check(splice);
+  %OptimizeFunctionOnNextCall(splice);
+  check(splice);
+
+  %ClearFunctionTypeFeedback(pop);
+  %ClearFunctionTypeFeedback(shift);
+  %ClearFunctionTypeFeedback(splice);
+}
+
+for (var i = 0; i < 3; i++) {
+  var a = [1, 2, 3];
+  if (i == 1) {
+    a = [1, 2, 3.5];
+  } else if (i == 2) {
+    a = [1, 2, "string"];
+  }
+  testRemove(a, "fast properties");
+  testRemove(a, "normalized");
+}
+
+var b = [];
+Object.defineProperty(b.__proto__, "0", {
+  set : function(v) {
+    b.x = v;
+    Object.defineProperty(b, "length", { writable : false });
+  },
+  get: function() {
+    return b.x;
+  }
+});
+
+b = [];
+try {
+  b.push(3, 4, 5);
+} catch(e) { }
+assertFalse(1 in b);
+assertFalse(2 in b);
+assertEquals(0, b.length);
+
+b = [];
+try {
+  b.unshift(3, 4, 5);
+} catch(e) { }
+assertFalse(1 in b);
+assertFalse(2 in b);
+assertEquals(0, b.length);
+
+b = [1, 2];
+try {
+  b.unshift(3, 4, 5);
+} catch(e) { }
+assertEquals(3, b[0]);
+assertEquals(4, b[1]);
+assertEquals(5, b[2]);
+assertEquals(1, b[3]);
+assertEquals(2, b[4]);
+assertEquals(5, b.length);
+
+b = [1, 2];
+
+Object.defineProperty(b.__proto__, "4", {
+  set : function(v) {
+    b.z = v;
+    Object.defineProperty(b, "length", { writable : false });
+  },
+  get: function() {
+    return b.z;
+  }
+});
+
+try {
+  b.unshift(3, 4, 5);
+} catch(e) { }
+
+assertFalse(2 in b);
+assertFalse(3 in b);
+assertEquals(2, b.length);
diff --git a/test/mjsunit/array-natives-elements.js b/test/mjsunit/array-natives-elements.js
index d63346d..a19a931 100644
--- a/test/mjsunit/array-natives-elements.js
+++ b/test/mjsunit/array-natives-elements.js
@@ -274,14 +274,11 @@
   assertEquals([1,1,2,3], a4);
   a4 = [1,2,3];
   a4.unshift(1.1);
-  // TODO(verwaest): We'll want to support double unshifting as well.
-  // assertTrue(%HasFastDoubleElements(a4));
-  assertTrue(%HasFastObjectElements(a4));
+  assertTrue(%HasFastDoubleElements(a4));
   assertEquals([1.1,1,2,3], a4);
   a4 = [1.1,2,3];
   a4.unshift(1);
-  // assertTrue(%HasFastDoubleElements(a4));
-  assertTrue(%HasFastObjectElements(a4));
+  assertTrue(%HasFastDoubleElements(a4));
   assertEquals([1,1.1,2,3], a4);
   a4 = [{},2,3];
   a4.unshift(1);
diff --git a/test/mjsunit/array-push-unshift-read-only-length.js b/test/mjsunit/array-push-unshift-read-only-length.js
deleted file mode 100644
index 67aa397..0000000
--- a/test/mjsunit/array-push-unshift-read-only-length.js
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Flags: --allow-natives-syntax
-
-function test(mode) {
-  var a = [];
-  Object.defineProperty(a, "length", { writable : false});
-
-  function check(f) {
-    try {
-      f(a);
-    } catch(e) { }
-    assertFalse(0 in a);
-    assertEquals(0, a.length);
-  }
-
-  function push(a) {
-    a.push(3);
-  }
-
-  if (mode == "fast properties") %ToFastProperties(a);
-
-  check(push);
-  check(push);
-  check(push);
-  %OptimizeFunctionOnNextCall(push);
-  check(push);
-
-  function unshift(a) {
-    a.unshift(3);
-  }
-
-  check(unshift);
-  check(unshift);
-  check(unshift);
-  %OptimizeFunctionOnNextCall(unshift);
-  check(unshift);
-}
-
-test("fast properties");
-
-test("normalized");
-
-var b = [];
-Object.defineProperty(b.__proto__, "0", {
-  set : function(v) {
-    b.x = v;
-    Object.defineProperty(b, "length", { writable : false });
-  },
-  get: function() {
-    return b.x;
-  }
-});
-
-b = [];
-try {
-  b.push(3, 4, 5);
-} catch(e) { }
-assertFalse(1 in b);
-assertFalse(2 in b);
-assertEquals(0, b.length);
-
-b = [];
-try {
-  b.unshift(3, 4, 5);
-} catch(e) { }
-assertFalse(1 in b);
-assertFalse(2 in b);
-assertEquals(0, b.length);
-
-b = [1, 2];
-try {
-  b.unshift(3, 4, 5);
-} catch(e) { }
-assertEquals(3, b[0]);
-assertEquals(4, b[1]);
-assertEquals(5, b[2]);
-assertEquals(1, b[3]);
-assertEquals(2, b[4]);
-assertEquals(5, b.length);
-
-b = [1, 2];
-
-Object.defineProperty(b.__proto__, "4", {
-  set : function(v) {
-    b.z = v;
-    Object.defineProperty(b, "length", { writable : false });
-  },
-  get: function() {
-    return b.z;
-  }
-});
-
-try {
-  b.unshift(3, 4, 5);
-} catch(e) { }
-
-// TODO(ulan): According to the ECMA-262 unshift should throw an exception
-// when moving b[0] to b[3] (see 15.4.4.13 step 6.d.ii). This is difficult
-// to do with our current implementation of SmartMove() in src/array.js and
-// it will regress performance. Uncomment the following line once acceptable
-// solution is found:
-// assertFalse(2 in b);
-// assertFalse(3 in b);
-// assertEquals(2, b.length);
diff --git a/test/mjsunit/array-reduce.js b/test/mjsunit/array-reduce.js
index 429f348..94e5144 100644
--- a/test/mjsunit/array-reduce.js
+++ b/test/mjsunit/array-reduce.js
@@ -521,3 +521,13 @@
             [3, 3, 2, [1, 2, 3, 4, 4, 5], 6],
             [6, 4, 3, [1, 2, 3, 4, 4, 5, 6], 10],
            ], arr, extender, 0);
+
+var arr = [];
+Object.defineProperty(arr, "0", { get: function() { delete this[0] },
+  configurable: true });
+assertEquals(undefined, arr.reduce(function(val) { return val }));
+
+var arr = [];
+Object.defineProperty(arr, "0", { get: function() { delete this[0] },
+  configurable: true});
+assertEquals(undefined, arr.reduceRight(function(val) { return val }));
diff --git a/test/mjsunit/array-shift2.js b/test/mjsunit/array-shift2.js
index 73d8cd4..75233ff 100644
--- a/test/mjsunit/array-shift2.js
+++ b/test/mjsunit/array-shift2.js
@@ -12,7 +12,17 @@
   array.shift();
   return array;
 }
-assertEquals(["element 1",2], test(["0",,2]));
-assertEquals(["element 1",{}], test([{},,{}]));
+
+var result = test(["0",,2]);
+assertEquals(["element 1","element 1"], result);
+assertTrue(result.hasOwnProperty("0"));
+assertFalse(result.hasOwnProperty("1"));
+result = test([{},,{}]);
+assertEquals(["element 1","element 1"], result);
+assertTrue(result.hasOwnProperty("0"));
+assertFalse(result.hasOwnProperty("1"));
 %OptimizeFunctionOnNextCall(test);
-assertEquals(["element 1",0], test([{},,0]));
+result = test([{},,0]);
+assertEquals(["element 1","element 1"], result);
+assertTrue(result.hasOwnProperty("0"));
+assertFalse(result.hasOwnProperty("1"));
diff --git a/test/mjsunit/array-shift4.js b/test/mjsunit/array-shift4.js
new file mode 100644
index 0000000..669b11a
--- /dev/null
+++ b/test/mjsunit/array-shift4.js
@@ -0,0 +1,24 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+// Inlining shift with holey smi arrays shouldn't deopt just because it
+// encounters the hole on the copy step.
+function doShift(a) {
+  var x = a.shift();
+  return x;
+}
+
+function makeArray() {
+  var a = [1, 2,, 3];
+  a[0] = 2;
+  return a;
+}
+
+doShift(makeArray());
+doShift(makeArray());
+%OptimizeFunctionOnNextCall(doShift);
+doShift(makeArray());
+assertOptimized(doShift);
diff --git a/test/mjsunit/array-unshift.js b/test/mjsunit/array-unshift.js
index 0eb299a..50aab4f 100644
--- a/test/mjsunit/array-unshift.js
+++ b/test/mjsunit/array-unshift.js
@@ -37,9 +37,7 @@
 })();
 
 
-// Check that unshift with no args has a side-effect of
-// filling the holes with elements from the prototype
-// (if present, of course)
+// Check that unshift with no args has no side-effects.
 (function() {
   var len = 3;
   var array = new Array(len);
@@ -65,15 +63,15 @@
   assertTrue(delete Array.prototype[0]);
   assertTrue(delete Array.prototype[2]);
 
-  // unshift makes array own 0 and 2...
-  assertTrue(array.hasOwnProperty(0));
+  // array still owns nothing...
+  assertFalse(array.hasOwnProperty(0));
   assertFalse(array.hasOwnProperty(1));
-  assertTrue(array.hasOwnProperty(2));
+  assertFalse(array.hasOwnProperty(2));
 
   // ... so they are not affected be delete.
-  assertEquals(array[0], at0);
+  assertEquals(array[0], undefined);
   assertEquals(array[1], undefined);
-  assertEquals(array[2], at2);
+  assertEquals(array[2], undefined);
 })();
 
 
@@ -115,9 +113,7 @@
   assertTrue(delete Array.prototype[7]);
 })();
 
-// Check that unshift with no args has a side-effect of
-// filling the holes with elements from the prototype
-// (if present, of course)
+// Check that unshift with no args has no side-effects.
 (function() {
   var len = 3;
   var array = new Array(len);
@@ -142,12 +138,12 @@
 
   assertEquals(len, array.unshift());
 
-  // unshift makes array own 0 and 2...
-  assertTrue(array.hasOwnProperty(0));
+  // array still owns nothing.
+  assertFalse(array.hasOwnProperty(0));
   assertFalse(array.hasOwnProperty(1));
-  assertTrue(array.hasOwnProperty(2));
+  assertFalse(array.hasOwnProperty(2));
 
-  // ... so they are not affected be delete.
+  // ... but still sees values from array_proto.
   assertEquals(array[0], at0);
   assertEquals(array[1], undefined);
   assertEquals(array[2], at2);
diff --git a/test/mjsunit/asm/do-while-false.js b/test/mjsunit/asm/do-while-false.js
new file mode 100644
index 0000000..ba906a0
--- /dev/null
+++ b/test/mjsunit/asm/do-while-false.js
@@ -0,0 +1,78 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+
+  function d0() {
+    do { } while(false);
+    return 110;
+  }
+
+  function d1() {
+    do { return 111; } while(false);
+    return 112;
+  }
+
+  function d2() {
+    do { break; } while(false);
+    return 113;
+  }
+
+  function d3(a) {
+    a = a | 0;
+    do { if (a) return 114; } while(false);
+    return 115;
+  }
+
+  function d4(a) {
+    a = a | 0;
+    do { if (a) return 116; else break; } while(false);
+    return 117;
+  }
+
+  function d5(a) {
+    a = a | 0;
+    do { if (a) return 118; } while(false);
+    return 119;
+  }
+
+  function d6(a) {
+    a = a | 0;
+    do {
+      if (a == 0) return 120;
+      if (a == 1) break;
+      if (a == 2) return 122;
+      if (a == 3) continue;
+      if (a == 4) return 124;
+    } while(false);
+    return 125;
+  }
+
+  return {d0: d0, d1: d1, d2: d2, d3: d3, d4: d4, d5: d5, d6: d6};
+}
+
+var m = Module();
+
+assertEquals(110, m.d0());
+
+assertEquals(111, m.d1());
+
+assertEquals(113, m.d2());
+
+assertEquals(114, m.d3(1));
+assertEquals(115, m.d3(0));
+
+assertEquals(116, m.d4(1));
+assertEquals(117, m.d4(0));
+
+assertEquals(118, m.d5(1));
+assertEquals(119, m.d5(0));
+
+assertEquals(120, m.d6(0));
+assertEquals(125, m.d6(1));
+assertEquals(122, m.d6(2));
+assertEquals(125, m.d6(3));
+assertEquals(124, m.d6(4));
+assertEquals(125, m.d6(5));
diff --git a/test/mjsunit/asm/do-while.js b/test/mjsunit/asm/do-while.js
new file mode 100644
index 0000000..214be64
--- /dev/null
+++ b/test/mjsunit/asm/do-while.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, buffer) {
+  "use asm";
+  function f(i) {
+    var j;
+    i = i|0;
+    do {
+      if (i > 0) {
+        j = i != 0;
+        i = (i - 1) | 0;
+      } else {
+        j = 0;
+      }
+    } while (j);
+    return i;
+  }
+  return {f:f};
+}
+
+var m = Module(this, {}, new ArrayBuffer(64*1024));
+
+assertEquals(-1, m.f("-1"));
+assertEquals(0, m.f(-Math.infinity));
+assertEquals(0, m.f(undefined));
+assertEquals(0, m.f(0));
+assertEquals(0, m.f(1));
+assertEquals(0, m.f(100));
diff --git a/test/mjsunit/asm/embenchen/box2d.js b/test/mjsunit/asm/embenchen/box2d.js
new file mode 100644
index 0000000..9bb029e
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/box2d.js
@@ -0,0 +1,20322 @@
+var EXPECTED_OUTPUT =
+  /frame averages: .+ \+- .+, range: .+ to .+ \n/;
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertTrue(EXPECTED_OUTPUT.test(Module.printBuffer));
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+var __ZTVN10__cxxabiv117__class_type_infoE = 7024;
+var __ZTVN10__cxxabiv120__si_class_type_infoE = 7064;
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(7731);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([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,232,118,72,0,0,0,0,255,255,255,255,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,101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,102,114,97,109,101,32,97,118,101,114,97,103,101,115,58,32,37,46,51,102,32,43,45,32,37,46,51,102,44,32,114,97,110,103,101,58,32,37,46,51,102,32,116,111,32,37,46,51,102,32,10,0,0,0,0,0,105,102,32,40,77,111,100,117,108,101,46,114,101,112,111,114,116,67,111,109,112,108,101,116,105,111,110,41,32,77,111,100,117,108,101,46,114,101,112,111,114,116,67,111,109,112,108,101,116,105,111,110,40,41,0,0,114,101,115,112,111,110,115,105,118,101,32,109,97,105,110,32,108,111,111,112,0,0,0,0,0,0,0,0,56,1,0,0,1,0,0,0,2,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,49,49,98,50,69,100,103,101,83,104,97,112,101,0,0,0,55,98,50,83,104,97,112,101,0,0,0,0,0,0,0,0,120,27,0,0,32,1,0,0,160,27,0,0,16,1,0,0,48,1,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,83,104,97,112,101,115,47,98,50,80,111,108,121,103,111,110,83,104,97,112,101,46,99,112,112,0,0,0,0,0,0,0,48,46,48,102,32,60,61,32,108,111,119,101,114,32,38,38,32,108,111,119,101,114,32,60,61,32,105,110,112,117,116,46,109,97,120,70,114,97,99,116,105,111,110,0,0,0,0,0,82,97,121,67,97,115,116,0,109,95,118,101,114,116,101,120,67,111,117,110,116,32,62,61,32,51,0,0,0,0,0,0,67,111,109,112,117,116,101,77,97,115,115,0,0,0,0,0,97,114,101,97,32,62,32,49,46,49,57,50,48,57,50,57,48,101,45,48,55,70,0,0,0,0,0,0,48,2,0,0,3,0,0,0,4,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,49,52,98,50,80,111,108,121,103,111,110,83,104,97,112,101,0,0,0,0,0,0,0,0,160,27,0,0,24,2,0,0,48,1,0,0,0,0,0,0,16,0,0,0,32,0,0,0,64,0,0,0,96,0,0,0,128,0,0,0,160,0,0,0,192,0,0,0,224,0,0,0,0,1,0,0,64,1,0,0,128,1,0,0,192,1,0,0,0,2,0,0,128,2,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,32,60,32,98,50,95,98,108,111,99,107,83,105,122,101,115,0,0,0,0,0,0,0,66,111,120,50,68,47,67,111,109,109,111,110,47,98,50,66,108,111,99,107,65,108,108,111,99,97,116,111,114,46,99,112,112,0,0,0,0,0,0,0,98,50,66,108,111,99,107,65,108,108,111,99,97,116,111,114,0,0,0,0,0,0,0,0,48,32,60,32,115,105,122,101,0,0,0,0,0,0,0,0,65,108,108,111,99,97,116,101,0,0,0,0,0,0,0,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,98,50,95,98,108,111,99,107,83,105,122,101,115,0,0,0,0,0,98,108,111,99,107,67,111,117,110,116,32,42,32,98,108,111,99,107,83,105,122,101,32,60,61,32,98,50,95,99,104,117,110,107,83,105,122,101,0,0,70,114,101,101,0,0,0,0,98,100,45,62,112,111,115,105,116,105,111,110,46,73,115,86,97,108,105,100,40,41,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,66,111,100,121,46,99,112,112,0,0,0,0,0,0,0,98,50,66,111,100,121,0,0,98,100,45,62,108,105,110,101,97,114,86,101,108,111,99,105,116,121,46,73,115,86,97,108,105,100,40,41,0,0,0,0,98,50,73,115,86,97,108,105,100,40,98,100,45,62,97,110,103,108,101,41,0,0,0,0,98,50,73,115,86,97,108,105,100,40,98,100,45,62,97,110,103,117,108,97,114,86,101,108,111,99,105,116,121,41,0,0,98,50,73,115,86,97,108,105,100,40,98,100,45,62,97,110,103,117,108,97,114,68,97,109,112,105,110,103,41,32,38,38,32,98,100,45,62,97,110,103,117,108,97,114,68,97,109,112,105,110,103,32,62,61,32,48,46,48,102,0,0,0,0,0,98,50,73,115,86,97,108,105,100,40,98,100,45,62,108,105,110,101,97,114,68,97,109,112,105,110,103,41,32,38,38,32,98,100,45,62,108,105,110,101,97,114,68,97,109,112,105,110,103,32,62,61,32,48,46,48,102,0,0,0,0,0,0,0,109,95,119,111,114,108,100,45,62,73,115,76,111,99,107,101,100,40,41,32,61,61,32,102,97,108,115,101,0,0,0,0,67,114,101,97,116,101,70,105,120,116,117,114,101,0,0,0,109,95,116,121,112,101,32,61,61,32,98,50,95,100,121,110,97,109,105,99,66,111,100,121,0,0,0,0,0,0,0,0,82,101,115,101,116,77,97,115,115,68,97,116,97,0,0,0,109,95,73,32,62,32,48,46,48,102,0,0,0,0,0,0,0,10,0,0,0,0,0,0,240,7,0,0,0,0,0,0,48,32,60,61,32,112,114,111,120,121,73,100,32,38,38,32,112,114,111,120,121,73,100,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,0,0,0,0,0,0,46,47,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,121,110,97,109,105,99,84,114,101,101,46,104,0,0,0,0,0,0,0,71,101,116,85,115,101,114,68,97,116,97,0,0,0,0,0,71,101,116,70,97,116,65,65,66,66,0,0,0,0,0,0,0,0,0,0,32,8,0,0,5,0,0,0,6,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,49,55,98,50,67,111,110,116,97,99,116,76,105,115,116,101,110,101,114,0,0,0,0,0,120,27,0,0,8,8,0,0,109,95,112,114,111,120,121,67,111,117,110,116,32,61,61,32,48,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,70,105,120,116,117,114,101,46,99,112,112,0,0,0,0,67,114,101,97,116,101,80,114,111,120,105,101,115,0,0,0,73,115,76,111,99,107,101,100,40,41,32,61,61,32,102,97,108,115,101,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,87,111,114,108,100,46,99,112,112,0,0,0,0,0,0,67,114,101,97,116,101,66,111,100,121,0,0,0,0,0,0,98,45,62,73,115,65,99,116,105,118,101,40,41,32,61,61,32,116,114,117,101,0,0,0,83,111,108,118,101,0,0,0,115,116,97,99,107,67,111,117,110,116,32,60,32,115,116,97,99,107,83,105,122,101,0,0,116,121,112,101,65,32,61,61,32,98,50,95,100,121,110,97,109,105,99,66,111,100,121,32,124,124,32,116,121,112,101,66,32,61,61,32,98,50,95,100,121,110,97,109,105,99,66,111,100,121,0,0,0,0,0,0,83,111,108,118,101,84,79,73,0,0,0,0,0,0,0,0,97,108,112,104,97,48,32,60,32,49,46,48,102,0,0,0,46,47,66,111,120,50,68,47,67,111,109,109,111,110,47,98,50,77,97,116,104,46,104,0,65,100,118,97,110,99,101,0,109,95,106,111,105,110,116,67,111,117,110,116,32,60,32,109,95,106,111,105,110,116,67,97,112,97,99,105,116,121,0,0,46,47,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,73,115,108,97,110,100,46,104,0,0,0,0,0,65,100,100,0,0,0,0,0,109,95,99,111,110,116,97,99,116,67,111,117,110,116,32,60,32,109,95,99,111,110,116,97,99,116,67,97,112,97,99,105,116,121,0,0,0,0,0,0,109,95,98,111,100,121,67,111,117,110,116,32,60,32,109,95,98,111,100,121,67,97,112,97,99,105,116,121,0,0,0,0,0,0,0,0,40,10,0,0,7,0,0,0,8,0,0,0,3,0,0,0,0,0,0,0,49,53,98,50,67,111,110,116,97,99,116,70,105,108,116,101,114,0,0,0,0,0,0,0,120,27,0,0,16,10,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,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,99,104,97,105,110,45,62,109,95,99,111,117,110,116,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,105,115,116,97,110,99,101,46,99,112,112,0,0,83,101,116,0,0,0,0,0,102,97,108,115,101,0,0,0,98,50,68,105,115,116,97,110,99,101,0,0,0,0,0,0,71,101,116,77,101,116,114,105,99,0,0,0,0,0,0,0,71,101,116,87,105,116,110,101,115,115,80,111,105,110,116,115,0,0,0,0,0,0,0,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,109,95,99,111,117,110,116,0,0,0,46,47,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,105,115,116,97,110,99,101,46,104,0,0,71,101,116,86,101,114,116,101,120,0,0,0,0,0,0,0,71,101,116,67,108,111,115,101,115,116,80,111,105,110,116,0,99,97,99,104,101,45,62,99,111,117,110,116,32,60,61,32,51,0,0,0,0,0,0,0,82,101,97,100,67,97,99,104,101,0,0,0,0,0,0,0,109,95,110,111,100,101,67,111,117,110,116,32,61,61,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,121,110,97,109,105,99,84,114,101,101,46,99,112,112,0,0,0,0,0,0,0,65,108,108,111,99,97,116,101,78,111,100,101,0,0,0,0,48,32,60,61,32,110,111,100,101,73,100,32,38,38,32,110,111,100,101,73,100,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,70,114,101,101,78,111,100,101,0,0,0,0,0,0,0,0,48,32,60,32,109,95,110,111,100,101,67,111,117,110,116,0,48,32,60,61,32,112,114,111,120,121,73,100,32,38,38,32,112,114,111,120,121,73,100,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,0,0,0,0,0,0,109,95,110,111,100,101,115,91,112,114,111,120,121,73,100,93,46,73,115,76,101,97,102,40,41,0,0,0,0,0,0,0,77,111,118,101,80,114,111,120,121,0,0,0,0,0,0,0,99,104,105,108,100,49,32,33,61,32,40,45,49,41,0,0,73,110,115,101,114,116,76,101,97,102,0,0,0,0,0,0,99,104,105,108,100,50,32,33,61,32,40,45,49,41,0,0,105,65,32,33,61,32,40,45,49,41,0,0,0,0,0,0,66,97,108,97,110,99,101,0,48,32,60,61,32,105,66,32,38,38,32,105,66,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,48,32,60,61,32,105,67,32,38,38,32,105,67,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,48,32,60,61,32,105,70,32,38,38,32,105,70,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,48,32,60,61,32,105,71,32,38,38,32,105,71,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,109,95,110,111,100,101,115,91,67,45,62,112,97,114,101,110,116,93,46,99,104,105,108,100,50,32,61,61,32,105,65,0,48,32,60,61,32,105,68,32,38,38,32,105,68,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,48,32,60,61,32,105,69,32,38,38,32,105,69,32,60,32,109,95,110,111,100,101,67,97,112,97,99,105,116,121,0,0,109,95,110,111,100,101,115,91,66,45,62,112,97,114,101,110,116,93,46,99,104,105,108,100,50,32,61,61,32,105,65,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,116,97,114,103,101,116,32,62,32,116,111,108,101,114,97,110,99,101,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,84,105,109,101,79,102,73,109,112,97,99,116,46,99,112,112,0,0,0,0,0,0,98,50,84,105,109,101,79,102,73,109,112,97,99,116,0,0,102,97,108,115,101,0,0,0,69,118,97,108,117,97,116,101,0,0,0,0,0,0,0,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,109,95,99,111,117,110,116,0,0,0,46,47,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,68,105,115,116,97,110,99,101,46,104,0,0,71,101,116,86,101,114,116,101,120,0,0,0,0,0,0,0,70,105,110,100,77,105,110,83,101,112,97,114,97,116,105,111,110,0,0,0,0,0,0,0,48,32,60,32,99,111,117,110,116,32,38,38,32,99,111,117,110,116,32,60,32,51,0,0,73,110,105,116,105,97,108,105,122,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109,95,105,110,100,101,120,32,61,61,32,48,0,0,0,0,66,111,120,50,68,47,67,111,109,109,111,110,47,98,50,83,116,97,99,107,65,108,108,111,99,97,116,111,114,46,99,112,112,0,0,0,0,0,0,0,126,98,50,83,116,97,99,107,65,108,108,111,99,97,116,111,114,0,0,0,0,0,0,0,109,95,101,110,116,114,121,67,111,117,110,116,32,61,61,32,48,0,0,0,0,0,0,0,109,95,101,110,116,114,121,67,111,117,110,116,32,60,32,98,50,95,109,97,120,83,116,97,99,107,69,110,116,114,105,101,115,0,0,0,0,0,0,0,65,108,108,111,99,97,116,101,0,0,0,0,0,0,0,0,109,95,101,110,116,114,121,67,111,117,110,116,32,62,32,48,0,0,0,0,0,0,0,0,70,114,101,101,0,0,0,0,112,32,61,61,32,101,110,116,114,121,45,62,100,97,116,97,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,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,48,32,60,61,32,116,121,112,101,49,32,38,38,32,116,121,112,101,49,32,60,32,98,50,83,104,97,112,101,58,58,101,95,116,121,112,101,67,111,117,110,116,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,111,110,116,97,99,116,46,99,112,112,0,0,0,48,32,60,61,32,116,121,112,101,50,32,38,38,32,116,121,112,101,50,32,60,32,98,50,83,104,97,112,101,58,58,101,95,116,121,112,101,67,111,117,110,116,0,0,0,0,0,0,67,114,101,97,116,101,0,0,115,95,105,110,105,116,105,97,108,105,122,101,100,32,61,61,32,116,114,117,101,0,0,0,68,101,115,116,114,111,121,0,48,32,60,61,32,116,121,112,101,65,32,38,38,32,116,121,112,101,66,32,60,32,98,50,83,104,97,112,101,58,58,101,95,116,121,112,101,67,111,117,110,116,0,0,0,0,0,0,0,0,0,0,120,17,0,0,1,0,0,0,9,0,0,0,10,0,0,0,0,0,0,0,57,98,50,67,111,110,116,97,99,116,0,0,0,0,0,0,120,27,0,0,104,17,0,0,0,0,0,0,104,18,0,0,3,0,0,0,11,0,0,0,12,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,101,100,103,101,0,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,69,100,103,101,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,0,0,98,50,69,100,103,101,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,50,50,98,50,69,100,103,101,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,0,0,0,160,27,0,0,72,18,0,0,120,17,0,0,0,0,0,0,0,0,0,0,96,19,0,0,4,0,0,0,13,0,0,0,14,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,101,100,103,101,0,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,69,100,103,101,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,0,98,50,69,100,103,101,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,50,51,98,50,69,100,103,101,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,0,160,27,0,0,64,19,0,0,120,17,0,0,0,0,0,0,0,0,0,0,96,20,0,0,5,0,0,0,15,0,0,0,16,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,80,111,108,121,103,111,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,46,99,112,112,0,0,0,98,50,80,111,108,121,103,111,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,50,53,98,50,80,111,108,121,103,111,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,160,27,0,0,64,20,0,0,120,17,0,0,0,0,0,0,0,0,0,0,72,21,0,0,6,0,0,0,17,0,0,0,18,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,80,111,108,121,103,111,110,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,98,50,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,49,54,98,50,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,160,27,0,0,48,21,0,0,120,17,0,0,0,0,0,0,116,111,105,73,110,100,101,120,65,32,60,32,109,95,98,111,100,121,67,111,117,110,116,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,98,50,73,115,108,97,110,100,46,99,112,112,0,0,0,0,0,83,111,108,118,101,84,79,73,0,0,0,0,0,0,0,0,116,111,105,73,110,100,101,120,66,32,60,32,109,95,98,111,100,121,67,111,117,110,116,0,100,101,110,32,62,32,48,46,48,102,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,67,111,108,108,105,100,101,69,100,103,101,46,99,112,112,0,0,0,0,0,0,0,98,50,67,111,108,108,105,100,101,69,100,103,101,65,110,100,67,105,114,99,108,101,0,0,48,32,60,61,32,101,100,103,101,49,32,38,38,32,101,100,103,101,49,32,60,32,112,111,108,121,49,45,62,109,95,118,101,114,116,101,120,67,111,117,110,116,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,98,50,67,111,108,108,105,100,101,80,111,108,121,103,111,110,46,99,112,112,0,0,0,0,98,50,70,105,110,100,73,110,99,105,100,101,110,116,69,100,103,101,0,0,0,0,0,0,98,50,69,100,103,101,83,101,112,97,114,97,116,105,111,110,0,0,0,0,0,0,0,0,0,0,0,0,120,23,0,0,7,0,0,0,19,0,0,0,20,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,104,97,105,110,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,104,97,105,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,0,98,50,67,104,97,105,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,50,51,98,50,67,104,97,105,110,65,110,100,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,0,0,160,27,0,0,88,23,0,0,120,17,0,0,0,0,0,0,0,0,0,0,120,24,0,0,8,0,0,0,21,0,0,0,22,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,104,97,105,110,0,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,104,97,105,110,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,98,50,67,104,97,105,110,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,112,111,108,121,103,111,110,0,0,0,0,0,50,52,98,50,67,104,97,105,110,65,110,100,80,111,108,121,103,111,110,67,111,110,116,97,99,116,0,0,0,0,0,0,160,27,0,0,88,24,0,0,120,17,0,0,0,0,0,0,0,0,0,0,88,25,0,0,9,0,0,0,23,0,0,0,24,0,0,0,0,0,0,0,109,95,102,105,120,116,117,114,101,65,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,105,114,99,108,101,67,111,110,116,97,99,116,46,99,112,112,0,0,0,0,0,98,50,67,105,114,99,108,101,67,111,110,116,97,99,116,0,109,95,102,105,120,116,117,114,101,66,45,62,71,101,116,84,121,112,101,40,41,32,61,61,32,98,50,83,104,97,112,101,58,58,101,95,99,105,114,99,108,101,0,0,0,0,0,0,49,53,98,50,67,105,114,99,108,101,67,111,110,116,97,99,116,0,0,0,0,0,0,0,160,27,0,0,64,25,0,0,120,17,0,0,0,0,0,0,112,111,105,110,116,67,111,117,110,116,32,62,32,48,0,0,66,111,120,50,68,47,68,121,110,97,109,105,99,115,47,67,111,110,116,97,99,116,115,47,98,50,67,111,110,116,97,99,116,83,111,108,118,101,114,46,99,112,112,0,0,0,0,0,98,50,67,111,110,116,97,99,116,83,111,108,118,101,114,0,109,97,110,105,102,111,108,100,45,62,112,111,105,110,116,67,111,117,110,116,32,62,32,48,0,0,0,0,0,0,0,0,73,110,105,116,105,97,108,105,122,101,86,101,108,111,99,105,116,121,67,111,110,115,116,114,97,105,110,116,115,0,0,0,112,111,105,110,116,67,111,117,110,116,32,61,61,32,49,32,124,124,32,112,111,105,110,116,67,111,117,110,116,32,61,61,32,50,0,0,0,0,0,0,83,111,108,118,101,86,101,108,111,99,105,116,121,67,111,110,115,116,114,97,105,110,116,115,0,0,0,0,0,0,0,0,97,46,120,32,62,61,32,48,46,48,102,32,38,38,32,97,46,121,32,62,61,32,48,46,48,102,0,0,0,0,0,0,112,99,45,62,112,111,105,110,116,67,111,117,110,116,32,62,32,48,0,0,0,0,0,0,73,110,105,116,105,97,108,105,122,101,0,0,0,0,0,0,66,111,120,50,68,47,67,111,108,108,105,115,105,111,110,47,83,104,97,112,101,115,47,98,50,67,104,97,105,110,83,104,97,112,101,46,99,112,112,0,48,32,60,61,32,105,110,100,101,120,32,38,38,32,105,110,100,101,120,32,60,32,109,95,99,111,117,110,116,32,45,32,49,0,0,0,0,0,0,0,71,101,116,67,104,105,108,100,69,100,103,101,0,0,0,0,83,116,57,116,121,112,101,95,105,110,102,111,0,0,0,0,120,27,0,0,232,26,0,0,78,49,48,95,95,99,120,120,97,98,105,118,49,49,54,95,95,115,104,105,109,95,116,121,112,101,95,105,110,102,111,69,0,0,0,0,0,0,0,0,160,27,0,0,0,27,0,0,248,26,0,0,0,0,0,0,78,49,48,95,95,99,120,120,97,98,105,118,49,49,55,95,95,99,108,97,115,115,95,116,121,112,101,95,105,110,102,111,69,0,0,0,0,0,0,0,160,27,0,0,56,27,0,0,40,27,0,0,0,0,0,0,0,0,0,0,96,27,0,0,25,0,0,0,26,0,0,0,27,0,0,0,28,0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,10,0,0,0,0,0,0,0,232,27,0,0,25,0,0,0,29,0,0,0,27,0,0,0,28,0,0,0,4,0,0,0,2,0,0,0,2,0,0,0,11,0,0,0,78,49,48,95,95,99,120,120,97,98,105,118,49,50,48,95,95,115,105,95,99,108,97,115,115,95,116,121,112,101,95,105,110,102,111,69,0,0,0,0,160,27,0,0,192,27,0,0,96,27,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,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,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,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,0,0,40,30,0,0,30,0,0,0,31,0,0,0,3,0,0,0,0,0,0,0,115,116,100,58,58,98,97,100,95,97,108,108,111,99,0,0,83,116,57,98,97,100,95,97,108,108,111,99,0,0,0,0,160,27,0,0,24,30,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+  function _emscripten_set_main_loop(func, fps, simulateInfiniteLoop, arg) {
+      Module['noExitRuntime'] = true;
+
+      Browser.mainLoop.runner = function Browser_mainLoop_runner() {
+        if (ABORT) return;
+        if (Browser.mainLoop.queue.length > 0) {
+          var start = Date.now();
+          var blocker = Browser.mainLoop.queue.shift();
+          blocker.func(blocker.arg);
+          if (Browser.mainLoop.remainingBlockers) {
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var next = remaining%1 == 0 ? remaining-1 : Math.floor(remaining);
+            if (blocker.counted) {
+              Browser.mainLoop.remainingBlockers = next;
+            } else {
+              // not counted, but move the progress along a tiny bit
+              next = next + 0.5; // do not steal all the next one's progress
+              Browser.mainLoop.remainingBlockers = (8*remaining + next)/9;
+            }
+          }
+          console.log('main loop blocker "' + blocker.name + '" took ' + (Date.now() - start) + ' ms'); //, left: ' + Browser.mainLoop.remainingBlockers);
+          Browser.mainLoop.updateStatus();
+          setTimeout(Browser.mainLoop.runner, 0);
+          return;
+        }
+        if (Browser.mainLoop.shouldPause) {
+          // catch pauses from non-main loop sources
+          Browser.mainLoop.paused = true;
+          Browser.mainLoop.shouldPause = false;
+          return;
+        }
+
+        // Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize
+        // VBO double-buffering and reduce GPU stalls.
+
+        if (Browser.mainLoop.method === 'timeout' && Module.ctx) {
+          Module.printErr('Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!');
+          Browser.mainLoop.method = ''; // just warn once per call to set main loop
+        }
+
+        if (Module['preMainLoop']) {
+          Module['preMainLoop']();
+        }
+
+        try {
+          if (typeof arg !== 'undefined') {
+            Runtime.dynCall('vi', func, [arg]);
+          } else {
+            Runtime.dynCall('v', func);
+          }
+        } catch (e) {
+          if (e instanceof ExitStatus) {
+            return;
+          } else {
+            if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+            throw e;
+          }
+        }
+
+        if (Module['postMainLoop']) {
+          Module['postMainLoop']();
+        }
+
+        if (Browser.mainLoop.shouldPause) {
+          // catch pauses from the main loop itself
+          Browser.mainLoop.paused = true;
+          Browser.mainLoop.shouldPause = false;
+          return;
+        }
+        Browser.mainLoop.scheduler();
+      }
+      if (fps && fps > 0) {
+        Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler() {
+          setTimeout(Browser.mainLoop.runner, 1000/fps); // doing this each time means that on exception, we stop
+        };
+        Browser.mainLoop.method = 'timeout';
+      } else {
+        Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler() {
+          Browser.requestAnimationFrame(Browser.mainLoop.runner);
+        };
+        Browser.mainLoop.method = 'rAF';
+      }
+      Browser.mainLoop.scheduler();
+
+      if (simulateInfiniteLoop) {
+        throw 'SimulateInfiniteLoop';
+      }
+    }
+
+  var _cosf=Math_cos;
+
+  function ___cxa_pure_virtual() {
+      ABORT = true;
+      throw 'Pure virtual function called!';
+    }
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+  function ___assert_fail(condition, filename, line, func) {
+      ABORT = true;
+      throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace();
+    }
+
+
+  function __ZSt18uncaught_exceptionv() { // std::uncaught_exception()
+      return !!__ZSt18uncaught_exceptionv.uncaught_exception;
+    }
+
+
+
+  function ___cxa_is_number_type(type) {
+      var isNumber = false;
+      try { if (type == __ZTIi) isNumber = true } catch(e){}
+      try { if (type == __ZTIj) isNumber = true } catch(e){}
+      try { if (type == __ZTIl) isNumber = true } catch(e){}
+      try { if (type == __ZTIm) isNumber = true } catch(e){}
+      try { if (type == __ZTIx) isNumber = true } catch(e){}
+      try { if (type == __ZTIy) isNumber = true } catch(e){}
+      try { if (type == __ZTIf) isNumber = true } catch(e){}
+      try { if (type == __ZTId) isNumber = true } catch(e){}
+      try { if (type == __ZTIe) isNumber = true } catch(e){}
+      try { if (type == __ZTIc) isNumber = true } catch(e){}
+      try { if (type == __ZTIa) isNumber = true } catch(e){}
+      try { if (type == __ZTIh) isNumber = true } catch(e){}
+      try { if (type == __ZTIs) isNumber = true } catch(e){}
+      try { if (type == __ZTIt) isNumber = true } catch(e){}
+      return isNumber;
+    }function ___cxa_does_inherit(definiteType, possibilityType, possibility) {
+      if (possibility == 0) return false;
+      if (possibilityType == 0 || possibilityType == definiteType)
+        return true;
+      var possibility_type_info;
+      if (___cxa_is_number_type(possibilityType)) {
+        possibility_type_info = possibilityType;
+      } else {
+        var possibility_type_infoAddr = HEAP32[((possibilityType)>>2)] - 8;
+        possibility_type_info = HEAP32[((possibility_type_infoAddr)>>2)];
+      }
+      switch (possibility_type_info) {
+      case 0: // possibility is a pointer
+        // See if definite type is a pointer
+        var definite_type_infoAddr = HEAP32[((definiteType)>>2)] - 8;
+        var definite_type_info = HEAP32[((definite_type_infoAddr)>>2)];
+        if (definite_type_info == 0) {
+          // Also a pointer; compare base types of pointers
+          var defPointerBaseAddr = definiteType+8;
+          var defPointerBaseType = HEAP32[((defPointerBaseAddr)>>2)];
+          var possPointerBaseAddr = possibilityType+8;
+          var possPointerBaseType = HEAP32[((possPointerBaseAddr)>>2)];
+          return ___cxa_does_inherit(defPointerBaseType, possPointerBaseType, possibility);
+        } else
+          return false; // one pointer and one non-pointer
+      case 1: // class with no base class
+        return false;
+      case 2: // class with base class
+        var parentTypeAddr = possibilityType + 8;
+        var parentType = HEAP32[((parentTypeAddr)>>2)];
+        return ___cxa_does_inherit(definiteType, parentType, possibility);
+      default:
+        return false; // some unencountered type
+      }
+    }
+
+
+
+  var ___cxa_last_thrown_exception=0;function ___resumeException(ptr) {
+      if (!___cxa_last_thrown_exception) { ___cxa_last_thrown_exception = ptr; }
+      throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+    }
+
+  var ___cxa_exception_header_size=8;function ___cxa_find_matching_catch(thrown, throwntype) {
+      if (thrown == -1) thrown = ___cxa_last_thrown_exception;
+      header = thrown - ___cxa_exception_header_size;
+      if (throwntype == -1) throwntype = HEAP32[((header)>>2)];
+      var typeArray = Array.prototype.slice.call(arguments, 2);
+
+      // If throwntype is a pointer, this means a pointer has been
+      // thrown. When a pointer is thrown, actually what's thrown
+      // is a pointer to the pointer. We'll dereference it.
+      if (throwntype != 0 && !___cxa_is_number_type(throwntype)) {
+        var throwntypeInfoAddr= HEAP32[((throwntype)>>2)] - 8;
+        var throwntypeInfo= HEAP32[((throwntypeInfoAddr)>>2)];
+        if (throwntypeInfo == 0)
+          thrown = HEAP32[((thrown)>>2)];
+      }
+      // The different catch blocks are denoted by different types.
+      // Due to inheritance, those types may not precisely match the
+      // type of the thrown object. Find one which matches, and
+      // return the type of the catch block which should be called.
+      for (var i = 0; i < typeArray.length; i++) {
+        if (___cxa_does_inherit(typeArray[i], throwntype, thrown))
+          return ((asm["setTempRet0"](typeArray[i]),thrown)|0);
+      }
+      // Shouldn't happen unless we have bogus data in typeArray
+      // or encounter a type for which emscripten doesn't have suitable
+      // typeinfo defined. Best-efforts match just in case.
+      return ((asm["setTempRet0"](throwntype),thrown)|0);
+    }function ___cxa_throw(ptr, type, destructor) {
+      if (!___cxa_throw.initialized) {
+        try {
+          HEAP32[((__ZTVN10__cxxabiv119__pointer_type_infoE)>>2)]=0; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        try {
+          HEAP32[((__ZTVN10__cxxabiv117__class_type_infoE)>>2)]=1; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        try {
+          HEAP32[((__ZTVN10__cxxabiv120__si_class_type_infoE)>>2)]=2; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        ___cxa_throw.initialized = true;
+      }
+      var header = ptr - ___cxa_exception_header_size;
+      HEAP32[((header)>>2)]=type;
+      HEAP32[(((header)+(4))>>2)]=destructor;
+      ___cxa_last_thrown_exception = ptr;
+      if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
+        __ZSt18uncaught_exceptionv.uncaught_exception = 1;
+      } else {
+        __ZSt18uncaught_exceptionv.uncaught_exception++;
+      }
+      throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+    }
+
+
+  Module["_memset"] = _memset;
+
+
+
+  function __exit(status) {
+      // void _exit(int status);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
+      Module['exit'](status);
+    }function _exit(status) {
+      __exit(status);
+    }function __ZSt9terminatev() {
+      _exit(-1234);
+    }
+
+  function _abort() {
+      Module['abort']();
+    }
+
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+  var _sinf=Math_sin;
+
+
+  var _sqrtf=Math_sqrt;
+
+  var _floorf=Math_floor;
+
+
+  function _fputs(s, stream) {
+      // int fputs(const char *restrict s, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
+      var fd = _fileno(stream);
+      return _write(fd, s, _strlen(s));
+    }
+
+  function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }function _puts(s) {
+      // int puts(const char *s);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html
+      // NOTE: puts() always writes an extra newline.
+      var stdout = HEAP32[((_stdout)>>2)];
+      var ret = _fputs(s, stdout);
+      if (ret < 0) {
+        return ret;
+      } else {
+        var newlineRet = _fputc(10, stdout);
+        return (newlineRet < 0) ? -1 : ret + 1;
+      }
+    }
+
+  function _clock() {
+      if (_clock.start === undefined) _clock.start = Date.now();
+      return Math.floor((Date.now() - _clock.start) * (1000000/1000));
+    }
+
+
+  var ___cxa_caught_exceptions=[];function ___cxa_begin_catch(ptr) {
+      __ZSt18uncaught_exceptionv.uncaught_exception--;
+      ___cxa_caught_exceptions.push(___cxa_last_thrown_exception);
+      return ptr;
+    }
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+  function __ZNSt9exceptionD2Ev() {}
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+    Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+    Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+    // just add the mouse delta to the current absolut mouse position
+    // FIXME: ideally this should be clamped against the canvas size and zero
+    Browser.mouseX += Browser.mouseMovementX;
+    Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+  function _emscripten_run_script(ptr) {
+      eval(Pointer_stringify(ptr));
+    }
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;function ___cxa_allocate_exception(size) {
+      var ptr = _malloc(size + ___cxa_exception_header_size);
+      return ptr + ___cxa_exception_header_size;
+    }
+
+  function _emscripten_cancel_main_loop() {
+      Browser.mainLoop.scheduler = null;
+      Browser.mainLoop.shouldPause = true;
+    }
+
+  var __ZTISt9exception=allocate([allocate([1,0,0,0,0,0,0], "i8", ALLOC_STATIC)+8, 0], "i32", ALLOC_STATIC);
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function invoke_iiii(index,a1,a2,a3) {
+  try {
+    return Module["dynCall_iiii"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viiiii(index,a1,a2,a3,a4,a5) {
+  try {
+    Module["dynCall_viiiii"](index,a1,a2,a3,a4,a5);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vi(index,a1) {
+  try {
+    Module["dynCall_vi"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vii(index,a1,a2) {
+  try {
+    Module["dynCall_vii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_ii(index,a1) {
+  try {
+    return Module["dynCall_ii"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viii(index,a1,a2,a3) {
+  try {
+    Module["dynCall_viii"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_v(index) {
+  try {
+    Module["dynCall_v"](index);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viid(index,a1,a2,a3) {
+  try {
+    Module["dynCall_viid"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6) {
+  try {
+    Module["dynCall_viiiiii"](index,a1,a2,a3,a4,a5,a6);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iii(index,a1,a2) {
+  try {
+    return Module["dynCall_iii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iiiiii(index,a1,a2,a3,a4,a5) {
+  try {
+    return Module["dynCall_iiiiii"](index,a1,a2,a3,a4,a5);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_viiii(index,a1,a2,a3,a4) {
+  try {
+    Module["dynCall_viiii"](index,a1,a2,a3,a4);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+  var __ZTISt9exception=env.__ZTISt9exception|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var invoke_iiii=env.invoke_iiii;
+  var invoke_viiiii=env.invoke_viiiii;
+  var invoke_vi=env.invoke_vi;
+  var invoke_vii=env.invoke_vii;
+  var invoke_ii=env.invoke_ii;
+  var invoke_viii=env.invoke_viii;
+  var invoke_v=env.invoke_v;
+  var invoke_viid=env.invoke_viid;
+  var invoke_viiiiii=env.invoke_viiiiii;
+  var invoke_iii=env.invoke_iii;
+  var invoke_iiiiii=env.invoke_iiiiii;
+  var invoke_viiii=env.invoke_viiii;
+  var ___cxa_throw=env.___cxa_throw;
+  var _emscripten_run_script=env._emscripten_run_script;
+  var _cosf=env._cosf;
+  var _send=env._send;
+  var __ZSt9terminatev=env.__ZSt9terminatev;
+  var __reallyNegative=env.__reallyNegative;
+  var ___cxa_is_number_type=env.___cxa_is_number_type;
+  var ___assert_fail=env.___assert_fail;
+  var ___cxa_allocate_exception=env.___cxa_allocate_exception;
+  var ___cxa_find_matching_catch=env.___cxa_find_matching_catch;
+  var _fflush=env._fflush;
+  var _pwrite=env._pwrite;
+  var ___setErrNo=env.___setErrNo;
+  var _sbrk=env._sbrk;
+  var ___cxa_begin_catch=env.___cxa_begin_catch;
+  var _sinf=env._sinf;
+  var _fileno=env._fileno;
+  var ___resumeException=env.___resumeException;
+  var __ZSt18uncaught_exceptionv=env.__ZSt18uncaught_exceptionv;
+  var _sysconf=env._sysconf;
+  var _clock=env._clock;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _puts=env._puts;
+  var _mkport=env._mkport;
+  var _floorf=env._floorf;
+  var _sqrtf=env._sqrtf;
+  var _write=env._write;
+  var _emscripten_set_main_loop=env._emscripten_set_main_loop;
+  var ___errno_location=env.___errno_location;
+  var __ZNSt9exceptionD2Ev=env.__ZNSt9exceptionD2Ev;
+  var _printf=env._printf;
+  var ___cxa_does_inherit=env.___cxa_does_inherit;
+  var __exit=env.__exit;
+  var _fputc=env._fputc;
+  var _abort=env._abort;
+  var _fwrite=env._fwrite;
+  var _time=env._time;
+  var _fprintf=env._fprintf;
+  var _emscripten_cancel_main_loop=env._emscripten_cancel_main_loop;
+  var __formatString=env.__formatString;
+  var _fputs=env._fputs;
+  var _exit=env._exit;
+  var ___cxa_pure_virtual=env.___cxa_pure_virtual;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[1790] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 7200 + (i5 << 2) | 0;
+    i5 = 7200 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[1790] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[7168 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 7200 + (i7 << 2) | 0;
+     i7 = 7200 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[1790] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[7168 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[7180 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 7200 + (i9 << 2) | 0;
+      i7 = HEAP32[1790] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 7200 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[1790] = i7 | i8;
+       i28 = 7200 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[7168 >> 2] = i4;
+     HEAP32[7180 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[7164 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[7464 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[7176 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 7464 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[7168 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[7180 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 7200 + (i9 << 2) | 0;
+       i7 = HEAP32[1790] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 7200 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[1790] = i7 | i8;
+        i25 = 7200 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[7168 >> 2] = i2;
+      HEAP32[7180 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[7164 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[7464 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[7464 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[7168 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[7176 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 7464 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 7200 + (i6 << 2) | 0;
+         i5 = HEAP32[1790] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 7200 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[1790] = i5 | i4;
+          i21 = 7200 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 7464 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[7164 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[7164 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[7176 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[7168 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[7180 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[7180 >> 2] = i2 + i12;
+   HEAP32[7168 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[7168 >> 2] = 0;
+   HEAP32[7180 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[7172 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[7172 >> 2] = i31;
+  i32 = HEAP32[7184 >> 2] | 0;
+  HEAP32[7184 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[1908] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[7640 >> 2] = i18;
+    HEAP32[7636 >> 2] = i18;
+    HEAP32[7644 >> 2] = -1;
+    HEAP32[7648 >> 2] = -1;
+    HEAP32[7652 >> 2] = 0;
+    HEAP32[7604 >> 2] = 0;
+    HEAP32[1908] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[7640 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[7600 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[7592 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[7604 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[7184 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 7608 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[7172 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[7636 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[7592 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[7600 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[7640 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[7604 >> 2] = HEAP32[7604 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[7592 >> 2] | 0) + i14 | 0;
+  HEAP32[7592 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[7596 >> 2] | 0) >>> 0) {
+   HEAP32[7596 >> 2] = i15;
+  }
+  i15 = HEAP32[7184 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 7608 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[7172 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[7184 >> 2] = i15 + i3;
+     HEAP32[7172 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[7188 >> 2] = HEAP32[7648 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+     HEAP32[7176 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 7608 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[7184 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[7180 >> 2] | 0)) {
+        i32 = (HEAP32[7168 >> 2] | 0) + i10 | 0;
+        HEAP32[7168 >> 2] = i32;
+        HEAP32[7180 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 7464 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 7200 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[1790] = HEAP32[1790] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 7200 + (i10 << 2) | 0;
+        i9 = HEAP32[1790] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 7200 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[1790] = i9 | i5;
+         i3 = 7200 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 7464 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[7164 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[7164 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[7176 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[7172 >> 2] | 0) + i10 | 0;
+       HEAP32[7172 >> 2] = i32;
+       HEAP32[7184 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 7608 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[7184 >> 2] = i17 + i4;
+    HEAP32[7172 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[7188 >> 2] = HEAP32[7648 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[7608 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[7612 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[7616 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[7620 >> 2];
+    HEAP32[7608 >> 2] = i17;
+    HEAP32[7612 >> 2] = i14;
+    HEAP32[7620 >> 2] = 0;
+    HEAP32[7616 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 7200 + (i4 << 2) | 0;
+      i5 = HEAP32[1790] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 7200 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[1790] = i5 | i3;
+       i7 = 7200 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 7464 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[7164 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[7164 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[7176 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[7176 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[7176 >> 2] = i17;
+    }
+    HEAP32[7608 >> 2] = i17;
+    HEAP32[7612 >> 2] = i14;
+    HEAP32[7620 >> 2] = 0;
+    HEAP32[7196 >> 2] = HEAP32[1908];
+    HEAP32[7192 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 7200 + (i32 << 2) | 0;
+     HEAP32[7200 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[7200 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[7184 >> 2] = i17 + i2;
+    HEAP32[7172 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[7188 >> 2] = HEAP32[7648 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[7172 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[7172 >> 2] = i31;
+   i32 = HEAP32[7184 >> 2] | 0;
+   HEAP32[7184 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function __ZN12b2EPCollider7CollideEP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS7_(i12, i2, i16, i5, i8, i6) {
+ i12 = i12 | 0;
+ i2 = i2 | 0;
+ i16 = i16 | 0;
+ i5 = i5 | 0;
+ i8 = i8 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, i29 = 0, d30 = 0.0, d31 = 0.0, d32 = 0.0, d33 = 0.0, i34 = 0, i35 = 0, d36 = 0.0, d37 = 0.0, i38 = 0, d39 = 0.0, i40 = 0, i41 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 144 | 0;
+ i18 = i1 + 128 | 0;
+ i11 = i1 + 24 | 0;
+ i9 = i1 + 72 | 0;
+ i10 = i1 + 48 | 0;
+ i3 = i1;
+ i4 = i12 + 132 | 0;
+ d28 = +HEAPF32[i5 + 12 >> 2];
+ d37 = +HEAPF32[i6 + 8 >> 2];
+ d23 = +HEAPF32[i5 + 8 >> 2];
+ d27 = +HEAPF32[i6 + 12 >> 2];
+ d22 = d28 * d37 - d23 * d27;
+ d27 = d37 * d23 + d28 * d27;
+ d37 = +d22;
+ d26 = +d27;
+ d25 = +HEAPF32[i6 >> 2] - +HEAPF32[i5 >> 2];
+ d36 = +HEAPF32[i6 + 4 >> 2] - +HEAPF32[i5 + 4 >> 2];
+ d24 = d28 * d25 + d23 * d36;
+ d25 = d28 * d36 - d23 * d25;
+ d23 = +d24;
+ d36 = +d25;
+ i5 = i4;
+ HEAPF32[i5 >> 2] = d23;
+ HEAPF32[i5 + 4 >> 2] = d36;
+ i5 = i12 + 140 | 0;
+ HEAPF32[i5 >> 2] = d37;
+ HEAPF32[i5 + 4 >> 2] = d26;
+ i5 = i12 + 144 | 0;
+ d26 = +HEAPF32[i8 + 12 >> 2];
+ i7 = i12 + 140 | 0;
+ d37 = +HEAPF32[i8 + 16 >> 2];
+ d24 = d24 + (d27 * d26 - d22 * d37);
+ i6 = i12 + 136 | 0;
+ d25 = d26 * d22 + d27 * d37 + d25;
+ d37 = +d24;
+ d27 = +d25;
+ i34 = i12 + 148 | 0;
+ HEAPF32[i34 >> 2] = d37;
+ HEAPF32[i34 + 4 >> 2] = d27;
+ i34 = i16 + 28 | 0;
+ i29 = HEAP32[i34 >> 2] | 0;
+ i34 = HEAP32[i34 + 4 >> 2] | 0;
+ i14 = i12 + 156 | 0;
+ HEAP32[i14 >> 2] = i29;
+ HEAP32[i14 + 4 >> 2] = i34;
+ i14 = i12 + 164 | 0;
+ i17 = i16 + 12 | 0;
+ i40 = HEAP32[i17 >> 2] | 0;
+ i17 = HEAP32[i17 + 4 >> 2] | 0;
+ i13 = i14;
+ HEAP32[i13 >> 2] = i40;
+ HEAP32[i13 + 4 >> 2] = i17;
+ i13 = i12 + 172 | 0;
+ i20 = i16 + 20 | 0;
+ i41 = HEAP32[i20 >> 2] | 0;
+ i20 = HEAP32[i20 + 4 >> 2] | 0;
+ i38 = i13;
+ HEAP32[i38 >> 2] = i41;
+ HEAP32[i38 + 4 >> 2] = i20;
+ i38 = i16 + 36 | 0;
+ i35 = HEAP32[i38 >> 2] | 0;
+ i38 = HEAP32[i38 + 4 >> 2] | 0;
+ i19 = i12 + 180 | 0;
+ HEAP32[i19 >> 2] = i35;
+ HEAP32[i19 + 4 >> 2] = i38;
+ i19 = (HEAP8[i16 + 44 | 0] | 0) != 0;
+ i21 = (HEAP8[i16 + 45 | 0] | 0) != 0;
+ d27 = (HEAP32[tempDoublePtr >> 2] = i41, +HEAPF32[tempDoublePtr >> 2]);
+ d37 = (HEAP32[tempDoublePtr >> 2] = i40, +HEAPF32[tempDoublePtr >> 2]);
+ d22 = d27 - d37;
+ d26 = (HEAP32[tempDoublePtr >> 2] = i20, +HEAPF32[tempDoublePtr >> 2]);
+ i20 = i12 + 168 | 0;
+ d36 = (HEAP32[tempDoublePtr >> 2] = i17, +HEAPF32[tempDoublePtr >> 2]);
+ d23 = d26 - d36;
+ d28 = +Math_sqrt(+(d22 * d22 + d23 * d23));
+ d33 = (HEAP32[tempDoublePtr >> 2] = i29, +HEAPF32[tempDoublePtr >> 2]);
+ d32 = (HEAP32[tempDoublePtr >> 2] = i34, +HEAPF32[tempDoublePtr >> 2]);
+ d31 = (HEAP32[tempDoublePtr >> 2] = i35, +HEAPF32[tempDoublePtr >> 2]);
+ d30 = (HEAP32[tempDoublePtr >> 2] = i38, +HEAPF32[tempDoublePtr >> 2]);
+ if (!(d28 < 1.1920928955078125e-7)) {
+  d39 = 1.0 / d28;
+  d22 = d22 * d39;
+  d23 = d23 * d39;
+ }
+ i16 = i12 + 196 | 0;
+ d28 = -d22;
+ HEAPF32[i16 >> 2] = d23;
+ i17 = i12 + 200 | 0;
+ HEAPF32[i17 >> 2] = d28;
+ d28 = (d24 - d37) * d23 + (d25 - d36) * d28;
+ if (i19) {
+  d37 = d37 - d33;
+  d36 = d36 - d32;
+  d39 = +Math_sqrt(+(d37 * d37 + d36 * d36));
+  if (!(d39 < 1.1920928955078125e-7)) {
+   d39 = 1.0 / d39;
+   d37 = d37 * d39;
+   d36 = d36 * d39;
+  }
+  d39 = -d37;
+  HEAPF32[i12 + 188 >> 2] = d36;
+  HEAPF32[i12 + 192 >> 2] = d39;
+  i29 = d23 * d37 - d22 * d36 >= 0.0;
+  d32 = (d24 - d33) * d36 + (d25 - d32) * d39;
+ } else {
+  i29 = 0;
+  d32 = 0.0;
+ }
+ L10 : do {
+  if (!i21) {
+   if (!i19) {
+    i41 = d28 >= 0.0;
+    HEAP8[i12 + 248 | 0] = i41 & 1;
+    i19 = i12 + 212 | 0;
+    if (i41) {
+     i15 = 64;
+     break;
+    } else {
+     i15 = 65;
+     break;
+    }
+   }
+   i19 = d32 >= 0.0;
+   if (i29) {
+    if (!i19) {
+     i41 = d28 >= 0.0;
+     HEAP8[i12 + 248 | 0] = i41 & 1;
+     i19 = i12 + 212 | 0;
+     if (!i41) {
+      d37 = +-d23;
+      d39 = +d22;
+      i38 = i19;
+      HEAPF32[i38 >> 2] = d37;
+      HEAPF32[i38 + 4 >> 2] = d39;
+      i38 = i16;
+      i40 = HEAP32[i38 >> 2] | 0;
+      i38 = HEAP32[i38 + 4 >> 2] | 0;
+      i41 = i12 + 228 | 0;
+      HEAP32[i41 >> 2] = i40;
+      HEAP32[i41 + 4 >> 2] = i38;
+      i41 = i12 + 236 | 0;
+      HEAPF32[i41 >> 2] = -(HEAP32[tempDoublePtr >> 2] = i40, +HEAPF32[tempDoublePtr >> 2]);
+      HEAPF32[i41 + 4 >> 2] = d39;
+      break;
+     }
+    } else {
+     HEAP8[i12 + 248 | 0] = 1;
+     i19 = i12 + 212 | 0;
+    }
+    i41 = i16;
+    i40 = HEAP32[i41 + 4 >> 2] | 0;
+    i38 = i19;
+    HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+    HEAP32[i38 + 4 >> 2] = i40;
+    i38 = i12 + 188 | 0;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i12 + 228 | 0;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    d37 = +-+HEAPF32[i16 >> 2];
+    d39 = +-+HEAPF32[i17 >> 2];
+    i41 = i12 + 236 | 0;
+    HEAPF32[i41 >> 2] = d37;
+    HEAPF32[i41 + 4 >> 2] = d39;
+    break;
+   } else {
+    if (i19) {
+     i41 = d28 >= 0.0;
+     HEAP8[i12 + 248 | 0] = i41 & 1;
+     i19 = i12 + 212 | 0;
+     if (i41) {
+      i38 = i16;
+      i41 = HEAP32[i38 >> 2] | 0;
+      i38 = HEAP32[i38 + 4 >> 2] | 0;
+      i40 = i19;
+      HEAP32[i40 >> 2] = i41;
+      HEAP32[i40 + 4 >> 2] = i38;
+      i40 = i12 + 228 | 0;
+      HEAP32[i40 >> 2] = i41;
+      HEAP32[i40 + 4 >> 2] = i38;
+      d37 = +-(HEAP32[tempDoublePtr >> 2] = i41, +HEAPF32[tempDoublePtr >> 2]);
+      d39 = +d22;
+      i41 = i12 + 236 | 0;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      break;
+     }
+    } else {
+     HEAP8[i12 + 248 | 0] = 0;
+     i19 = i12 + 212 | 0;
+    }
+    d39 = +-d23;
+    d37 = +d22;
+    i38 = i19;
+    HEAPF32[i38 >> 2] = d39;
+    HEAPF32[i38 + 4 >> 2] = d37;
+    i38 = i16;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i12 + 228 | 0;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    d37 = +-+HEAPF32[i12 + 188 >> 2];
+    d39 = +-+HEAPF32[i12 + 192 >> 2];
+    i41 = i12 + 236 | 0;
+    HEAPF32[i41 >> 2] = d37;
+    HEAPF32[i41 + 4 >> 2] = d39;
+    break;
+   }
+  } else {
+   d33 = d31 - d27;
+   d31 = d30 - d26;
+   d30 = +Math_sqrt(+(d33 * d33 + d31 * d31));
+   if (d30 < 1.1920928955078125e-7) {
+    d30 = d33;
+   } else {
+    d39 = 1.0 / d30;
+    d30 = d33 * d39;
+    d31 = d31 * d39;
+   }
+   d39 = -d30;
+   i34 = i12 + 204 | 0;
+   HEAPF32[i34 >> 2] = d31;
+   i35 = i12 + 208 | 0;
+   HEAPF32[i35 >> 2] = d39;
+   i38 = d22 * d31 - d23 * d30 > 0.0;
+   d24 = (d24 - d27) * d31 + (d25 - d26) * d39;
+   if (!i19) {
+    i19 = d28 >= 0.0;
+    if (!i21) {
+     HEAP8[i12 + 248 | 0] = i19 & 1;
+     i15 = i12 + 212 | 0;
+     if (i19) {
+      i19 = i15;
+      i15 = 64;
+      break;
+     } else {
+      i19 = i15;
+      i15 = 65;
+      break;
+     }
+    }
+    if (i38) {
+     if (!i19) {
+      i41 = d24 >= 0.0;
+      HEAP8[i12 + 248 | 0] = i41 & 1;
+      i19 = i12 + 212 | 0;
+      if (!i41) {
+       d37 = +-d23;
+       d39 = +d22;
+       i38 = i19;
+       HEAPF32[i38 >> 2] = d37;
+       HEAPF32[i38 + 4 >> 2] = d39;
+       i38 = i12 + 228 | 0;
+       HEAPF32[i38 >> 2] = d37;
+       HEAPF32[i38 + 4 >> 2] = d39;
+       i38 = i16;
+       i40 = HEAP32[i38 + 4 >> 2] | 0;
+       i41 = i12 + 236 | 0;
+       HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+       HEAP32[i41 + 4 >> 2] = i40;
+       break;
+      }
+     } else {
+      HEAP8[i12 + 248 | 0] = 1;
+      i19 = i12 + 212 | 0;
+     }
+     i41 = i16;
+     i40 = HEAP32[i41 + 4 >> 2] | 0;
+     i38 = i19;
+     HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+     HEAP32[i38 + 4 >> 2] = i40;
+     d37 = +-+HEAPF32[i16 >> 2];
+     d39 = +-+HEAPF32[i17 >> 2];
+     i38 = i12 + 228 | 0;
+     HEAPF32[i38 >> 2] = d37;
+     HEAPF32[i38 + 4 >> 2] = d39;
+     i38 = i12 + 204 | 0;
+     i40 = HEAP32[i38 + 4 >> 2] | 0;
+     i41 = i12 + 236 | 0;
+     HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+     HEAP32[i41 + 4 >> 2] = i40;
+     break;
+    } else {
+     if (i19) {
+      i41 = d24 >= 0.0;
+      HEAP8[i12 + 248 | 0] = i41 & 1;
+      i19 = i12 + 212 | 0;
+      if (i41) {
+       i40 = i16;
+       i38 = HEAP32[i40 >> 2] | 0;
+       i40 = HEAP32[i40 + 4 >> 2] | 0;
+       i41 = i19;
+       HEAP32[i41 >> 2] = i38;
+       HEAP32[i41 + 4 >> 2] = i40;
+       d37 = +-(HEAP32[tempDoublePtr >> 2] = i38, +HEAPF32[tempDoublePtr >> 2]);
+       d39 = +d22;
+       i41 = i12 + 228 | 0;
+       HEAPF32[i41 >> 2] = d37;
+       HEAPF32[i41 + 4 >> 2] = d39;
+       i41 = i12 + 236 | 0;
+       HEAP32[i41 >> 2] = i38;
+       HEAP32[i41 + 4 >> 2] = i40;
+       break;
+      }
+     } else {
+      HEAP8[i12 + 248 | 0] = 0;
+      i19 = i12 + 212 | 0;
+     }
+     d39 = +-d23;
+     d37 = +d22;
+     i38 = i19;
+     HEAPF32[i38 >> 2] = d39;
+     HEAPF32[i38 + 4 >> 2] = d37;
+     d37 = +-+HEAPF32[i12 + 204 >> 2];
+     d39 = +-+HEAPF32[i12 + 208 >> 2];
+     i38 = i12 + 228 | 0;
+     HEAPF32[i38 >> 2] = d37;
+     HEAPF32[i38 + 4 >> 2] = d39;
+     i38 = i16;
+     i40 = HEAP32[i38 + 4 >> 2] | 0;
+     i41 = i12 + 236 | 0;
+     HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+     HEAP32[i41 + 4 >> 2] = i40;
+     break;
+    }
+   }
+   if (i29 & i38) {
+    if (!(d32 >= 0.0) & !(d28 >= 0.0)) {
+     i41 = d24 >= 0.0;
+     HEAP8[i12 + 248 | 0] = i41 & 1;
+     i19 = i12 + 212 | 0;
+     if (!i41) {
+      d37 = +-d23;
+      d39 = +d22;
+      i41 = i19;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      i41 = i12 + 228 | 0;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      i41 = i12 + 236 | 0;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      break;
+     }
+    } else {
+     HEAP8[i12 + 248 | 0] = 1;
+     i19 = i12 + 212 | 0;
+    }
+    i38 = i16;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i19;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    i41 = i12 + 188 | 0;
+    i40 = HEAP32[i41 + 4 >> 2] | 0;
+    i38 = i12 + 228 | 0;
+    HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+    HEAP32[i38 + 4 >> 2] = i40;
+    i38 = i12 + 204 | 0;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i12 + 236 | 0;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    break;
+   }
+   if (i29) {
+    do {
+     if (!(d32 >= 0.0)) {
+      if (d28 >= 0.0) {
+       i41 = d24 >= 0.0;
+       HEAP8[i12 + 248 | 0] = i41 & 1;
+       i19 = i12 + 212 | 0;
+       if (i41) {
+        break;
+       }
+      } else {
+       HEAP8[i12 + 248 | 0] = 0;
+       i19 = i12 + 212 | 0;
+      }
+      d37 = +-d23;
+      d39 = +d22;
+      i41 = i19;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      d39 = +-+HEAPF32[i34 >> 2];
+      d37 = +-+HEAPF32[i35 >> 2];
+      i41 = i12 + 228 | 0;
+      HEAPF32[i41 >> 2] = d39;
+      HEAPF32[i41 + 4 >> 2] = d37;
+      d37 = +-+HEAPF32[i16 >> 2];
+      d39 = +-+HEAPF32[i17 >> 2];
+      i41 = i12 + 236 | 0;
+      HEAPF32[i41 >> 2] = d37;
+      HEAPF32[i41 + 4 >> 2] = d39;
+      break L10;
+     } else {
+      HEAP8[i12 + 248 | 0] = 1;
+      i19 = i12 + 212 | 0;
+     }
+    } while (0);
+    i38 = i16;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i19;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    i41 = i12 + 188 | 0;
+    i40 = HEAP32[i41 + 4 >> 2] | 0;
+    i38 = i12 + 228 | 0;
+    HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+    HEAP32[i38 + 4 >> 2] = i40;
+    i38 = i16;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i41 = i12 + 236 | 0;
+    HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i41 + 4 >> 2] = i40;
+    break;
+   }
+   if (!i38) {
+    if (!(!(d32 >= 0.0) | !(d28 >= 0.0))) {
+     i41 = d24 >= 0.0;
+     HEAP8[i12 + 248 | 0] = i41 & 1;
+     i19 = i12 + 212 | 0;
+     if (i41) {
+      i40 = i16;
+      i38 = HEAP32[i40 >> 2] | 0;
+      i40 = HEAP32[i40 + 4 >> 2] | 0;
+      i41 = i19;
+      HEAP32[i41 >> 2] = i38;
+      HEAP32[i41 + 4 >> 2] = i40;
+      i41 = i12 + 228 | 0;
+      HEAP32[i41 >> 2] = i38;
+      HEAP32[i41 + 4 >> 2] = i40;
+      i41 = i12 + 236 | 0;
+      HEAP32[i41 >> 2] = i38;
+      HEAP32[i41 + 4 >> 2] = i40;
+      break;
+     }
+    } else {
+     HEAP8[i12 + 248 | 0] = 0;
+     i19 = i12 + 212 | 0;
+    }
+    d37 = +-d23;
+    d39 = +d22;
+    i41 = i19;
+    HEAPF32[i41 >> 2] = d37;
+    HEAPF32[i41 + 4 >> 2] = d39;
+    d39 = +-+HEAPF32[i34 >> 2];
+    d37 = +-+HEAPF32[i35 >> 2];
+    i41 = i12 + 228 | 0;
+    HEAPF32[i41 >> 2] = d39;
+    HEAPF32[i41 + 4 >> 2] = d37;
+    d37 = +-+HEAPF32[i12 + 188 >> 2];
+    d39 = +-+HEAPF32[i12 + 192 >> 2];
+    i41 = i12 + 236 | 0;
+    HEAPF32[i41 >> 2] = d37;
+    HEAPF32[i41 + 4 >> 2] = d39;
+    break;
+   }
+   do {
+    if (!(d24 >= 0.0)) {
+     if (d32 >= 0.0) {
+      i41 = d28 >= 0.0;
+      HEAP8[i12 + 248 | 0] = i41 & 1;
+      i19 = i12 + 212 | 0;
+      if (i41) {
+       break;
+      }
+     } else {
+      HEAP8[i12 + 248 | 0] = 0;
+      i19 = i12 + 212 | 0;
+     }
+     d37 = +-d23;
+     d39 = +d22;
+     i41 = i19;
+     HEAPF32[i41 >> 2] = d37;
+     HEAPF32[i41 + 4 >> 2] = d39;
+     d39 = +-+HEAPF32[i16 >> 2];
+     d37 = +-+HEAPF32[i17 >> 2];
+     i41 = i12 + 228 | 0;
+     HEAPF32[i41 >> 2] = d39;
+     HEAPF32[i41 + 4 >> 2] = d37;
+     d37 = +-+HEAPF32[i12 + 188 >> 2];
+     d39 = +-+HEAPF32[i12 + 192 >> 2];
+     i41 = i12 + 236 | 0;
+     HEAPF32[i41 >> 2] = d37;
+     HEAPF32[i41 + 4 >> 2] = d39;
+     break L10;
+    } else {
+     HEAP8[i12 + 248 | 0] = 1;
+     i19 = i12 + 212 | 0;
+    }
+   } while (0);
+   i38 = i16;
+   i40 = HEAP32[i38 + 4 >> 2] | 0;
+   i41 = i19;
+   HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+   HEAP32[i41 + 4 >> 2] = i40;
+   i41 = i16;
+   i40 = HEAP32[i41 + 4 >> 2] | 0;
+   i38 = i12 + 228 | 0;
+   HEAP32[i38 >> 2] = HEAP32[i41 >> 2];
+   HEAP32[i38 + 4 >> 2] = i40;
+   i38 = i12 + 204 | 0;
+   i40 = HEAP32[i38 + 4 >> 2] | 0;
+   i41 = i12 + 236 | 0;
+   HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+   HEAP32[i41 + 4 >> 2] = i40;
+  }
+ } while (0);
+ if ((i15 | 0) == 64) {
+  i38 = i16;
+  i41 = HEAP32[i38 >> 2] | 0;
+  i38 = HEAP32[i38 + 4 >> 2] | 0;
+  i40 = i19;
+  HEAP32[i40 >> 2] = i41;
+  HEAP32[i40 + 4 >> 2] = i38;
+  d37 = +-(HEAP32[tempDoublePtr >> 2] = i41, +HEAPF32[tempDoublePtr >> 2]);
+  d39 = +d22;
+  i41 = i12 + 228 | 0;
+  HEAPF32[i41 >> 2] = d37;
+  HEAPF32[i41 + 4 >> 2] = d39;
+  i41 = i12 + 236 | 0;
+  HEAPF32[i41 >> 2] = d37;
+  HEAPF32[i41 + 4 >> 2] = d39;
+ } else if ((i15 | 0) == 65) {
+  d37 = +-d23;
+  d39 = +d22;
+  i40 = i19;
+  HEAPF32[i40 >> 2] = d37;
+  HEAPF32[i40 + 4 >> 2] = d39;
+  i40 = i16;
+  i38 = HEAP32[i40 >> 2] | 0;
+  i40 = HEAP32[i40 + 4 >> 2] | 0;
+  i41 = i12 + 228 | 0;
+  HEAP32[i41 >> 2] = i38;
+  HEAP32[i41 + 4 >> 2] = i40;
+  i41 = i12 + 236 | 0;
+  HEAP32[i41 >> 2] = i38;
+  HEAP32[i41 + 4 >> 2] = i40;
+ }
+ i21 = i8 + 148 | 0;
+ i34 = i12 + 128 | 0;
+ HEAP32[i34 >> 2] = HEAP32[i21 >> 2];
+ if ((HEAP32[i21 >> 2] | 0) > 0) {
+  i19 = 0;
+  do {
+   d33 = +HEAPF32[i5 >> 2];
+   d37 = +HEAPF32[i8 + (i19 << 3) + 20 >> 2];
+   d39 = +HEAPF32[i7 >> 2];
+   d36 = +HEAPF32[i8 + (i19 << 3) + 24 >> 2];
+   d32 = +(+HEAPF32[i4 >> 2] + (d33 * d37 - d39 * d36));
+   d36 = +(d37 * d39 + d33 * d36 + +HEAPF32[i6 >> 2]);
+   i41 = i12 + (i19 << 3) | 0;
+   HEAPF32[i41 >> 2] = d32;
+   HEAPF32[i41 + 4 >> 2] = d36;
+   d36 = +HEAPF32[i5 >> 2];
+   d32 = +HEAPF32[i8 + (i19 << 3) + 84 >> 2];
+   d33 = +HEAPF32[i7 >> 2];
+   d39 = +HEAPF32[i8 + (i19 << 3) + 88 >> 2];
+   d37 = +(d36 * d32 - d33 * d39);
+   d39 = +(d32 * d33 + d36 * d39);
+   i41 = i12 + (i19 << 3) + 64 | 0;
+   HEAPF32[i41 >> 2] = d37;
+   HEAPF32[i41 + 4 >> 2] = d39;
+   i19 = i19 + 1 | 0;
+  } while ((i19 | 0) < (HEAP32[i21 >> 2] | 0));
+ }
+ i21 = i12 + 244 | 0;
+ HEAPF32[i21 >> 2] = .019999999552965164;
+ i19 = i2 + 60 | 0;
+ HEAP32[i19 >> 2] = 0;
+ i29 = i12 + 248 | 0;
+ i35 = HEAP32[i34 >> 2] | 0;
+ if ((i35 | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ d23 = +HEAPF32[i12 + 164 >> 2];
+ d26 = +HEAPF32[i20 >> 2];
+ d24 = +HEAPF32[i12 + 212 >> 2];
+ d27 = +HEAPF32[i12 + 216 >> 2];
+ d22 = 3.4028234663852886e+38;
+ i20 = 0;
+ do {
+  d25 = d24 * (+HEAPF32[i12 + (i20 << 3) >> 2] - d23) + d27 * (+HEAPF32[i12 + (i20 << 3) + 4 >> 2] - d26);
+  d22 = d25 < d22 ? d25 : d22;
+  i20 = i20 + 1 | 0;
+ } while ((i20 | 0) != (i35 | 0));
+ if (d22 > .019999999552965164) {
+  STACKTOP = i1;
+  return;
+ }
+ __ZN12b2EPCollider24ComputePolygonSeparationEv(i18, i12);
+ i20 = HEAP32[i18 >> 2] | 0;
+ if ((i20 | 0) != 0) {
+  d23 = +HEAPF32[i18 + 8 >> 2];
+  if (d23 > +HEAPF32[i21 >> 2]) {
+   STACKTOP = i1;
+   return;
+  }
+  if (d23 > d22 * .9800000190734863 + .0010000000474974513) {
+   i18 = HEAP32[i18 + 4 >> 2] | 0;
+   i35 = i2 + 56 | 0;
+   if ((i20 | 0) == 1) {
+    i18 = i11;
+    i15 = 77;
+   } else {
+    HEAP32[i35 >> 2] = 2;
+    i40 = i14;
+    i41 = HEAP32[i40 + 4 >> 2] | 0;
+    i38 = i11;
+    HEAP32[i38 >> 2] = HEAP32[i40 >> 2];
+    HEAP32[i38 + 4 >> 2] = i41;
+    i38 = i11 + 8 | 0;
+    HEAP8[i38] = 0;
+    i41 = i18 & 255;
+    HEAP8[i38 + 1 | 0] = i41;
+    HEAP8[i38 + 2 | 0] = 0;
+    HEAP8[i38 + 3 | 0] = 1;
+    i38 = i13;
+    i40 = HEAP32[i38 + 4 >> 2] | 0;
+    i13 = i11 + 12 | 0;
+    HEAP32[i13 >> 2] = HEAP32[i38 >> 2];
+    HEAP32[i13 + 4 >> 2] = i40;
+    i13 = i11 + 20 | 0;
+    HEAP8[i13] = 0;
+    HEAP8[i13 + 1 | 0] = i41;
+    HEAP8[i13 + 2 | 0] = 0;
+    HEAP8[i13 + 3 | 0] = 1;
+    HEAP32[i9 >> 2] = i18;
+    i13 = i18 + 1 | 0;
+    i16 = (i13 | 0) < (HEAP32[i34 >> 2] | 0) ? i13 : 0;
+    HEAP32[i9 + 4 >> 2] = i16;
+    i17 = i12 + (i18 << 3) | 0;
+    i13 = HEAP32[i17 >> 2] | 0;
+    i17 = HEAP32[i17 + 4 >> 2] | 0;
+    i29 = i9 + 8 | 0;
+    HEAP32[i29 >> 2] = i13;
+    HEAP32[i29 + 4 >> 2] = i17;
+    i16 = i12 + (i16 << 3) | 0;
+    i29 = HEAP32[i16 >> 2] | 0;
+    i16 = HEAP32[i16 + 4 >> 2] | 0;
+    i20 = i9 + 16 | 0;
+    HEAP32[i20 >> 2] = i29;
+    HEAP32[i20 + 4 >> 2] = i16;
+    i20 = i12 + (i18 << 3) + 64 | 0;
+    i12 = HEAP32[i20 >> 2] | 0;
+    i20 = HEAP32[i20 + 4 >> 2] | 0;
+    i14 = i9 + 24 | 0;
+    HEAP32[i14 >> 2] = i12;
+    HEAP32[i14 + 4 >> 2] = i20;
+    i14 = 0;
+   }
+  } else {
+   i15 = 75;
+  }
+ } else {
+  i15 = 75;
+ }
+ if ((i15 | 0) == 75) {
+  i18 = i11;
+  i35 = i2 + 56 | 0;
+  i15 = 77;
+ }
+ do {
+  if ((i15 | 0) == 77) {
+   HEAP32[i35 >> 2] = 1;
+   i15 = HEAP32[i34 >> 2] | 0;
+   if ((i15 | 0) > 1) {
+    d23 = +HEAPF32[i12 + 216 >> 2];
+    d22 = +HEAPF32[i12 + 212 >> 2];
+    i34 = 0;
+    d24 = d22 * +HEAPF32[i12 + 64 >> 2] + d23 * +HEAPF32[i12 + 68 >> 2];
+    i35 = 1;
+    while (1) {
+     d25 = d22 * +HEAPF32[i12 + (i35 << 3) + 64 >> 2] + d23 * +HEAPF32[i12 + (i35 << 3) + 68 >> 2];
+     i20 = d25 < d24;
+     i34 = i20 ? i35 : i34;
+     i35 = i35 + 1 | 0;
+     if ((i35 | 0) < (i15 | 0)) {
+      d24 = i20 ? d25 : d24;
+     } else {
+      break;
+     }
+    }
+   } else {
+    i34 = 0;
+   }
+   i20 = i34 + 1 | 0;
+   i40 = (i20 | 0) < (i15 | 0) ? i20 : 0;
+   i41 = i12 + (i34 << 3) | 0;
+   i38 = HEAP32[i41 + 4 >> 2] | 0;
+   i35 = i11;
+   HEAP32[i35 >> 2] = HEAP32[i41 >> 2];
+   HEAP32[i35 + 4 >> 2] = i38;
+   i35 = i11 + 8 | 0;
+   HEAP8[i35] = 0;
+   HEAP8[i35 + 1 | 0] = i34;
+   HEAP8[i35 + 2 | 0] = 1;
+   HEAP8[i35 + 3 | 0] = 0;
+   i35 = i12 + (i40 << 3) | 0;
+   i38 = HEAP32[i35 + 4 >> 2] | 0;
+   i41 = i11 + 12 | 0;
+   HEAP32[i41 >> 2] = HEAP32[i35 >> 2];
+   HEAP32[i41 + 4 >> 2] = i38;
+   i41 = i11 + 20 | 0;
+   HEAP8[i41] = 0;
+   HEAP8[i41 + 1 | 0] = i40;
+   HEAP8[i41 + 2 | 0] = 1;
+   HEAP8[i41 + 3 | 0] = 0;
+   if ((HEAP8[i29] | 0) == 0) {
+    HEAP32[i9 >> 2] = 1;
+    HEAP32[i9 + 4 >> 2] = 0;
+    i11 = i13;
+    i13 = HEAP32[i11 >> 2] | 0;
+    i11 = HEAP32[i11 + 4 >> 2] | 0;
+    i29 = i9 + 8 | 0;
+    HEAP32[i29 >> 2] = i13;
+    HEAP32[i29 + 4 >> 2] = i11;
+    i29 = HEAP32[i14 >> 2] | 0;
+    i14 = HEAP32[i14 + 4 >> 2] | 0;
+    i12 = i9 + 16 | 0;
+    HEAP32[i12 >> 2] = i29;
+    HEAP32[i12 + 4 >> 2] = i14;
+    i12 = (HEAPF32[tempDoublePtr >> 2] = -+HEAPF32[i16 >> 2], HEAP32[tempDoublePtr >> 2] | 0);
+    i20 = (HEAPF32[tempDoublePtr >> 2] = -+HEAPF32[i17 >> 2], HEAP32[tempDoublePtr >> 2] | 0);
+    i16 = i9 + 24 | 0;
+    HEAP32[i16 >> 2] = i12;
+    HEAP32[i16 + 4 >> 2] = i20;
+    i16 = i14;
+    i17 = i11;
+    i11 = i18;
+    i18 = 1;
+    i14 = 1;
+    break;
+   } else {
+    HEAP32[i9 >> 2] = 0;
+    HEAP32[i9 + 4 >> 2] = 1;
+    i17 = i14;
+    i11 = HEAP32[i17 >> 2] | 0;
+    i17 = HEAP32[i17 + 4 >> 2] | 0;
+    i29 = i9 + 8 | 0;
+    HEAP32[i29 >> 2] = i11;
+    HEAP32[i29 + 4 >> 2] = i17;
+    i29 = HEAP32[i13 >> 2] | 0;
+    i13 = HEAP32[i13 + 4 >> 2] | 0;
+    i20 = i9 + 16 | 0;
+    HEAP32[i20 >> 2] = i29;
+    HEAP32[i20 + 4 >> 2] = i13;
+    i20 = i16;
+    i12 = HEAP32[i20 >> 2] | 0;
+    i20 = HEAP32[i20 + 4 >> 2] | 0;
+    i16 = i9 + 24 | 0;
+    HEAP32[i16 >> 2] = i12;
+    HEAP32[i16 + 4 >> 2] = i20;
+    i16 = i13;
+    i13 = i11;
+    i11 = i18;
+    i18 = 0;
+    i14 = 1;
+    break;
+   }
+  }
+ } while (0);
+ d30 = (HEAP32[tempDoublePtr >> 2] = i20, +HEAPF32[tempDoublePtr >> 2]);
+ d39 = (HEAP32[tempDoublePtr >> 2] = i12, +HEAPF32[tempDoublePtr >> 2]);
+ d31 = (HEAP32[tempDoublePtr >> 2] = i13, +HEAPF32[tempDoublePtr >> 2]);
+ d32 = (HEAP32[tempDoublePtr >> 2] = i17, +HEAPF32[tempDoublePtr >> 2]);
+ d33 = (HEAP32[tempDoublePtr >> 2] = i29, +HEAPF32[tempDoublePtr >> 2]);
+ d37 = (HEAP32[tempDoublePtr >> 2] = i16, +HEAPF32[tempDoublePtr >> 2]);
+ i41 = i9 + 32 | 0;
+ i16 = i9 + 24 | 0;
+ i13 = i9 + 28 | 0;
+ d39 = -d39;
+ HEAPF32[i41 >> 2] = d30;
+ HEAPF32[i9 + 36 >> 2] = d39;
+ i20 = i9 + 44 | 0;
+ d36 = -d30;
+ i17 = i20;
+ HEAPF32[i17 >> 2] = d36;
+ HEAP32[i17 + 4 >> 2] = i12;
+ i17 = i9 + 8 | 0;
+ i15 = i9 + 12 | 0;
+ d39 = d30 * d31 + d32 * d39;
+ HEAPF32[i9 + 40 >> 2] = d39;
+ i29 = i9 + 52 | 0;
+ HEAPF32[i29 >> 2] = d33 * d36 + (HEAP32[tempDoublePtr >> 2] = i12, +HEAPF32[tempDoublePtr >> 2]) * d37;
+ if ((__Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i10, i11, i41, d39, i18) | 0) < 2) {
+  STACKTOP = i1;
+  return;
+ }
+ if ((__Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i3, i10, i20, +HEAPF32[i29 >> 2], HEAP32[i9 + 4 >> 2] | 0) | 0) < 2) {
+  STACKTOP = i1;
+  return;
+ }
+ i10 = i2 + 40 | 0;
+ if (i14) {
+  i40 = i16;
+  i41 = HEAP32[i40 >> 2] | 0;
+  i40 = HEAP32[i40 + 4 >> 2] | 0;
+  i35 = i10;
+  HEAP32[i35 >> 2] = i41;
+  HEAP32[i35 + 4 >> 2] = i40;
+  i35 = i17;
+  i40 = HEAP32[i35 >> 2] | 0;
+  i35 = HEAP32[i35 + 4 >> 2] | 0;
+  i38 = i2 + 48 | 0;
+  HEAP32[i38 >> 2] = i40;
+  HEAP32[i38 + 4 >> 2] = i35;
+  d23 = (HEAP32[tempDoublePtr >> 2] = i40, +HEAPF32[tempDoublePtr >> 2]);
+  d22 = (HEAP32[tempDoublePtr >> 2] = i41, +HEAPF32[tempDoublePtr >> 2]);
+  d24 = +HEAPF32[i15 >> 2];
+  d25 = +HEAPF32[i13 >> 2];
+  d28 = +HEAPF32[i3 >> 2];
+  d27 = +HEAPF32[i3 + 4 >> 2];
+  d26 = +HEAPF32[i21 >> 2];
+  if (!((d28 - d23) * d22 + (d27 - d24) * d25 <= d26)) {
+   d28 = d26;
+   i8 = 0;
+  } else {
+   d37 = d28 - +HEAPF32[i4 >> 2];
+   d36 = d27 - +HEAPF32[i6 >> 2];
+   d33 = +HEAPF32[i5 >> 2];
+   d28 = +HEAPF32[i7 >> 2];
+   d39 = +(d37 * d33 + d36 * d28);
+   d28 = +(d33 * d36 - d37 * d28);
+   i8 = i2;
+   HEAPF32[i8 >> 2] = d39;
+   HEAPF32[i8 + 4 >> 2] = d28;
+   HEAP32[i2 + 16 >> 2] = HEAP32[i3 + 8 >> 2];
+   d28 = +HEAPF32[i21 >> 2];
+   i8 = 1;
+  }
+  d26 = +HEAPF32[i3 + 12 >> 2];
+  d27 = +HEAPF32[i3 + 16 >> 2];
+  if ((d26 - d23) * d22 + (d27 - d24) * d25 <= d28) {
+   d36 = d26 - +HEAPF32[i4 >> 2];
+   d33 = d27 - +HEAPF32[i6 >> 2];
+   d32 = +HEAPF32[i5 >> 2];
+   d39 = +HEAPF32[i7 >> 2];
+   d37 = +(d36 * d32 + d33 * d39);
+   d39 = +(d32 * d33 - d36 * d39);
+   i41 = i2 + (i8 * 20 | 0) | 0;
+   HEAPF32[i41 >> 2] = d37;
+   HEAPF32[i41 + 4 >> 2] = d39;
+   HEAP32[i2 + (i8 * 20 | 0) + 16 >> 2] = HEAP32[i3 + 20 >> 2];
+   i8 = i8 + 1 | 0;
+  }
+ } else {
+  i38 = HEAP32[i9 >> 2] | 0;
+  i35 = i8 + (i38 << 3) + 84 | 0;
+  i41 = HEAP32[i35 + 4 >> 2] | 0;
+  i40 = i10;
+  HEAP32[i40 >> 2] = HEAP32[i35 >> 2];
+  HEAP32[i40 + 4 >> 2] = i41;
+  i38 = i8 + (i38 << 3) + 20 | 0;
+  i40 = HEAP32[i38 + 4 >> 2] | 0;
+  i41 = i2 + 48 | 0;
+  HEAP32[i41 >> 2] = HEAP32[i38 >> 2];
+  HEAP32[i41 + 4 >> 2] = i40;
+  d22 = +HEAPF32[i17 >> 2];
+  d23 = +HEAPF32[i16 >> 2];
+  d24 = +HEAPF32[i15 >> 2];
+  d25 = +HEAPF32[i13 >> 2];
+  d26 = +HEAPF32[i21 >> 2];
+  if (!((+HEAPF32[i3 >> 2] - d22) * d23 + (+HEAPF32[i3 + 4 >> 2] - d24) * d25 <= d26)) {
+   i8 = 0;
+  } else {
+   i40 = i3;
+   i8 = HEAP32[i40 + 4 >> 2] | 0;
+   i41 = i2;
+   HEAP32[i41 >> 2] = HEAP32[i40 >> 2];
+   HEAP32[i41 + 4 >> 2] = i8;
+   i41 = i3 + 8 | 0;
+   i8 = i2 + 16 | 0;
+   HEAP8[i8 + 2 | 0] = HEAP8[i41 + 3 | 0] | 0;
+   HEAP8[i8 + 3 | 0] = HEAP8[i41 + 2 | 0] | 0;
+   HEAP8[i8] = HEAP8[i41 + 1 | 0] | 0;
+   HEAP8[i8 + 1 | 0] = HEAP8[i41] | 0;
+   d26 = +HEAPF32[i21 >> 2];
+   i8 = 1;
+  }
+  i4 = i3 + 12 | 0;
+  if ((+HEAPF32[i4 >> 2] - d22) * d23 + (+HEAPF32[i3 + 16 >> 2] - d24) * d25 <= d26) {
+   i38 = i4;
+   i41 = HEAP32[i38 + 4 >> 2] | 0;
+   i40 = i2 + (i8 * 20 | 0) | 0;
+   HEAP32[i40 >> 2] = HEAP32[i38 >> 2];
+   HEAP32[i40 + 4 >> 2] = i41;
+   i40 = i3 + 20 | 0;
+   i41 = i2 + (i8 * 20 | 0) + 16 | 0;
+   HEAP8[i41 + 2 | 0] = HEAP8[i40 + 3 | 0] | 0;
+   HEAP8[i41 + 3 | 0] = HEAP8[i40 + 2 | 0] | 0;
+   HEAP8[i41] = HEAP8[i40 + 1 | 0] | 0;
+   HEAP8[i41 + 1 | 0] = HEAP8[i40] | 0;
+   i8 = i8 + 1 | 0;
+  }
+ }
+ HEAP32[i19 >> 2] = i8;
+ STACKTOP = i1;
+ return;
+}
+function __ZN7b2World8SolveTOIERK10b2TimeStep(i30, i11) {
+ i30 = i30 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, i39 = 0, i40 = 0, i41 = 0, d42 = 0.0, i43 = 0, i44 = 0, i45 = 0, i46 = 0, i47 = 0, i48 = 0, i49 = 0, i50 = 0, i51 = 0, i52 = 0, i53 = 0, i54 = 0, i55 = 0, i56 = 0, i57 = 0, i58 = 0, i59 = 0, i60 = 0, i61 = 0, i62 = 0, i63 = 0, i64 = 0, i65 = 0, i66 = 0, d67 = 0.0, d68 = 0.0, d69 = 0.0, d70 = 0.0, d71 = 0.0, d72 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 336 | 0;
+ i3 = i1 + 284 | 0;
+ i6 = i1 + 152 | 0;
+ i5 = i1 + 144 | 0;
+ i4 = i1 + 108 | 0;
+ i8 = i1 + 72 | 0;
+ i7 = i1 + 64 | 0;
+ i14 = i1 + 24 | 0;
+ i9 = i1;
+ i10 = i30 + 102872 | 0;
+ i13 = i30 + 102944 | 0;
+ __ZN8b2IslandC2EiiiP16b2StackAllocatorP17b2ContactListener(i3, 64, 32, 0, i30 + 68 | 0, HEAP32[i13 >> 2] | 0);
+ i2 = i30 + 102995 | 0;
+ if ((HEAP8[i2] | 0) != 0) {
+  i15 = HEAP32[i30 + 102952 >> 2] | 0;
+  if ((i15 | 0) != 0) {
+   do {
+    i66 = i15 + 4 | 0;
+    HEAP16[i66 >> 1] = HEAP16[i66 >> 1] & 65534;
+    HEAPF32[i15 + 60 >> 2] = 0.0;
+    i15 = HEAP32[i15 + 96 >> 2] | 0;
+   } while ((i15 | 0) != 0);
+  }
+  i15 = i30 + 102932 | 0;
+  i16 = HEAP32[i15 >> 2] | 0;
+  if ((i16 | 0) != 0) {
+   do {
+    i66 = i16 + 4 | 0;
+    HEAP32[i66 >> 2] = HEAP32[i66 >> 2] & -34;
+    HEAP32[i16 + 128 >> 2] = 0;
+    HEAPF32[i16 + 132 >> 2] = 1.0;
+    i16 = HEAP32[i16 + 12 >> 2] | 0;
+   } while ((i16 | 0) != 0);
+  }
+ } else {
+  i15 = i30 + 102932 | 0;
+ }
+ i25 = i3 + 28 | 0;
+ i26 = i3 + 36 | 0;
+ i27 = i3 + 32 | 0;
+ i28 = i3 + 40 | 0;
+ i29 = i3 + 8 | 0;
+ i24 = i3 + 44 | 0;
+ i23 = i3 + 12 | 0;
+ i22 = i7 + 4 | 0;
+ i21 = i9 + 4 | 0;
+ i20 = i9 + 8 | 0;
+ i19 = i9 + 16 | 0;
+ i18 = i11 + 12 | 0;
+ i17 = i9 + 12 | 0;
+ i16 = i9 + 20 | 0;
+ i39 = i30 + 102994 | 0;
+ i37 = i6 + 16 | 0;
+ i36 = i6 + 20 | 0;
+ i35 = i6 + 24 | 0;
+ i34 = i6 + 44 | 0;
+ i33 = i6 + 48 | 0;
+ i32 = i6 + 52 | 0;
+ i41 = i6 + 28 | 0;
+ i31 = i6 + 56 | 0;
+ i40 = i6 + 92 | 0;
+ i30 = i6 + 128 | 0;
+ i38 = i5 + 4 | 0;
+ L11 : while (1) {
+  i47 = HEAP32[i15 >> 2] | 0;
+  if ((i47 | 0) == 0) {
+   i4 = 36;
+   break;
+  } else {
+   d42 = 1.0;
+   i44 = 0;
+  }
+  do {
+   i48 = i47 + 4 | 0;
+   i43 = HEAP32[i48 >> 2] | 0;
+   do {
+    if ((i43 & 4 | 0) != 0 ? (HEAP32[i47 + 128 >> 2] | 0) <= 8 : 0) {
+     if ((i43 & 32 | 0) == 0) {
+      i43 = HEAP32[i47 + 48 >> 2] | 0;
+      i45 = HEAP32[i47 + 52 >> 2] | 0;
+      if ((HEAP8[i43 + 38 | 0] | 0) != 0) {
+       break;
+      }
+      if ((HEAP8[i45 + 38 | 0] | 0) != 0) {
+       break;
+      }
+      i46 = HEAP32[i43 + 8 >> 2] | 0;
+      i50 = HEAP32[i45 + 8 >> 2] | 0;
+      i53 = HEAP32[i46 >> 2] | 0;
+      i52 = HEAP32[i50 >> 2] | 0;
+      if (!((i53 | 0) == 2 | (i52 | 0) == 2)) {
+       i4 = 16;
+       break L11;
+      }
+      i51 = HEAP16[i46 + 4 >> 1] | 0;
+      i49 = HEAP16[i50 + 4 >> 1] | 0;
+      if (!((i51 & 2) != 0 & (i53 | 0) != 0 | (i49 & 2) != 0 & (i52 | 0) != 0)) {
+       break;
+      }
+      if (!((i51 & 8) != 0 | (i53 | 0) != 2 | ((i49 & 8) != 0 | (i52 | 0) != 2))) {
+       break;
+      }
+      i51 = i46 + 28 | 0;
+      i52 = i46 + 60 | 0;
+      d68 = +HEAPF32[i52 >> 2];
+      i49 = i50 + 28 | 0;
+      i53 = i50 + 60 | 0;
+      d67 = +HEAPF32[i53 >> 2];
+      if (!(d68 < d67)) {
+       if (d67 < d68) {
+        if (!(d67 < 1.0)) {
+         i4 = 25;
+         break L11;
+        }
+        d67 = (d68 - d67) / (1.0 - d67);
+        i66 = i50 + 36 | 0;
+        d69 = 1.0 - d67;
+        d71 = +(+HEAPF32[i66 >> 2] * d69 + d67 * +HEAPF32[i50 + 44 >> 2]);
+        d70 = +(d69 * +HEAPF32[i50 + 40 >> 2] + d67 * +HEAPF32[i50 + 48 >> 2]);
+        HEAPF32[i66 >> 2] = d71;
+        HEAPF32[i66 + 4 >> 2] = d70;
+        i66 = i50 + 52 | 0;
+        HEAPF32[i66 >> 2] = d69 * +HEAPF32[i66 >> 2] + d67 * +HEAPF32[i50 + 56 >> 2];
+        HEAPF32[i53 >> 2] = d68;
+        d67 = d68;
+       } else {
+        d67 = d68;
+       }
+      } else {
+       if (!(d68 < 1.0)) {
+        i4 = 21;
+        break L11;
+       }
+       d71 = (d67 - d68) / (1.0 - d68);
+       i66 = i46 + 36 | 0;
+       d70 = 1.0 - d71;
+       d68 = +(+HEAPF32[i66 >> 2] * d70 + d71 * +HEAPF32[i46 + 44 >> 2]);
+       d69 = +(d70 * +HEAPF32[i46 + 40 >> 2] + d71 * +HEAPF32[i46 + 48 >> 2]);
+       HEAPF32[i66 >> 2] = d68;
+       HEAPF32[i66 + 4 >> 2] = d69;
+       i66 = i46 + 52 | 0;
+       HEAPF32[i66 >> 2] = d70 * +HEAPF32[i66 >> 2] + d71 * +HEAPF32[i46 + 56 >> 2];
+       HEAPF32[i52 >> 2] = d67;
+      }
+      if (!(d67 < 1.0)) {
+       i4 = 28;
+       break L11;
+      }
+      i66 = HEAP32[i47 + 56 >> 2] | 0;
+      i46 = HEAP32[i47 + 60 >> 2] | 0;
+      HEAP32[i37 >> 2] = 0;
+      HEAP32[i36 >> 2] = 0;
+      HEAPF32[i35 >> 2] = 0.0;
+      HEAP32[i34 >> 2] = 0;
+      HEAP32[i33 >> 2] = 0;
+      HEAPF32[i32 >> 2] = 0.0;
+      __ZN15b2DistanceProxy3SetEPK7b2Shapei(i6, HEAP32[i43 + 12 >> 2] | 0, i66);
+      __ZN15b2DistanceProxy3SetEPK7b2Shapei(i41, HEAP32[i45 + 12 >> 2] | 0, i46);
+      i43 = i31 + 0 | 0;
+      i45 = i51 + 0 | 0;
+      i46 = i43 + 36 | 0;
+      do {
+       HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+       i43 = i43 + 4 | 0;
+       i45 = i45 + 4 | 0;
+      } while ((i43 | 0) < (i46 | 0));
+      i43 = i40 + 0 | 0;
+      i45 = i49 + 0 | 0;
+      i46 = i43 + 36 | 0;
+      do {
+       HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+       i43 = i43 + 4 | 0;
+       i45 = i45 + 4 | 0;
+      } while ((i43 | 0) < (i46 | 0));
+      HEAPF32[i30 >> 2] = 1.0;
+      __Z14b2TimeOfImpactP11b2TOIOutputPK10b2TOIInput(i5, i6);
+      if ((HEAP32[i5 >> 2] | 0) == 3) {
+       d67 = d67 + (1.0 - d67) * +HEAPF32[i38 >> 2];
+       d67 = d67 < 1.0 ? d67 : 1.0;
+      } else {
+       d67 = 1.0;
+      }
+      HEAPF32[i47 + 132 >> 2] = d67;
+      HEAP32[i48 >> 2] = HEAP32[i48 >> 2] | 32;
+     } else {
+      d67 = +HEAPF32[i47 + 132 >> 2];
+     }
+     if (d67 < d42) {
+      d42 = d67;
+      i44 = i47;
+     }
+    }
+   } while (0);
+   i47 = HEAP32[i47 + 12 >> 2] | 0;
+  } while ((i47 | 0) != 0);
+  if ((i44 | 0) == 0 | d42 > .9999988079071045) {
+   i4 = 36;
+   break;
+  }
+  i47 = HEAP32[(HEAP32[i44 + 48 >> 2] | 0) + 8 >> 2] | 0;
+  i48 = HEAP32[(HEAP32[i44 + 52 >> 2] | 0) + 8 >> 2] | 0;
+  i49 = i47 + 28 | 0;
+  i43 = i4 + 0 | 0;
+  i45 = i49 + 0 | 0;
+  i46 = i43 + 36 | 0;
+  do {
+   HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+   i43 = i43 + 4 | 0;
+   i45 = i45 + 4 | 0;
+  } while ((i43 | 0) < (i46 | 0));
+  i50 = i48 + 28 | 0;
+  i43 = i8 + 0 | 0;
+  i45 = i50 + 0 | 0;
+  i46 = i43 + 36 | 0;
+  do {
+   HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+   i43 = i43 + 4 | 0;
+   i45 = i45 + 4 | 0;
+  } while ((i43 | 0) < (i46 | 0));
+  i43 = i47 + 60 | 0;
+  d67 = +HEAPF32[i43 >> 2];
+  if (!(d67 < 1.0)) {
+   i4 = 38;
+   break;
+  }
+  d70 = (d42 - d67) / (1.0 - d67);
+  i57 = i47 + 36 | 0;
+  d67 = 1.0 - d70;
+  i52 = i47 + 44 | 0;
+  i53 = i47 + 48 | 0;
+  d71 = +HEAPF32[i57 >> 2] * d67 + d70 * +HEAPF32[i52 >> 2];
+  d72 = d67 * +HEAPF32[i47 + 40 >> 2] + d70 * +HEAPF32[i53 >> 2];
+  d69 = +d71;
+  d68 = +d72;
+  HEAPF32[i57 >> 2] = d69;
+  HEAPF32[i57 + 4 >> 2] = d68;
+  i57 = i47 + 52 | 0;
+  i51 = i47 + 56 | 0;
+  d70 = d67 * +HEAPF32[i57 >> 2] + d70 * +HEAPF32[i51 >> 2];
+  HEAPF32[i57 >> 2] = d70;
+  HEAPF32[i43 >> 2] = d42;
+  i57 = i47 + 44 | 0;
+  HEAPF32[i57 >> 2] = d69;
+  HEAPF32[i57 + 4 >> 2] = d68;
+  HEAPF32[i51 >> 2] = d70;
+  d68 = +Math_sin(+d70);
+  i57 = i47 + 20 | 0;
+  HEAPF32[i57 >> 2] = d68;
+  d70 = +Math_cos(+d70);
+  i56 = i47 + 24 | 0;
+  HEAPF32[i56 >> 2] = d70;
+  i58 = i47 + 12 | 0;
+  i55 = i47 + 28 | 0;
+  d69 = +HEAPF32[i55 >> 2];
+  i54 = i47 + 32 | 0;
+  d67 = +HEAPF32[i54 >> 2];
+  d71 = +(d71 - (d70 * d69 - d68 * d67));
+  d67 = +(d72 - (d68 * d69 + d70 * d67));
+  i43 = i58;
+  HEAPF32[i43 >> 2] = d71;
+  HEAPF32[i43 + 4 >> 2] = d67;
+  i43 = i48 + 60 | 0;
+  d67 = +HEAPF32[i43 >> 2];
+  if (!(d67 < 1.0)) {
+   i4 = 40;
+   break;
+  }
+  d70 = (d42 - d67) / (1.0 - d67);
+  i64 = i48 + 36 | 0;
+  d72 = 1.0 - d70;
+  i61 = i48 + 44 | 0;
+  i60 = i48 + 48 | 0;
+  d71 = +HEAPF32[i64 >> 2] * d72 + d70 * +HEAPF32[i61 >> 2];
+  d67 = d72 * +HEAPF32[i48 + 40 >> 2] + d70 * +HEAPF32[i60 >> 2];
+  d69 = +d71;
+  d68 = +d67;
+  HEAPF32[i64 >> 2] = d69;
+  HEAPF32[i64 + 4 >> 2] = d68;
+  i64 = i48 + 52 | 0;
+  i59 = i48 + 56 | 0;
+  d70 = d72 * +HEAPF32[i64 >> 2] + d70 * +HEAPF32[i59 >> 2];
+  HEAPF32[i64 >> 2] = d70;
+  HEAPF32[i43 >> 2] = d42;
+  i64 = i48 + 44 | 0;
+  HEAPF32[i64 >> 2] = d69;
+  HEAPF32[i64 + 4 >> 2] = d68;
+  HEAPF32[i59 >> 2] = d70;
+  d68 = +Math_sin(+d70);
+  i64 = i48 + 20 | 0;
+  HEAPF32[i64 >> 2] = d68;
+  d70 = +Math_cos(+d70);
+  i63 = i48 + 24 | 0;
+  HEAPF32[i63 >> 2] = d70;
+  i65 = i48 + 12 | 0;
+  i62 = i48 + 28 | 0;
+  d69 = +HEAPF32[i62 >> 2];
+  i66 = i48 + 32 | 0;
+  d72 = +HEAPF32[i66 >> 2];
+  d71 = +(d71 - (d70 * d69 - d68 * d72));
+  d72 = +(d67 - (d68 * d69 + d70 * d72));
+  i43 = i65;
+  HEAPF32[i43 >> 2] = d71;
+  HEAPF32[i43 + 4 >> 2] = d72;
+  __ZN9b2Contact6UpdateEP17b2ContactListener(i44, HEAP32[i13 >> 2] | 0);
+  i43 = i44 + 4 | 0;
+  i45 = HEAP32[i43 >> 2] | 0;
+  HEAP32[i43 >> 2] = i45 & -33;
+  i46 = i44 + 128 | 0;
+  HEAP32[i46 >> 2] = (HEAP32[i46 >> 2] | 0) + 1;
+  if ((i45 & 6 | 0) != 6) {
+   HEAP32[i43 >> 2] = i45 & -37;
+   i43 = i49 + 0 | 0;
+   i45 = i4 + 0 | 0;
+   i46 = i43 + 36 | 0;
+   do {
+    HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+    i43 = i43 + 4 | 0;
+    i45 = i45 + 4 | 0;
+   } while ((i43 | 0) < (i46 | 0));
+   i43 = i50 + 0 | 0;
+   i45 = i8 + 0 | 0;
+   i46 = i43 + 36 | 0;
+   do {
+    HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+    i43 = i43 + 4 | 0;
+    i45 = i45 + 4 | 0;
+   } while ((i43 | 0) < (i46 | 0));
+   d69 = +HEAPF32[i51 >> 2];
+   d71 = +Math_sin(+d69);
+   HEAPF32[i57 >> 2] = d71;
+   d69 = +Math_cos(+d69);
+   HEAPF32[i56 >> 2] = d69;
+   d72 = +HEAPF32[i55 >> 2];
+   d70 = +HEAPF32[i54 >> 2];
+   d68 = +(+HEAPF32[i52 >> 2] - (d69 * d72 - d71 * d70));
+   d70 = +(+HEAPF32[i53 >> 2] - (d71 * d72 + d69 * d70));
+   HEAPF32[i58 >> 2] = d68;
+   HEAPF32[i58 + 4 >> 2] = d70;
+   d70 = +HEAPF32[i59 >> 2];
+   d68 = +Math_sin(+d70);
+   HEAPF32[i64 >> 2] = d68;
+   d70 = +Math_cos(+d70);
+   HEAPF32[i63 >> 2] = d70;
+   d69 = +HEAPF32[i62 >> 2];
+   d72 = +HEAPF32[i66 >> 2];
+   d71 = +(+HEAPF32[i61 >> 2] - (d70 * d69 - d68 * d72));
+   d72 = +(+HEAPF32[i60 >> 2] - (d68 * d69 + d70 * d72));
+   i66 = i65;
+   HEAPF32[i66 >> 2] = d71;
+   HEAPF32[i66 + 4 >> 2] = d72;
+   continue;
+  }
+  i45 = i47 + 4 | 0;
+  i46 = HEAPU16[i45 >> 1] | 0;
+  if ((i46 & 2 | 0) == 0) {
+   HEAP16[i45 >> 1] = i46 | 2;
+   HEAPF32[i47 + 144 >> 2] = 0.0;
+  }
+  i46 = i48 + 4 | 0;
+  i49 = HEAPU16[i46 >> 1] | 0;
+  if ((i49 & 2 | 0) == 0) {
+   HEAP16[i46 >> 1] = i49 | 2;
+   HEAPF32[i48 + 144 >> 2] = 0.0;
+  }
+  HEAP32[i25 >> 2] = 0;
+  HEAP32[i26 >> 2] = 0;
+  HEAP32[i27 >> 2] = 0;
+  if ((HEAP32[i28 >> 2] | 0) <= 0) {
+   i4 = 48;
+   break;
+  }
+  i49 = i47 + 8 | 0;
+  HEAP32[i49 >> 2] = 0;
+  i51 = HEAP32[i25 >> 2] | 0;
+  HEAP32[(HEAP32[i29 >> 2] | 0) + (i51 << 2) >> 2] = i47;
+  i51 = i51 + 1 | 0;
+  HEAP32[i25 >> 2] = i51;
+  if ((i51 | 0) >= (HEAP32[i28 >> 2] | 0)) {
+   i4 = 50;
+   break;
+  }
+  i50 = i48 + 8 | 0;
+  HEAP32[i50 >> 2] = i51;
+  i51 = HEAP32[i25 >> 2] | 0;
+  HEAP32[(HEAP32[i29 >> 2] | 0) + (i51 << 2) >> 2] = i48;
+  HEAP32[i25 >> 2] = i51 + 1;
+  i51 = HEAP32[i26 >> 2] | 0;
+  if ((i51 | 0) >= (HEAP32[i24 >> 2] | 0)) {
+   i4 = 52;
+   break;
+  }
+  HEAP32[i26 >> 2] = i51 + 1;
+  HEAP32[(HEAP32[i23 >> 2] | 0) + (i51 << 2) >> 2] = i44;
+  HEAP16[i45 >> 1] = HEAPU16[i45 >> 1] | 1;
+  HEAP16[i46 >> 1] = HEAPU16[i46 >> 1] | 1;
+  HEAP32[i43 >> 2] = HEAP32[i43 >> 2] | 1;
+  HEAP32[i7 >> 2] = i47;
+  HEAP32[i22 >> 2] = i48;
+  i44 = 1;
+  while (1) {
+   L58 : do {
+    if ((HEAP32[i47 >> 2] | 0) == 2 ? (i12 = HEAP32[i47 + 112 >> 2] | 0, (i12 | 0) != 0) : 0) {
+     i47 = i47 + 4 | 0;
+     i51 = i12;
+     do {
+      if ((HEAP32[i25 >> 2] | 0) == (HEAP32[i28 >> 2] | 0)) {
+       break L58;
+      }
+      if ((HEAP32[i26 >> 2] | 0) == (HEAP32[i24 >> 2] | 0)) {
+       break L58;
+      }
+      i52 = HEAP32[i51 + 4 >> 2] | 0;
+      i53 = i52 + 4 | 0;
+      do {
+       if ((HEAP32[i53 >> 2] & 1 | 0) == 0) {
+        i48 = HEAP32[i51 >> 2] | 0;
+        if (((HEAP32[i48 >> 2] | 0) == 2 ? (HEAP16[i47 >> 1] & 8) == 0 : 0) ? (HEAP16[i48 + 4 >> 1] & 8) == 0 : 0) {
+         break;
+        }
+        if ((HEAP8[(HEAP32[i52 + 48 >> 2] | 0) + 38 | 0] | 0) == 0 ? (HEAP8[(HEAP32[i52 + 52 >> 2] | 0) + 38 | 0] | 0) == 0 : 0) {
+         i54 = i48 + 28 | 0;
+         i43 = i14 + 0 | 0;
+         i45 = i54 + 0 | 0;
+         i46 = i43 + 36 | 0;
+         do {
+          HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+          i43 = i43 + 4 | 0;
+          i45 = i45 + 4 | 0;
+         } while ((i43 | 0) < (i46 | 0));
+         i43 = i48 + 4 | 0;
+         if ((HEAP16[i43 >> 1] & 1) == 0) {
+          i45 = i48 + 60 | 0;
+          d67 = +HEAPF32[i45 >> 2];
+          if (!(d67 < 1.0)) {
+           i4 = 67;
+           break L11;
+          }
+          d70 = (d42 - d67) / (1.0 - d67);
+          i65 = i48 + 36 | 0;
+          d72 = 1.0 - d70;
+          d71 = +HEAPF32[i65 >> 2] * d72 + d70 * +HEAPF32[i48 + 44 >> 2];
+          d67 = d72 * +HEAPF32[i48 + 40 >> 2] + d70 * +HEAPF32[i48 + 48 >> 2];
+          d69 = +d71;
+          d68 = +d67;
+          HEAPF32[i65 >> 2] = d69;
+          HEAPF32[i65 + 4 >> 2] = d68;
+          i65 = i48 + 52 | 0;
+          i66 = i48 + 56 | 0;
+          d70 = d72 * +HEAPF32[i65 >> 2] + d70 * +HEAPF32[i66 >> 2];
+          HEAPF32[i65 >> 2] = d70;
+          HEAPF32[i45 >> 2] = d42;
+          i65 = i48 + 44 | 0;
+          HEAPF32[i65 >> 2] = d69;
+          HEAPF32[i65 + 4 >> 2] = d68;
+          HEAPF32[i66 >> 2] = d70;
+          d68 = +Math_sin(+d70);
+          HEAPF32[i48 + 20 >> 2] = d68;
+          d70 = +Math_cos(+d70);
+          HEAPF32[i48 + 24 >> 2] = d70;
+          d69 = +HEAPF32[i48 + 28 >> 2];
+          d72 = +HEAPF32[i48 + 32 >> 2];
+          d71 = +(d71 - (d70 * d69 - d68 * d72));
+          d72 = +(d67 - (d68 * d69 + d70 * d72));
+          i66 = i48 + 12 | 0;
+          HEAPF32[i66 >> 2] = d71;
+          HEAPF32[i66 + 4 >> 2] = d72;
+         }
+         __ZN9b2Contact6UpdateEP17b2ContactListener(i52, HEAP32[i13 >> 2] | 0);
+         i45 = HEAP32[i53 >> 2] | 0;
+         if ((i45 & 4 | 0) == 0) {
+          i43 = i54 + 0 | 0;
+          i45 = i14 + 0 | 0;
+          i46 = i43 + 36 | 0;
+          do {
+           HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+           i43 = i43 + 4 | 0;
+           i45 = i45 + 4 | 0;
+          } while ((i43 | 0) < (i46 | 0));
+          d70 = +HEAPF32[i48 + 56 >> 2];
+          d68 = +Math_sin(+d70);
+          HEAPF32[i48 + 20 >> 2] = d68;
+          d70 = +Math_cos(+d70);
+          HEAPF32[i48 + 24 >> 2] = d70;
+          d69 = +HEAPF32[i48 + 28 >> 2];
+          d72 = +HEAPF32[i48 + 32 >> 2];
+          d71 = +(+HEAPF32[i48 + 44 >> 2] - (d70 * d69 - d68 * d72));
+          d72 = +(+HEAPF32[i48 + 48 >> 2] - (d68 * d69 + d70 * d72));
+          i66 = i48 + 12 | 0;
+          HEAPF32[i66 >> 2] = d71;
+          HEAPF32[i66 + 4 >> 2] = d72;
+          break;
+         }
+         if ((i45 & 2 | 0) == 0) {
+          i43 = i54 + 0 | 0;
+          i45 = i14 + 0 | 0;
+          i46 = i43 + 36 | 0;
+          do {
+           HEAP32[i43 >> 2] = HEAP32[i45 >> 2];
+           i43 = i43 + 4 | 0;
+           i45 = i45 + 4 | 0;
+          } while ((i43 | 0) < (i46 | 0));
+          d70 = +HEAPF32[i48 + 56 >> 2];
+          d68 = +Math_sin(+d70);
+          HEAPF32[i48 + 20 >> 2] = d68;
+          d70 = +Math_cos(+d70);
+          HEAPF32[i48 + 24 >> 2] = d70;
+          d69 = +HEAPF32[i48 + 28 >> 2];
+          d72 = +HEAPF32[i48 + 32 >> 2];
+          d71 = +(+HEAPF32[i48 + 44 >> 2] - (d70 * d69 - d68 * d72));
+          d72 = +(+HEAPF32[i48 + 48 >> 2] - (d68 * d69 + d70 * d72));
+          i66 = i48 + 12 | 0;
+          HEAPF32[i66 >> 2] = d71;
+          HEAPF32[i66 + 4 >> 2] = d72;
+          break;
+         }
+         HEAP32[i53 >> 2] = i45 | 1;
+         i45 = HEAP32[i26 >> 2] | 0;
+         if ((i45 | 0) >= (HEAP32[i24 >> 2] | 0)) {
+          i4 = 74;
+          break L11;
+         }
+         HEAP32[i26 >> 2] = i45 + 1;
+         HEAP32[(HEAP32[i23 >> 2] | 0) + (i45 << 2) >> 2] = i52;
+         i45 = HEAPU16[i43 >> 1] | 0;
+         if ((i45 & 1 | 0) == 0) {
+          HEAP16[i43 >> 1] = i45 | 1;
+          if ((HEAP32[i48 >> 2] | 0) != 0 ? (i45 & 2 | 0) == 0 : 0) {
+           HEAP16[i43 >> 1] = i45 | 3;
+           HEAPF32[i48 + 144 >> 2] = 0.0;
+          }
+          i43 = HEAP32[i25 >> 2] | 0;
+          if ((i43 | 0) >= (HEAP32[i28 >> 2] | 0)) {
+           i4 = 80;
+           break L11;
+          }
+          HEAP32[i48 + 8 >> 2] = i43;
+          i66 = HEAP32[i25 >> 2] | 0;
+          HEAP32[(HEAP32[i29 >> 2] | 0) + (i66 << 2) >> 2] = i48;
+          HEAP32[i25 >> 2] = i66 + 1;
+         }
+        }
+       }
+      } while (0);
+      i51 = HEAP32[i51 + 12 >> 2] | 0;
+     } while ((i51 | 0) != 0);
+    }
+   } while (0);
+   if ((i44 | 0) >= 2) {
+    break;
+   }
+   i47 = HEAP32[i7 + (i44 << 2) >> 2] | 0;
+   i44 = i44 + 1 | 0;
+  }
+  d72 = (1.0 - d42) * +HEAPF32[i11 >> 2];
+  HEAPF32[i9 >> 2] = d72;
+  HEAPF32[i21 >> 2] = 1.0 / d72;
+  HEAPF32[i20 >> 2] = 1.0;
+  HEAP32[i19 >> 2] = 20;
+  HEAP32[i17 >> 2] = HEAP32[i18 >> 2];
+  HEAP8[i16] = 0;
+  __ZN8b2Island8SolveTOIERK10b2TimeStepii(i3, i9, HEAP32[i49 >> 2] | 0, HEAP32[i50 >> 2] | 0);
+  i44 = HEAP32[i25 >> 2] | 0;
+  if ((i44 | 0) > 0) {
+   i43 = 0;
+   do {
+    i45 = HEAP32[(HEAP32[i29 >> 2] | 0) + (i43 << 2) >> 2] | 0;
+    i66 = i45 + 4 | 0;
+    HEAP16[i66 >> 1] = HEAP16[i66 >> 1] & 65534;
+    if ((HEAP32[i45 >> 2] | 0) == 2) {
+     __ZN6b2Body19SynchronizeFixturesEv(i45);
+     i44 = HEAP32[i45 + 112 >> 2] | 0;
+     if ((i44 | 0) != 0) {
+      do {
+       i66 = (HEAP32[i44 + 4 >> 2] | 0) + 4 | 0;
+       HEAP32[i66 >> 2] = HEAP32[i66 >> 2] & -34;
+       i44 = HEAP32[i44 + 12 >> 2] | 0;
+      } while ((i44 | 0) != 0);
+     }
+     i44 = HEAP32[i25 >> 2] | 0;
+    }
+    i43 = i43 + 1 | 0;
+   } while ((i43 | 0) < (i44 | 0));
+  }
+  __ZN16b2ContactManager15FindNewContactsEv(i10);
+  if ((HEAP8[i39] | 0) != 0) {
+   i4 = 92;
+   break;
+  }
+ }
+ if ((i4 | 0) == 16) {
+  ___assert_fail(2288, 2184, 641, 2344);
+ } else if ((i4 | 0) == 21) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 25) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 28) {
+  ___assert_fail(2360, 2184, 676, 2344);
+ } else if ((i4 | 0) == 36) {
+  HEAP8[i2] = 1;
+  __ZN8b2IslandD2Ev(i3);
+  STACKTOP = i1;
+  return;
+ } else if ((i4 | 0) == 38) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 40) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 48) {
+  ___assert_fail(2520, 2440, 54, 2472);
+ } else if ((i4 | 0) == 50) {
+  ___assert_fail(2520, 2440, 54, 2472);
+ } else if ((i4 | 0) == 52) {
+  ___assert_fail(2480, 2440, 62, 2472);
+ } else if ((i4 | 0) == 67) {
+  ___assert_fail(2360, 2376, 723, 2400);
+ } else if ((i4 | 0) == 74) {
+  ___assert_fail(2480, 2440, 62, 2472);
+ } else if ((i4 | 0) == 80) {
+  ___assert_fail(2520, 2440, 54, 2472);
+ } else if ((i4 | 0) == 92) {
+  HEAP8[i2] = 0;
+  __ZN8b2IslandD2Ev(i3);
+  STACKTOP = i1;
+  return;
+ }
+}
+function __ZNSt3__16__sortIRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i5, i8, i1) {
+ i5 = i5 | 0;
+ i8 = i8 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i3;
+ L1 : while (1) {
+  i7 = i8;
+  i4 = i8 + -12 | 0;
+  L3 : while (1) {
+   i9 = i5;
+   i11 = i7 - i9 | 0;
+   switch ((i11 | 0) / 12 | 0 | 0) {
+   case 4:
+    {
+     i6 = 14;
+     break L1;
+    }
+   case 2:
+    {
+     i6 = 4;
+     break L1;
+    }
+   case 3:
+    {
+     i6 = 6;
+     break L1;
+    }
+   case 5:
+    {
+     i6 = 15;
+     break L1;
+    }
+   case 1:
+   case 0:
+    {
+     i6 = 67;
+     break L1;
+    }
+   default:
+    {}
+   }
+   if ((i11 | 0) < 372) {
+    i6 = 21;
+    break L1;
+   }
+   i12 = (i11 | 0) / 24 | 0;
+   i10 = i5 + (i12 * 12 | 0) | 0;
+   do {
+    if ((i11 | 0) > 11988) {
+     i14 = (i11 | 0) / 48 | 0;
+     i11 = i5 + (i14 * 12 | 0) | 0;
+     i14 = i5 + ((i14 + i12 | 0) * 12 | 0) | 0;
+     i12 = __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i5, i11, i10, i14, i1) | 0;
+     if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i14) | 0) {
+      HEAP32[i2 + 0 >> 2] = HEAP32[i14 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i14 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i14 + 8 >> 2];
+      HEAP32[i14 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i14 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i14 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i13 = i12 + 1 | 0;
+      if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i14, i10) | 0) {
+       HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+       HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+       HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+       HEAP32[i10 + 0 >> 2] = HEAP32[i14 + 0 >> 2];
+       HEAP32[i10 + 4 >> 2] = HEAP32[i14 + 4 >> 2];
+       HEAP32[i10 + 8 >> 2] = HEAP32[i14 + 8 >> 2];
+       HEAP32[i14 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+       HEAP32[i14 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+       HEAP32[i14 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+       i13 = i12 + 2 | 0;
+       if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i10, i11) | 0) {
+        HEAP32[i2 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+        HEAP32[i2 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+        HEAP32[i2 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+        HEAP32[i11 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+        HEAP32[i11 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+        HEAP32[i11 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+        HEAP32[i10 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+        HEAP32[i10 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+        HEAP32[i10 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+        if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i11, i5) | 0) {
+         HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+         HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+         HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+         HEAP32[i5 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+         HEAP32[i5 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+         HEAP32[i5 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+         HEAP32[i11 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+         HEAP32[i11 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+         HEAP32[i11 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+         i12 = i12 + 4 | 0;
+        } else {
+         i12 = i12 + 3 | 0;
+        }
+       } else {
+        i12 = i13;
+       }
+      } else {
+       i12 = i13;
+      }
+     }
+    } else {
+     i15 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i10, i5) | 0;
+     i11 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i10) | 0;
+     if (!i15) {
+      if (!i11) {
+       i12 = 0;
+       break;
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i10, i5) | 0)) {
+       i12 = 1;
+       break;
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+      HEAP32[i5 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i5 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i5 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i12 = 2;
+      break;
+     }
+     if (i11) {
+      HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+      HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i12 = 1;
+      break;
+     }
+     HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+     HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+     HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+     HEAP32[i5 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+     HEAP32[i5 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+     HEAP32[i5 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+     HEAP32[i10 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+     HEAP32[i10 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+     HEAP32[i10 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+     if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i10) | 0) {
+      HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i12 = 2;
+     } else {
+      i12 = 1;
+     }
+    }
+   } while (0);
+   do {
+    if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i10) | 0) {
+     i13 = i4;
+    } else {
+     i13 = i4;
+     while (1) {
+      i13 = i13 + -12 | 0;
+      if ((i5 | 0) == (i13 | 0)) {
+       break;
+      }
+      if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i13, i10) | 0) {
+       i6 = 50;
+       break;
+      }
+     }
+     if ((i6 | 0) == 50) {
+      i6 = 0;
+      HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+      HEAP32[i5 + 0 >> 2] = HEAP32[i13 + 0 >> 2];
+      HEAP32[i5 + 4 >> 2] = HEAP32[i13 + 4 >> 2];
+      HEAP32[i5 + 8 >> 2] = HEAP32[i13 + 8 >> 2];
+      HEAP32[i13 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i13 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i13 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i12 = i12 + 1 | 0;
+      break;
+     }
+     i10 = i5 + 12 | 0;
+     if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i4) | 0)) {
+      if ((i10 | 0) == (i4 | 0)) {
+       i6 = 67;
+       break L1;
+      }
+      while (1) {
+       i9 = i10 + 12 | 0;
+       if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i10) | 0) {
+        break;
+       }
+       if ((i9 | 0) == (i4 | 0)) {
+        i6 = 67;
+        break L1;
+       } else {
+        i10 = i9;
+       }
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+      HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i10 = i9;
+     }
+     if ((i10 | 0) == (i4 | 0)) {
+      i6 = 67;
+      break L1;
+     } else {
+      i9 = i4;
+     }
+     while (1) {
+      while (1) {
+       i11 = i10 + 12 | 0;
+       if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i10) | 0) {
+        break;
+       } else {
+        i10 = i11;
+       }
+      }
+      do {
+       i9 = i9 + -12 | 0;
+      } while (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i9) | 0);
+      if (!(i10 >>> 0 < i9 >>> 0)) {
+       i5 = i10;
+       continue L3;
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      HEAP32[i9 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i9 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i9 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i10 = i11;
+     }
+    }
+   } while (0);
+   i11 = i5 + 12 | 0;
+   L47 : do {
+    if (i11 >>> 0 < i13 >>> 0) {
+     while (1) {
+      i15 = i11;
+      while (1) {
+       i11 = i15 + 12 | 0;
+       if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i15, i10) | 0) {
+        i15 = i11;
+       } else {
+        i14 = i13;
+        break;
+       }
+      }
+      do {
+       i14 = i14 + -12 | 0;
+      } while (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i14, i10) | 0));
+      if (i15 >>> 0 > i14 >>> 0) {
+       i11 = i15;
+       break L47;
+      }
+      HEAP32[i2 + 0 >> 2] = HEAP32[i15 + 0 >> 2];
+      HEAP32[i2 + 4 >> 2] = HEAP32[i15 + 4 >> 2];
+      HEAP32[i2 + 8 >> 2] = HEAP32[i15 + 8 >> 2];
+      HEAP32[i15 + 0 >> 2] = HEAP32[i14 + 0 >> 2];
+      HEAP32[i15 + 4 >> 2] = HEAP32[i14 + 4 >> 2];
+      HEAP32[i15 + 8 >> 2] = HEAP32[i14 + 8 >> 2];
+      HEAP32[i14 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+      HEAP32[i14 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+      HEAP32[i14 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+      i13 = i14;
+      i10 = (i10 | 0) == (i15 | 0) ? i14 : i10;
+      i12 = i12 + 1 | 0;
+     }
+    }
+   } while (0);
+   if ((i11 | 0) != (i10 | 0) ? FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i10, i11) | 0 : 0) {
+    HEAP32[i2 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+    HEAP32[i2 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+    HEAP32[i2 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+    HEAP32[i11 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+    HEAP32[i11 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+    HEAP32[i11 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+    HEAP32[i10 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+    HEAP32[i10 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+    HEAP32[i10 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+    i12 = i12 + 1 | 0;
+   }
+   if ((i12 | 0) == 0) {
+    i12 = __ZNSt3__127__insertion_sort_incompleteIRPFbRK6b2PairS3_EPS1_EEbT0_S8_T_(i5, i11, i1) | 0;
+    i10 = i11 + 12 | 0;
+    if (__ZNSt3__127__insertion_sort_incompleteIRPFbRK6b2PairS3_EPS1_EEbT0_S8_T_(i10, i8, i1) | 0) {
+     i6 = 62;
+     break;
+    }
+    if (i12) {
+     i5 = i10;
+     continue;
+    }
+   }
+   i15 = i11;
+   if ((i15 - i9 | 0) >= (i7 - i15 | 0)) {
+    i6 = 66;
+    break;
+   }
+   __ZNSt3__16__sortIRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i5, i11, i1);
+   i5 = i11 + 12 | 0;
+  }
+  if ((i6 | 0) == 62) {
+   i6 = 0;
+   if (i12) {
+    i6 = 67;
+    break;
+   } else {
+    i8 = i11;
+    continue;
+   }
+  } else if ((i6 | 0) == 66) {
+   i6 = 0;
+   __ZNSt3__16__sortIRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i11 + 12 | 0, i8, i1);
+   i8 = i11;
+   continue;
+  }
+ }
+ if ((i6 | 0) == 4) {
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i5) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+  HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+  HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+  HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+  HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 6) {
+  i6 = i5 + 12 | 0;
+  i15 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i6, i5) | 0;
+  i7 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i6) | 0;
+  if (!i15) {
+   if (!i7) {
+    STACKTOP = i3;
+    return;
+   }
+   HEAP32[i2 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i2 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i2 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i6, i5) | 0)) {
+    STACKTOP = i3;
+    return;
+   }
+   HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+   STACKTOP = i3;
+   return;
+  }
+  if (i7) {
+   HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+  HEAP32[i5 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i5 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i5 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  HEAP32[i6 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i6 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i6 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i6) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  HEAP32[i6 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+  HEAP32[i6 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+  HEAP32[i6 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+  HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 14) {
+  __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i5, i5 + 12 | 0, i5 + 24 | 0, i4, i1) | 0;
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 15) {
+  i6 = i5 + 12 | 0;
+  i7 = i5 + 24 | 0;
+  i8 = i5 + 36 | 0;
+  __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i5, i6, i7, i8, i1) | 0;
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i8) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+  HEAP32[i8 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+  HEAP32[i8 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+  HEAP32[i8 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+  HEAP32[i4 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i4 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i8, i7) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+  HEAP32[i7 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+  HEAP32[i7 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+  HEAP32[i7 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+  HEAP32[i8 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i8 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i8 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i7, i6) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+  HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+  HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+  HEAP32[i7 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i7 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i7 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i6, i5) | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i2 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+  HEAP32[i2 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+  HEAP32[i5 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i5 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i5 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  HEAP32[i6 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+  HEAP32[i6 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+  HEAP32[i6 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 21) {
+  __ZNSt3__118__insertion_sort_3IRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i5, i8, i1);
+  STACKTOP = i3;
+  return;
+ } else if ((i6 | 0) == 67) {
+  STACKTOP = i3;
+  return;
+ }
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[7176 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[7180 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[7168 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 7200 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[1790] = HEAP32[1790] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 7464 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[7184 >> 2] | 0)) {
+   i21 = (HEAP32[7172 >> 2] | 0) + i11 | 0;
+   HEAP32[7172 >> 2] = i21;
+   HEAP32[7184 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[7180 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[7180 >> 2] = 0;
+   HEAP32[7168 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[7180 >> 2] | 0)) {
+   i21 = (HEAP32[7168 >> 2] | 0) + i11 | 0;
+   HEAP32[7168 >> 2] = i21;
+   HEAP32[7180 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 7464 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[7164 >> 2] = HEAP32[7164 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 7200 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[1790] = HEAP32[1790] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[7180 >> 2] | 0)) {
+   HEAP32[7168 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 7200 + (i7 << 2) | 0;
+  i8 = HEAP32[1790] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 7200 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[1790] = i8 | i6;
+   i4 = 7200 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 7464 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[7164 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L204 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L204;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[7176 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[7176 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[7164 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[7192 >> 2] | 0) + -1 | 0;
+ HEAP32[7192 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 7616 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[7192 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function __ZNSt3__127__insertion_sort_incompleteIRPFbRK6b2PairS3_EPS1_EEbT0_S8_T_(i3, i4, i2) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i7 = i1 + 12 | 0;
+ i6 = i1;
+ switch ((i4 - i3 | 0) / 12 | 0 | 0) {
+ case 5:
+  {
+   i6 = i3 + 12 | 0;
+   i8 = i3 + 24 | 0;
+   i5 = i3 + 36 | 0;
+   i4 = i4 + -12 | 0;
+   __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i3, i6, i8, i5, i2) | 0;
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i4, i5) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i5, i8) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+   HEAP32[i8 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i8 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i8 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i8, i6) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+   HEAP32[i8 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i8 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i8 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i6, i3) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+   HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ case 4:
+  {
+   __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i3, i3 + 12 | 0, i3 + 24 | 0, i4 + -12 | 0, i2) | 0;
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ case 3:
+  {
+   i5 = i3 + 12 | 0;
+   i4 = i4 + -12 | 0;
+   i10 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i5, i3) | 0;
+   i6 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i4, i5) | 0;
+   if (!i10) {
+    if (!i6) {
+     i10 = 1;
+     STACKTOP = i1;
+     return i10 | 0;
+    }
+    HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+    HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i5, i3) | 0)) {
+     i10 = 1;
+     STACKTOP = i1;
+     return i10 | 0;
+    }
+    HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    HEAP32[i3 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   if (i6) {
+    HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    HEAP32[i3 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+    HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+   HEAP32[i3 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i4, i5) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ case 2:
+  {
+   i4 = i4 + -12 | 0;
+   if (!(FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i4, i3) | 0)) {
+    i10 = 1;
+    STACKTOP = i1;
+    return i10 | 0;
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+   HEAP32[i3 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i4 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i4 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ case 1:
+ case 0:
+  {
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ default:
+  {
+   i9 = i3 + 24 | 0;
+   i10 = i3 + 12 | 0;
+   i11 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i10, i3) | 0;
+   i8 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i9, i10) | 0;
+   do {
+    if (i11) {
+     if (i8) {
+      HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+      HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+      HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+      HEAP32[i3 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i3 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i3 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      HEAP32[i9 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+      HEAP32[i9 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+      HEAP32[i9 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+      break;
+     }
+     HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+     HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+     HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+     HEAP32[i3 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+     HEAP32[i3 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+     HEAP32[i3 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+     HEAP32[i10 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+     HEAP32[i10 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+     HEAP32[i10 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+     if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i9, i10) | 0) {
+      HEAP32[i7 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i7 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i7 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      HEAP32[i9 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+      HEAP32[i9 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+      HEAP32[i9 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+     }
+    } else {
+     if (i8) {
+      HEAP32[i7 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+      HEAP32[i7 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+      HEAP32[i7 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+      HEAP32[i10 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      HEAP32[i9 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+      HEAP32[i9 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+      HEAP32[i9 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+      if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i10, i3) | 0) {
+       HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+       HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+       HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+       HEAP32[i3 + 0 >> 2] = HEAP32[i10 + 0 >> 2];
+       HEAP32[i3 + 4 >> 2] = HEAP32[i10 + 4 >> 2];
+       HEAP32[i3 + 8 >> 2] = HEAP32[i10 + 8 >> 2];
+       HEAP32[i10 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+       HEAP32[i10 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+       HEAP32[i10 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+      }
+     }
+    }
+   } while (0);
+   i7 = i3 + 36 | 0;
+   if ((i7 | 0) == (i4 | 0)) {
+    i11 = 1;
+    STACKTOP = i1;
+    return i11 | 0;
+   }
+   i8 = 0;
+   while (1) {
+    if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i7, i9) | 0) {
+     HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+     HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+     HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+     i10 = i7;
+     while (1) {
+      HEAP32[i10 + 0 >> 2] = HEAP32[i9 + 0 >> 2];
+      HEAP32[i10 + 4 >> 2] = HEAP32[i9 + 4 >> 2];
+      HEAP32[i10 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+      if ((i9 | 0) == (i3 | 0)) {
+       break;
+      }
+      i10 = i9 + -12 | 0;
+      if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i6, i10) | 0) {
+       i11 = i9;
+       i9 = i10;
+       i10 = i11;
+      } else {
+       break;
+      }
+     }
+     HEAP32[i9 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+     HEAP32[i9 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+     HEAP32[i9 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+     i8 = i8 + 1 | 0;
+     if ((i8 | 0) == 8) {
+      break;
+     }
+    }
+    i9 = i7 + 12 | 0;
+    if ((i9 | 0) == (i4 | 0)) {
+     i2 = 1;
+     i5 = 35;
+     break;
+    } else {
+     i11 = i7;
+     i7 = i9;
+     i9 = i11;
+    }
+   }
+   if ((i5 | 0) == 35) {
+    STACKTOP = i1;
+    return i2 | 0;
+   }
+   i11 = (i7 + 12 | 0) == (i4 | 0);
+   STACKTOP = i1;
+   return i11 | 0;
+  }
+ }
+ return 0;
+}
+function __ZN13b2DynamicTree7BalanceEi(i11, i6) {
+ i11 = i11 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, d19 = 0.0, i20 = 0, i21 = 0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0;
+ i1 = STACKTOP;
+ if ((i6 | 0) == -1) {
+  ___assert_fail(3216, 2944, 382, 3232);
+ }
+ i5 = HEAP32[i11 + 4 >> 2] | 0;
+ i13 = i5 + (i6 * 36 | 0) | 0;
+ i18 = i5 + (i6 * 36 | 0) + 24 | 0;
+ i8 = HEAP32[i18 >> 2] | 0;
+ if ((i8 | 0) == -1) {
+  i21 = i6;
+  STACKTOP = i1;
+  return i21 | 0;
+ }
+ i2 = i5 + (i6 * 36 | 0) + 32 | 0;
+ if ((HEAP32[i2 >> 2] | 0) < 2) {
+  i21 = i6;
+  STACKTOP = i1;
+  return i21 | 0;
+ }
+ i20 = i5 + (i6 * 36 | 0) + 28 | 0;
+ i7 = HEAP32[i20 >> 2] | 0;
+ if (!((i8 | 0) > -1)) {
+  ___assert_fail(3240, 2944, 392, 3232);
+ }
+ i12 = HEAP32[i11 + 12 >> 2] | 0;
+ if ((i8 | 0) >= (i12 | 0)) {
+  ___assert_fail(3240, 2944, 392, 3232);
+ }
+ if (!((i7 | 0) > -1 & (i7 | 0) < (i12 | 0))) {
+  ___assert_fail(3272, 2944, 393, 3232);
+ }
+ i9 = i5 + (i8 * 36 | 0) | 0;
+ i10 = i5 + (i7 * 36 | 0) | 0;
+ i3 = i5 + (i7 * 36 | 0) + 32 | 0;
+ i4 = i5 + (i8 * 36 | 0) + 32 | 0;
+ i14 = (HEAP32[i3 >> 2] | 0) - (HEAP32[i4 >> 2] | 0) | 0;
+ if ((i14 | 0) > 1) {
+  i21 = i5 + (i7 * 36 | 0) + 24 | 0;
+  i14 = HEAP32[i21 >> 2] | 0;
+  i18 = i5 + (i7 * 36 | 0) + 28 | 0;
+  i15 = HEAP32[i18 >> 2] | 0;
+  i16 = i5 + (i14 * 36 | 0) | 0;
+  i17 = i5 + (i15 * 36 | 0) | 0;
+  if (!((i14 | 0) > -1 & (i14 | 0) < (i12 | 0))) {
+   ___assert_fail(3304, 2944, 407, 3232);
+  }
+  if (!((i15 | 0) > -1 & (i15 | 0) < (i12 | 0))) {
+   ___assert_fail(3336, 2944, 408, 3232);
+  }
+  HEAP32[i21 >> 2] = i6;
+  i21 = i5 + (i6 * 36 | 0) + 20 | 0;
+  i12 = i5 + (i7 * 36 | 0) + 20 | 0;
+  HEAP32[i12 >> 2] = HEAP32[i21 >> 2];
+  HEAP32[i21 >> 2] = i7;
+  i12 = HEAP32[i12 >> 2] | 0;
+  do {
+   if (!((i12 | 0) == -1)) {
+    i11 = i5 + (i12 * 36 | 0) + 24 | 0;
+    if ((HEAP32[i11 >> 2] | 0) == (i6 | 0)) {
+     HEAP32[i11 >> 2] = i7;
+     break;
+    }
+    i11 = i5 + (i12 * 36 | 0) + 28 | 0;
+    if ((HEAP32[i11 >> 2] | 0) == (i6 | 0)) {
+     HEAP32[i11 >> 2] = i7;
+     break;
+    } else {
+     ___assert_fail(3368, 2944, 424, 3232);
+    }
+   } else {
+    HEAP32[i11 >> 2] = i7;
+   }
+  } while (0);
+  i11 = i5 + (i14 * 36 | 0) + 32 | 0;
+  i12 = i5 + (i15 * 36 | 0) + 32 | 0;
+  if ((HEAP32[i11 >> 2] | 0) > (HEAP32[i12 >> 2] | 0)) {
+   HEAP32[i18 >> 2] = i14;
+   HEAP32[i20 >> 2] = i15;
+   HEAP32[i5 + (i15 * 36 | 0) + 20 >> 2] = i6;
+   d19 = +HEAPF32[i9 >> 2];
+   d22 = +HEAPF32[i17 >> 2];
+   d19 = d19 < d22 ? d19 : d22;
+   d23 = +HEAPF32[i5 + (i8 * 36 | 0) + 4 >> 2];
+   d22 = +HEAPF32[i5 + (i15 * 36 | 0) + 4 >> 2];
+   d24 = +d19;
+   d23 = +(d23 < d22 ? d23 : d22);
+   i21 = i13;
+   HEAPF32[i21 >> 2] = d24;
+   HEAPF32[i21 + 4 >> 2] = d23;
+   d23 = +HEAPF32[i5 + (i8 * 36 | 0) + 8 >> 2];
+   d24 = +HEAPF32[i5 + (i15 * 36 | 0) + 8 >> 2];
+   d22 = +HEAPF32[i5 + (i8 * 36 | 0) + 12 >> 2];
+   d25 = +HEAPF32[i5 + (i15 * 36 | 0) + 12 >> 2];
+   d23 = +(d23 > d24 ? d23 : d24);
+   d24 = +(d22 > d25 ? d22 : d25);
+   i21 = i5 + (i6 * 36 | 0) + 8 | 0;
+   HEAPF32[i21 >> 2] = d23;
+   HEAPF32[i21 + 4 >> 2] = d24;
+   d24 = +HEAPF32[i16 >> 2];
+   d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 4 >> 2];
+   d23 = +HEAPF32[i5 + (i14 * 36 | 0) + 4 >> 2];
+   d19 = +(d19 < d24 ? d19 : d24);
+   d22 = +(d22 < d23 ? d22 : d23);
+   i21 = i10;
+   HEAPF32[i21 >> 2] = d19;
+   HEAPF32[i21 + 4 >> 2] = d22;
+   d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 8 >> 2];
+   d19 = +HEAPF32[i5 + (i14 * 36 | 0) + 8 >> 2];
+   d23 = +HEAPF32[i5 + (i6 * 36 | 0) + 12 >> 2];
+   d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 12 >> 2];
+   d19 = +(d22 > d19 ? d22 : d19);
+   d25 = +(d23 > d24 ? d23 : d24);
+   i5 = i5 + (i7 * 36 | 0) + 8 | 0;
+   HEAPF32[i5 >> 2] = d19;
+   HEAPF32[i5 + 4 >> 2] = d25;
+   i4 = HEAP32[i4 >> 2] | 0;
+   i5 = HEAP32[i12 >> 2] | 0;
+   i4 = ((i4 | 0) > (i5 | 0) ? i4 : i5) + 1 | 0;
+   HEAP32[i2 >> 2] = i4;
+   i2 = HEAP32[i11 >> 2] | 0;
+   i2 = (i4 | 0) > (i2 | 0) ? i4 : i2;
+  } else {
+   HEAP32[i18 >> 2] = i15;
+   HEAP32[i20 >> 2] = i14;
+   HEAP32[i5 + (i14 * 36 | 0) + 20 >> 2] = i6;
+   d19 = +HEAPF32[i9 >> 2];
+   d22 = +HEAPF32[i16 >> 2];
+   d19 = d19 < d22 ? d19 : d22;
+   d23 = +HEAPF32[i5 + (i8 * 36 | 0) + 4 >> 2];
+   d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 4 >> 2];
+   d22 = +d19;
+   d23 = +(d23 < d24 ? d23 : d24);
+   i21 = i13;
+   HEAPF32[i21 >> 2] = d22;
+   HEAPF32[i21 + 4 >> 2] = d23;
+   d23 = +HEAPF32[i5 + (i8 * 36 | 0) + 8 >> 2];
+   d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 8 >> 2];
+   d22 = +HEAPF32[i5 + (i8 * 36 | 0) + 12 >> 2];
+   d25 = +HEAPF32[i5 + (i14 * 36 | 0) + 12 >> 2];
+   d23 = +(d23 > d24 ? d23 : d24);
+   d24 = +(d22 > d25 ? d22 : d25);
+   i21 = i5 + (i6 * 36 | 0) + 8 | 0;
+   HEAPF32[i21 >> 2] = d23;
+   HEAPF32[i21 + 4 >> 2] = d24;
+   d24 = +HEAPF32[i17 >> 2];
+   d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 4 >> 2];
+   d23 = +HEAPF32[i5 + (i15 * 36 | 0) + 4 >> 2];
+   d19 = +(d19 < d24 ? d19 : d24);
+   d23 = +(d22 < d23 ? d22 : d23);
+   i21 = i10;
+   HEAPF32[i21 >> 2] = d19;
+   HEAPF32[i21 + 4 >> 2] = d23;
+   d23 = +HEAPF32[i5 + (i6 * 36 | 0) + 8 >> 2];
+   d19 = +HEAPF32[i5 + (i15 * 36 | 0) + 8 >> 2];
+   d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 12 >> 2];
+   d24 = +HEAPF32[i5 + (i15 * 36 | 0) + 12 >> 2];
+   d19 = +(d23 > d19 ? d23 : d19);
+   d25 = +(d22 > d24 ? d22 : d24);
+   i5 = i5 + (i7 * 36 | 0) + 8 | 0;
+   HEAPF32[i5 >> 2] = d19;
+   HEAPF32[i5 + 4 >> 2] = d25;
+   i4 = HEAP32[i4 >> 2] | 0;
+   i5 = HEAP32[i11 >> 2] | 0;
+   i4 = ((i4 | 0) > (i5 | 0) ? i4 : i5) + 1 | 0;
+   HEAP32[i2 >> 2] = i4;
+   i2 = HEAP32[i12 >> 2] | 0;
+   i2 = (i4 | 0) > (i2 | 0) ? i4 : i2;
+  }
+  HEAP32[i3 >> 2] = i2 + 1;
+  i21 = i7;
+  STACKTOP = i1;
+  return i21 | 0;
+ }
+ if (!((i14 | 0) < -1)) {
+  i21 = i6;
+  STACKTOP = i1;
+  return i21 | 0;
+ }
+ i21 = i5 + (i8 * 36 | 0) + 24 | 0;
+ i14 = HEAP32[i21 >> 2] | 0;
+ i20 = i5 + (i8 * 36 | 0) + 28 | 0;
+ i15 = HEAP32[i20 >> 2] | 0;
+ i17 = i5 + (i14 * 36 | 0) | 0;
+ i16 = i5 + (i15 * 36 | 0) | 0;
+ if (!((i14 | 0) > -1 & (i14 | 0) < (i12 | 0))) {
+  ___assert_fail(3400, 2944, 467, 3232);
+ }
+ if (!((i15 | 0) > -1 & (i15 | 0) < (i12 | 0))) {
+  ___assert_fail(3432, 2944, 468, 3232);
+ }
+ HEAP32[i21 >> 2] = i6;
+ i21 = i5 + (i6 * 36 | 0) + 20 | 0;
+ i12 = i5 + (i8 * 36 | 0) + 20 | 0;
+ HEAP32[i12 >> 2] = HEAP32[i21 >> 2];
+ HEAP32[i21 >> 2] = i8;
+ i12 = HEAP32[i12 >> 2] | 0;
+ do {
+  if (!((i12 | 0) == -1)) {
+   i11 = i5 + (i12 * 36 | 0) + 24 | 0;
+   if ((HEAP32[i11 >> 2] | 0) == (i6 | 0)) {
+    HEAP32[i11 >> 2] = i8;
+    break;
+   }
+   i11 = i5 + (i12 * 36 | 0) + 28 | 0;
+   if ((HEAP32[i11 >> 2] | 0) == (i6 | 0)) {
+    HEAP32[i11 >> 2] = i8;
+    break;
+   } else {
+    ___assert_fail(3464, 2944, 484, 3232);
+   }
+  } else {
+   HEAP32[i11 >> 2] = i8;
+  }
+ } while (0);
+ i12 = i5 + (i14 * 36 | 0) + 32 | 0;
+ i11 = i5 + (i15 * 36 | 0) + 32 | 0;
+ if ((HEAP32[i12 >> 2] | 0) > (HEAP32[i11 >> 2] | 0)) {
+  HEAP32[i20 >> 2] = i14;
+  HEAP32[i18 >> 2] = i15;
+  HEAP32[i5 + (i15 * 36 | 0) + 20 >> 2] = i6;
+  d19 = +HEAPF32[i10 >> 2];
+  d22 = +HEAPF32[i16 >> 2];
+  d19 = d19 < d22 ? d19 : d22;
+  d23 = +HEAPF32[i5 + (i7 * 36 | 0) + 4 >> 2];
+  d22 = +HEAPF32[i5 + (i15 * 36 | 0) + 4 >> 2];
+  d24 = +d19;
+  d23 = +(d23 < d22 ? d23 : d22);
+  i21 = i13;
+  HEAPF32[i21 >> 2] = d24;
+  HEAPF32[i21 + 4 >> 2] = d23;
+  d23 = +HEAPF32[i5 + (i7 * 36 | 0) + 8 >> 2];
+  d22 = +HEAPF32[i5 + (i15 * 36 | 0) + 8 >> 2];
+  d24 = +HEAPF32[i5 + (i7 * 36 | 0) + 12 >> 2];
+  d25 = +HEAPF32[i5 + (i15 * 36 | 0) + 12 >> 2];
+  d22 = +(d23 > d22 ? d23 : d22);
+  d24 = +(d24 > d25 ? d24 : d25);
+  i21 = i5 + (i6 * 36 | 0) + 8 | 0;
+  HEAPF32[i21 >> 2] = d22;
+  HEAPF32[i21 + 4 >> 2] = d24;
+  d24 = +HEAPF32[i17 >> 2];
+  d23 = +HEAPF32[i5 + (i6 * 36 | 0) + 4 >> 2];
+  d22 = +HEAPF32[i5 + (i14 * 36 | 0) + 4 >> 2];
+  d19 = +(d19 < d24 ? d19 : d24);
+  d22 = +(d23 < d22 ? d23 : d22);
+  i21 = i9;
+  HEAPF32[i21 >> 2] = d19;
+  HEAPF32[i21 + 4 >> 2] = d22;
+  d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 8 >> 2];
+  d23 = +HEAPF32[i5 + (i14 * 36 | 0) + 8 >> 2];
+  d19 = +HEAPF32[i5 + (i6 * 36 | 0) + 12 >> 2];
+  d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 12 >> 2];
+  d22 = +(d22 > d23 ? d22 : d23);
+  d25 = +(d19 > d24 ? d19 : d24);
+  i5 = i5 + (i8 * 36 | 0) + 8 | 0;
+  HEAPF32[i5 >> 2] = d22;
+  HEAPF32[i5 + 4 >> 2] = d25;
+  i3 = HEAP32[i3 >> 2] | 0;
+  i5 = HEAP32[i11 >> 2] | 0;
+  i3 = ((i3 | 0) > (i5 | 0) ? i3 : i5) + 1 | 0;
+  HEAP32[i2 >> 2] = i3;
+  i2 = HEAP32[i12 >> 2] | 0;
+  i2 = (i3 | 0) > (i2 | 0) ? i3 : i2;
+ } else {
+  HEAP32[i20 >> 2] = i15;
+  HEAP32[i18 >> 2] = i14;
+  HEAP32[i5 + (i14 * 36 | 0) + 20 >> 2] = i6;
+  d19 = +HEAPF32[i10 >> 2];
+  d22 = +HEAPF32[i17 >> 2];
+  d19 = d19 < d22 ? d19 : d22;
+  d23 = +HEAPF32[i5 + (i7 * 36 | 0) + 4 >> 2];
+  d24 = +HEAPF32[i5 + (i14 * 36 | 0) + 4 >> 2];
+  d22 = +d19;
+  d24 = +(d23 < d24 ? d23 : d24);
+  i21 = i13;
+  HEAPF32[i21 >> 2] = d22;
+  HEAPF32[i21 + 4 >> 2] = d24;
+  d24 = +HEAPF32[i5 + (i7 * 36 | 0) + 8 >> 2];
+  d23 = +HEAPF32[i5 + (i14 * 36 | 0) + 8 >> 2];
+  d22 = +HEAPF32[i5 + (i7 * 36 | 0) + 12 >> 2];
+  d25 = +HEAPF32[i5 + (i14 * 36 | 0) + 12 >> 2];
+  d23 = +(d24 > d23 ? d24 : d23);
+  d24 = +(d22 > d25 ? d22 : d25);
+  i21 = i5 + (i6 * 36 | 0) + 8 | 0;
+  HEAPF32[i21 >> 2] = d23;
+  HEAPF32[i21 + 4 >> 2] = d24;
+  d24 = +HEAPF32[i16 >> 2];
+  d23 = +HEAPF32[i5 + (i6 * 36 | 0) + 4 >> 2];
+  d22 = +HEAPF32[i5 + (i15 * 36 | 0) + 4 >> 2];
+  d19 = +(d19 < d24 ? d19 : d24);
+  d22 = +(d23 < d22 ? d23 : d22);
+  i21 = i9;
+  HEAPF32[i21 >> 2] = d19;
+  HEAPF32[i21 + 4 >> 2] = d22;
+  d22 = +HEAPF32[i5 + (i6 * 36 | 0) + 8 >> 2];
+  d23 = +HEAPF32[i5 + (i15 * 36 | 0) + 8 >> 2];
+  d19 = +HEAPF32[i5 + (i6 * 36 | 0) + 12 >> 2];
+  d24 = +HEAPF32[i5 + (i15 * 36 | 0) + 12 >> 2];
+  d22 = +(d22 > d23 ? d22 : d23);
+  d25 = +(d19 > d24 ? d19 : d24);
+  i5 = i5 + (i8 * 36 | 0) + 8 | 0;
+  HEAPF32[i5 >> 2] = d22;
+  HEAPF32[i5 + 4 >> 2] = d25;
+  i3 = HEAP32[i3 >> 2] | 0;
+  i5 = HEAP32[i12 >> 2] | 0;
+  i3 = ((i3 | 0) > (i5 | 0) ? i3 : i5) + 1 | 0;
+  HEAP32[i2 >> 2] = i3;
+  i2 = HEAP32[i11 >> 2] | 0;
+  i2 = (i3 | 0) > (i2 | 0) ? i3 : i2;
+ }
+ HEAP32[i4 >> 2] = i2 + 1;
+ i21 = i8;
+ STACKTOP = i1;
+ return i21 | 0;
+}
+function __Z10b2DistanceP16b2DistanceOutputP14b2SimplexCachePK15b2DistanceInput(i2, i5, i3) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i6 = 0, d7 = 0.0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0, d22 = 0.0, i23 = 0, d24 = 0.0, d25 = 0.0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, d36 = 0.0, d37 = 0.0, d38 = 0.0, i39 = 0, i40 = 0, i41 = 0, i42 = 0, d43 = 0.0, d44 = 0.0, d45 = 0.0, i46 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 176 | 0;
+ i11 = i1 + 152 | 0;
+ i10 = i1 + 136 | 0;
+ i4 = i1 + 24 | 0;
+ i14 = i1 + 12 | 0;
+ i15 = i1;
+ HEAP32[652] = (HEAP32[652] | 0) + 1;
+ i9 = i3 + 28 | 0;
+ i31 = i3 + 56 | 0;
+ HEAP32[i11 + 0 >> 2] = HEAP32[i31 + 0 >> 2];
+ HEAP32[i11 + 4 >> 2] = HEAP32[i31 + 4 >> 2];
+ HEAP32[i11 + 8 >> 2] = HEAP32[i31 + 8 >> 2];
+ HEAP32[i11 + 12 >> 2] = HEAP32[i31 + 12 >> 2];
+ i31 = i3 + 72 | 0;
+ HEAP32[i10 + 0 >> 2] = HEAP32[i31 + 0 >> 2];
+ HEAP32[i10 + 4 >> 2] = HEAP32[i31 + 4 >> 2];
+ HEAP32[i10 + 8 >> 2] = HEAP32[i31 + 8 >> 2];
+ HEAP32[i10 + 12 >> 2] = HEAP32[i31 + 12 >> 2];
+ __ZN9b2Simplex9ReadCacheEPK14b2SimplexCachePK15b2DistanceProxyRK11b2TransformS5_S8_(i4, i5, i3, i11, i9, i10);
+ i9 = i4 + 108 | 0;
+ i31 = HEAP32[i9 >> 2] | 0;
+ if ((i31 | 0) == 3 | (i31 | 0) == 2 | (i31 | 0) == 1) {
+  i8 = i4 + 16 | 0;
+  i6 = i4 + 20 | 0;
+  d17 = +HEAPF32[i11 + 12 >> 2];
+  d18 = +HEAPF32[i11 + 8 >> 2];
+  i13 = i3 + 16 | 0;
+  i12 = i3 + 20 | 0;
+  d16 = +HEAPF32[i11 >> 2];
+  d21 = +HEAPF32[i11 + 4 >> 2];
+  d19 = +HEAPF32[i10 + 12 >> 2];
+  d22 = +HEAPF32[i10 + 8 >> 2];
+  i23 = i3 + 44 | 0;
+  i20 = i3 + 48 | 0;
+  d24 = +HEAPF32[i10 >> 2];
+  d25 = +HEAPF32[i10 + 4 >> 2];
+  i11 = i4 + 52 | 0;
+  i10 = i4 + 56 | 0;
+  i30 = i4 + 16 | 0;
+  i27 = i4 + 36 | 0;
+  i26 = i4 + 52 | 0;
+  i29 = i4 + 24 | 0;
+  i28 = i4 + 60 | 0;
+  i33 = 0;
+  L3 : while (1) {
+   i32 = (i31 | 0) > 0;
+   if (i32) {
+    i34 = 0;
+    do {
+     HEAP32[i14 + (i34 << 2) >> 2] = HEAP32[i4 + (i34 * 36 | 0) + 28 >> 2];
+     HEAP32[i15 + (i34 << 2) >> 2] = HEAP32[i4 + (i34 * 36 | 0) + 32 >> 2];
+     i34 = i34 + 1 | 0;
+    } while ((i34 | 0) != (i31 | 0));
+   }
+   do {
+    if ((i31 | 0) == 2) {
+     i46 = i30;
+     d45 = +HEAPF32[i46 >> 2];
+     d36 = +HEAPF32[i46 + 4 >> 2];
+     i46 = i26;
+     d38 = +HEAPF32[i46 >> 2];
+     d37 = +HEAPF32[i46 + 4 >> 2];
+     d43 = d38 - d45;
+     d44 = d37 - d36;
+     d36 = d45 * d43 + d36 * d44;
+     if (d36 >= -0.0) {
+      HEAPF32[i29 >> 2] = 1.0;
+      HEAP32[i9 >> 2] = 1;
+      i35 = 17;
+      break;
+     }
+     d37 = d38 * d43 + d37 * d44;
+     if (!(d37 <= 0.0)) {
+      d45 = 1.0 / (d37 - d36);
+      HEAPF32[i29 >> 2] = d37 * d45;
+      HEAPF32[i28 >> 2] = -(d36 * d45);
+      HEAP32[i9 >> 2] = 2;
+      i35 = 18;
+      break;
+     } else {
+      HEAPF32[i28 >> 2] = 1.0;
+      HEAP32[i9 >> 2] = 1;
+      i34 = i4 + 0 | 0;
+      i39 = i27 + 0 | 0;
+      i35 = i34 + 36 | 0;
+      do {
+       HEAP32[i34 >> 2] = HEAP32[i39 >> 2];
+       i34 = i34 + 4 | 0;
+       i39 = i39 + 4 | 0;
+      } while ((i34 | 0) < (i35 | 0));
+      i35 = 17;
+      break;
+     }
+    } else if ((i31 | 0) == 3) {
+     __ZN9b2Simplex6Solve3Ev(i4);
+     i34 = HEAP32[i9 >> 2] | 0;
+     if ((i34 | 0) == 1) {
+      i35 = 17;
+     } else if ((i34 | 0) == 0) {
+      i35 = 15;
+      break L3;
+     } else if ((i34 | 0) == 2) {
+      i35 = 18;
+     } else if ((i34 | 0) == 3) {
+      i35 = 42;
+      break L3;
+     } else {
+      i35 = 16;
+      break L3;
+     }
+    } else if ((i31 | 0) == 1) {
+     i35 = 17;
+    } else {
+     i35 = 13;
+     break L3;
+    }
+   } while (0);
+   do {
+    if ((i35 | 0) == 17) {
+     d36 = -+HEAPF32[i8 >> 2];
+     d37 = -+HEAPF32[i6 >> 2];
+     i34 = 1;
+    } else if ((i35 | 0) == 18) {
+     d44 = +HEAPF32[i8 >> 2];
+     d37 = +HEAPF32[i11 >> 2] - d44;
+     d45 = +HEAPF32[i6 >> 2];
+     d36 = +HEAPF32[i10 >> 2] - d45;
+     if (d44 * d36 - d37 * d45 > 0.0) {
+      d36 = -d36;
+      i34 = 2;
+      break;
+     } else {
+      d37 = -d37;
+      i34 = 2;
+      break;
+     }
+    }
+   } while (0);
+   if (d37 * d37 + d36 * d36 < 1.4210854715202004e-14) {
+    i35 = 42;
+    break;
+   }
+   i39 = i4 + (i34 * 36 | 0) | 0;
+   d44 = -d36;
+   d45 = -d37;
+   d43 = d17 * d44 + d18 * d45;
+   d44 = d17 * d45 - d18 * d44;
+   i40 = HEAP32[i13 >> 2] | 0;
+   i41 = HEAP32[i12 >> 2] | 0;
+   if ((i41 | 0) > 1) {
+    i42 = 0;
+    d45 = d44 * +HEAPF32[i40 + 4 >> 2] + d43 * +HEAPF32[i40 >> 2];
+    i46 = 1;
+    while (1) {
+     d38 = d43 * +HEAPF32[i40 + (i46 << 3) >> 2] + d44 * +HEAPF32[i40 + (i46 << 3) + 4 >> 2];
+     i35 = d38 > d45;
+     i42 = i35 ? i46 : i42;
+     i46 = i46 + 1 | 0;
+     if ((i46 | 0) == (i41 | 0)) {
+      break;
+     } else {
+      d45 = i35 ? d38 : d45;
+     }
+    }
+    i35 = i4 + (i34 * 36 | 0) + 28 | 0;
+    HEAP32[i35 >> 2] = i42;
+    if (!((i42 | 0) > -1)) {
+     i35 = 28;
+     break;
+    }
+   } else {
+    i35 = i4 + (i34 * 36 | 0) + 28 | 0;
+    HEAP32[i35 >> 2] = 0;
+    i42 = 0;
+   }
+   if ((i41 | 0) <= (i42 | 0)) {
+    i35 = 28;
+    break;
+   }
+   d45 = +HEAPF32[i40 + (i42 << 3) >> 2];
+   d43 = +HEAPF32[i40 + (i42 << 3) + 4 >> 2];
+   d38 = d16 + (d17 * d45 - d18 * d43);
+   d44 = +d38;
+   d43 = +(d45 * d18 + d17 * d43 + d21);
+   i40 = i39;
+   HEAPF32[i40 >> 2] = d44;
+   HEAPF32[i40 + 4 >> 2] = d43;
+   d43 = d36 * d19 + d37 * d22;
+   d44 = d37 * d19 - d36 * d22;
+   i40 = HEAP32[i23 >> 2] | 0;
+   i39 = HEAP32[i20 >> 2] | 0;
+   if ((i39 | 0) > 1) {
+    i41 = 0;
+    d37 = d44 * +HEAPF32[i40 + 4 >> 2] + d43 * +HEAPF32[i40 >> 2];
+    i42 = 1;
+    while (1) {
+     d36 = d43 * +HEAPF32[i40 + (i42 << 3) >> 2] + d44 * +HEAPF32[i40 + (i42 << 3) + 4 >> 2];
+     i46 = d36 > d37;
+     i41 = i46 ? i42 : i41;
+     i42 = i42 + 1 | 0;
+     if ((i42 | 0) == (i39 | 0)) {
+      break;
+     } else {
+      d37 = i46 ? d36 : d37;
+     }
+    }
+    i42 = i4 + (i34 * 36 | 0) + 32 | 0;
+    HEAP32[i42 >> 2] = i41;
+    if (!((i41 | 0) > -1)) {
+     i35 = 35;
+     break;
+    }
+   } else {
+    i42 = i4 + (i34 * 36 | 0) + 32 | 0;
+    HEAP32[i42 >> 2] = 0;
+    i41 = 0;
+   }
+   if ((i39 | 0) <= (i41 | 0)) {
+    i35 = 35;
+    break;
+   }
+   d37 = +HEAPF32[i40 + (i41 << 3) >> 2];
+   d45 = +HEAPF32[i40 + (i41 << 3) + 4 >> 2];
+   d44 = d24 + (d19 * d37 - d22 * d45);
+   d43 = +d44;
+   d45 = +(d37 * d22 + d19 * d45 + d25);
+   i46 = i4 + (i34 * 36 | 0) + 8 | 0;
+   HEAPF32[i46 >> 2] = d43;
+   HEAPF32[i46 + 4 >> 2] = d45;
+   d44 = +(d44 - d38);
+   d45 = +(+HEAPF32[i4 + (i34 * 36 | 0) + 12 >> 2] - +HEAPF32[i4 + (i34 * 36 | 0) + 4 >> 2]);
+   i46 = i4 + (i34 * 36 | 0) + 16 | 0;
+   HEAPF32[i46 >> 2] = d44;
+   HEAPF32[i46 + 4 >> 2] = d45;
+   i33 = i33 + 1 | 0;
+   HEAP32[654] = (HEAP32[654] | 0) + 1;
+   if (i32) {
+    i34 = HEAP32[i35 >> 2] | 0;
+    i32 = 0;
+    do {
+     if ((i34 | 0) == (HEAP32[i14 + (i32 << 2) >> 2] | 0) ? (HEAP32[i42 >> 2] | 0) == (HEAP32[i15 + (i32 << 2) >> 2] | 0) : 0) {
+      i35 = 42;
+      break L3;
+     }
+     i32 = i32 + 1 | 0;
+    } while ((i32 | 0) < (i31 | 0));
+   }
+   i31 = (HEAP32[i9 >> 2] | 0) + 1 | 0;
+   HEAP32[i9 >> 2] = i31;
+   if ((i33 | 0) >= 20) {
+    i35 = 42;
+    break;
+   }
+  }
+  if ((i35 | 0) == 13) {
+   ___assert_fail(2712, 2672, 498, 2720);
+  } else if ((i35 | 0) == 15) {
+   ___assert_fail(2712, 2672, 194, 2856);
+  } else if ((i35 | 0) == 16) {
+   ___assert_fail(2712, 2672, 207, 2856);
+  } else if ((i35 | 0) == 28) {
+   ___assert_fail(2776, 2808, 103, 2840);
+  } else if ((i35 | 0) == 35) {
+   ___assert_fail(2776, 2808, 103, 2840);
+  } else if ((i35 | 0) == 42) {
+   i12 = HEAP32[656] | 0;
+   HEAP32[656] = (i12 | 0) > (i33 | 0) ? i12 : i33;
+   i14 = i2 + 8 | 0;
+   __ZNK9b2Simplex16GetWitnessPointsEP6b2Vec2S1_(i4, i2, i14);
+   d44 = +HEAPF32[i2 >> 2] - +HEAPF32[i14 >> 2];
+   i13 = i2 + 4 | 0;
+   i12 = i2 + 12 | 0;
+   d45 = +HEAPF32[i13 >> 2] - +HEAPF32[i12 >> 2];
+   i15 = i2 + 16 | 0;
+   HEAPF32[i15 >> 2] = +Math_sqrt(+(d44 * d44 + d45 * d45));
+   HEAP32[i2 + 20 >> 2] = i33;
+   i9 = HEAP32[i9 >> 2] | 0;
+   if ((i9 | 0) == 2) {
+    d45 = +HEAPF32[i8 >> 2] - +HEAPF32[i11 >> 2];
+    d7 = +HEAPF32[i6 >> 2] - +HEAPF32[i10 >> 2];
+    d7 = +Math_sqrt(+(d45 * d45 + d7 * d7));
+   } else if ((i9 | 0) == 3) {
+    d7 = +HEAPF32[i8 >> 2];
+    d45 = +HEAPF32[i6 >> 2];
+    d7 = (+HEAPF32[i11 >> 2] - d7) * (+HEAPF32[i4 + 92 >> 2] - d45) - (+HEAPF32[i10 >> 2] - d45) * (+HEAPF32[i4 + 88 >> 2] - d7);
+   } else if ((i9 | 0) == 1) {
+    d7 = 0.0;
+   } else if ((i9 | 0) == 0) {
+    ___assert_fail(2712, 2672, 246, 2736);
+   } else {
+    ___assert_fail(2712, 2672, 259, 2736);
+   }
+   HEAPF32[i5 >> 2] = d7;
+   HEAP16[i5 + 4 >> 1] = i9;
+   i6 = 0;
+   do {
+    HEAP8[i5 + i6 + 6 | 0] = HEAP32[i4 + (i6 * 36 | 0) + 28 >> 2];
+    HEAP8[i5 + i6 + 9 | 0] = HEAP32[i4 + (i6 * 36 | 0) + 32 >> 2];
+    i6 = i6 + 1 | 0;
+   } while ((i6 | 0) < (i9 | 0));
+   if ((HEAP8[i3 + 88 | 0] | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   d7 = +HEAPF32[i3 + 24 >> 2];
+   d16 = +HEAPF32[i3 + 52 >> 2];
+   d18 = +HEAPF32[i15 >> 2];
+   d17 = d7 + d16;
+   if (!(d18 > d17 & d18 > 1.1920928955078125e-7)) {
+    d44 = +((+HEAPF32[i2 >> 2] + +HEAPF32[i14 >> 2]) * .5);
+    d45 = +((+HEAPF32[i13 >> 2] + +HEAPF32[i12 >> 2]) * .5);
+    i46 = i2;
+    HEAPF32[i46 >> 2] = d44;
+    HEAPF32[i46 + 4 >> 2] = d45;
+    i46 = i14;
+    HEAPF32[i46 >> 2] = d44;
+    HEAPF32[i46 + 4 >> 2] = d45;
+    HEAPF32[i15 >> 2] = 0.0;
+    STACKTOP = i1;
+    return;
+   }
+   HEAPF32[i15 >> 2] = d18 - d17;
+   d18 = +HEAPF32[i14 >> 2];
+   d21 = +HEAPF32[i2 >> 2];
+   d24 = d18 - d21;
+   d17 = +HEAPF32[i12 >> 2];
+   d19 = +HEAPF32[i13 >> 2];
+   d22 = d17 - d19;
+   d25 = +Math_sqrt(+(d24 * d24 + d22 * d22));
+   if (!(d25 < 1.1920928955078125e-7)) {
+    d45 = 1.0 / d25;
+    d24 = d24 * d45;
+    d22 = d22 * d45;
+   }
+   HEAPF32[i2 >> 2] = d7 * d24 + d21;
+   HEAPF32[i13 >> 2] = d7 * d22 + d19;
+   HEAPF32[i14 >> 2] = d18 - d16 * d24;
+   HEAPF32[i12 >> 2] = d17 - d16 * d22;
+   STACKTOP = i1;
+   return;
+  }
+ } else if ((i31 | 0) == 0) {
+  ___assert_fail(2712, 2672, 194, 2856);
+ } else {
+  ___assert_fail(2712, 2672, 207, 2856);
+ }
+}
+function __ZN8b2Island5SolveEP9b2ProfileRK10b2TimeStepRK6b2Vec2b(i4, i8, i11, i17, i7) {
+ i4 = i4 | 0;
+ i8 = i8 | 0;
+ i11 = i11 | 0;
+ i17 = i17 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, d5 = 0.0, i6 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i18 = 0, i19 = 0, i20 = 0, d21 = 0.0, i22 = 0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, d29 = 0.0, i30 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 160 | 0;
+ i6 = i3 + 128 | 0;
+ i9 = i3 + 148 | 0;
+ i10 = i3 + 96 | 0;
+ i16 = i3 + 52 | 0;
+ i2 = i3;
+ __ZN7b2TimerC2Ev(i9);
+ d5 = +HEAPF32[i11 >> 2];
+ i1 = i4 + 28 | 0;
+ if ((HEAP32[i1 >> 2] | 0) > 0) {
+  i13 = i4 + 8 | 0;
+  i12 = i17 + 4 | 0;
+  i15 = i4 + 20 | 0;
+  i14 = i4 + 24 | 0;
+  i19 = 0;
+  do {
+   i22 = HEAP32[(HEAP32[i13 >> 2] | 0) + (i19 << 2) >> 2] | 0;
+   i18 = i22 + 44 | 0;
+   i20 = HEAP32[i18 >> 2] | 0;
+   i18 = HEAP32[i18 + 4 >> 2] | 0;
+   d21 = +HEAPF32[i22 + 56 >> 2];
+   i30 = i22 + 64 | 0;
+   d27 = +HEAPF32[i30 >> 2];
+   d24 = +HEAPF32[i30 + 4 >> 2];
+   d23 = +HEAPF32[i22 + 72 >> 2];
+   i30 = i22 + 36 | 0;
+   HEAP32[i30 >> 2] = i20;
+   HEAP32[i30 + 4 >> 2] = i18;
+   HEAPF32[i22 + 52 >> 2] = d21;
+   if ((HEAP32[i22 >> 2] | 0) == 2) {
+    d25 = +HEAPF32[i22 + 140 >> 2];
+    d26 = +HEAPF32[i22 + 120 >> 2];
+    d28 = 1.0 - d5 * +HEAPF32[i22 + 132 >> 2];
+    d28 = d28 < 1.0 ? d28 : 1.0;
+    d28 = d28 < 0.0 ? 0.0 : d28;
+    d29 = 1.0 - d5 * +HEAPF32[i22 + 136 >> 2];
+    d29 = d29 < 1.0 ? d29 : 1.0;
+    d27 = (d27 + d5 * (d25 * +HEAPF32[i17 >> 2] + d26 * +HEAPF32[i22 + 76 >> 2])) * d28;
+    d24 = (d24 + d5 * (d25 * +HEAPF32[i12 >> 2] + d26 * +HEAPF32[i22 + 80 >> 2])) * d28;
+    d23 = (d23 + d5 * +HEAPF32[i22 + 128 >> 2] * +HEAPF32[i22 + 84 >> 2]) * (d29 < 0.0 ? 0.0 : d29);
+   }
+   i30 = (HEAP32[i15 >> 2] | 0) + (i19 * 12 | 0) | 0;
+   HEAP32[i30 >> 2] = i20;
+   HEAP32[i30 + 4 >> 2] = i18;
+   HEAPF32[(HEAP32[i15 >> 2] | 0) + (i19 * 12 | 0) + 8 >> 2] = d21;
+   d28 = +d27;
+   d29 = +d24;
+   i30 = (HEAP32[i14 >> 2] | 0) + (i19 * 12 | 0) | 0;
+   HEAPF32[i30 >> 2] = d28;
+   HEAPF32[i30 + 4 >> 2] = d29;
+   HEAPF32[(HEAP32[i14 >> 2] | 0) + (i19 * 12 | 0) + 8 >> 2] = d23;
+   i19 = i19 + 1 | 0;
+  } while ((i19 | 0) < (HEAP32[i1 >> 2] | 0));
+ } else {
+  i14 = i4 + 24 | 0;
+  i15 = i4 + 20 | 0;
+ }
+ HEAP32[i10 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+ HEAP32[i10 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+ HEAP32[i10 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+ HEAP32[i10 + 12 >> 2] = HEAP32[i11 + 12 >> 2];
+ HEAP32[i10 + 16 >> 2] = HEAP32[i11 + 16 >> 2];
+ HEAP32[i10 + 20 >> 2] = HEAP32[i11 + 20 >> 2];
+ i22 = HEAP32[i15 >> 2] | 0;
+ HEAP32[i10 + 24 >> 2] = i22;
+ i30 = HEAP32[i14 >> 2] | 0;
+ HEAP32[i10 + 28 >> 2] = i30;
+ HEAP32[i16 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+ HEAP32[i16 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+ HEAP32[i16 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+ HEAP32[i16 + 12 >> 2] = HEAP32[i11 + 12 >> 2];
+ HEAP32[i16 + 16 >> 2] = HEAP32[i11 + 16 >> 2];
+ HEAP32[i16 + 20 >> 2] = HEAP32[i11 + 20 >> 2];
+ i13 = i4 + 12 | 0;
+ HEAP32[i16 + 24 >> 2] = HEAP32[i13 >> 2];
+ i12 = i4 + 36 | 0;
+ HEAP32[i16 + 28 >> 2] = HEAP32[i12 >> 2];
+ HEAP32[i16 + 32 >> 2] = i22;
+ HEAP32[i16 + 36 >> 2] = i30;
+ HEAP32[i16 + 40 >> 2] = HEAP32[i4 >> 2];
+ __ZN15b2ContactSolverC2EP18b2ContactSolverDef(i2, i16);
+ __ZN15b2ContactSolver29InitializeVelocityConstraintsEv(i2);
+ if ((HEAP8[i11 + 20 | 0] | 0) != 0) {
+  __ZN15b2ContactSolver9WarmStartEv(i2);
+ }
+ i16 = i4 + 32 | 0;
+ if ((HEAP32[i16 >> 2] | 0) > 0) {
+  i18 = i4 + 16 | 0;
+  i17 = 0;
+  do {
+   i30 = HEAP32[(HEAP32[i18 >> 2] | 0) + (i17 << 2) >> 2] | 0;
+   FUNCTION_TABLE_vii[HEAP32[(HEAP32[i30 >> 2] | 0) + 28 >> 2] & 15](i30, i10);
+   i17 = i17 + 1 | 0;
+  } while ((i17 | 0) < (HEAP32[i16 >> 2] | 0));
+ }
+ HEAPF32[i8 + 12 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i9);
+ i17 = i11 + 12 | 0;
+ if ((HEAP32[i17 >> 2] | 0) > 0) {
+  i20 = i4 + 16 | 0;
+  i19 = 0;
+  do {
+   if ((HEAP32[i16 >> 2] | 0) > 0) {
+    i18 = 0;
+    do {
+     i30 = HEAP32[(HEAP32[i20 >> 2] | 0) + (i18 << 2) >> 2] | 0;
+     FUNCTION_TABLE_vii[HEAP32[(HEAP32[i30 >> 2] | 0) + 32 >> 2] & 15](i30, i10);
+     i18 = i18 + 1 | 0;
+    } while ((i18 | 0) < (HEAP32[i16 >> 2] | 0));
+   }
+   __ZN15b2ContactSolver24SolveVelocityConstraintsEv(i2);
+   i19 = i19 + 1 | 0;
+  } while ((i19 | 0) < (HEAP32[i17 >> 2] | 0));
+ }
+ __ZN15b2ContactSolver13StoreImpulsesEv(i2);
+ HEAPF32[i8 + 16 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i9);
+ if ((HEAP32[i1 >> 2] | 0) > 0) {
+  i19 = HEAP32[i14 >> 2] | 0;
+  i18 = 0;
+  do {
+   i30 = HEAP32[i15 >> 2] | 0;
+   i17 = i30 + (i18 * 12 | 0) | 0;
+   i22 = i17;
+   d23 = +HEAPF32[i22 >> 2];
+   d21 = +HEAPF32[i22 + 4 >> 2];
+   d24 = +HEAPF32[i30 + (i18 * 12 | 0) + 8 >> 2];
+   i30 = i19 + (i18 * 12 | 0) | 0;
+   d26 = +HEAPF32[i30 >> 2];
+   d27 = +HEAPF32[i30 + 4 >> 2];
+   d25 = +HEAPF32[i19 + (i18 * 12 | 0) + 8 >> 2];
+   d29 = d5 * d26;
+   d28 = d5 * d27;
+   d28 = d29 * d29 + d28 * d28;
+   if (d28 > 4.0) {
+    d29 = 2.0 / +Math_sqrt(+d28);
+    d26 = d26 * d29;
+    d27 = d27 * d29;
+   }
+   d28 = d5 * d25;
+   if (d28 * d28 > 2.4674012660980225) {
+    if (!(d28 > 0.0)) {
+     d28 = -d28;
+    }
+    d25 = d25 * (1.5707963705062866 / d28);
+   }
+   d29 = +(d23 + d5 * d26);
+   d28 = +(d21 + d5 * d27);
+   i19 = i17;
+   HEAPF32[i19 >> 2] = d29;
+   HEAPF32[i19 + 4 >> 2] = d28;
+   HEAPF32[(HEAP32[i15 >> 2] | 0) + (i18 * 12 | 0) + 8 >> 2] = d24 + d5 * d25;
+   d28 = +d26;
+   d29 = +d27;
+   i19 = (HEAP32[i14 >> 2] | 0) + (i18 * 12 | 0) | 0;
+   HEAPF32[i19 >> 2] = d28;
+   HEAPF32[i19 + 4 >> 2] = d29;
+   i19 = HEAP32[i14 >> 2] | 0;
+   HEAPF32[i19 + (i18 * 12 | 0) + 8 >> 2] = d25;
+   i18 = i18 + 1 | 0;
+  } while ((i18 | 0) < (HEAP32[i1 >> 2] | 0));
+ }
+ i11 = i11 + 16 | 0;
+ L41 : do {
+  if ((HEAP32[i11 >> 2] | 0) > 0) {
+   i17 = i4 + 16 | 0;
+   i19 = 0;
+   while (1) {
+    i18 = __ZN15b2ContactSolver24SolvePositionConstraintsEv(i2) | 0;
+    if ((HEAP32[i16 >> 2] | 0) > 0) {
+     i20 = 0;
+     i22 = 1;
+     do {
+      i30 = HEAP32[(HEAP32[i17 >> 2] | 0) + (i20 << 2) >> 2] | 0;
+      i22 = i22 & (FUNCTION_TABLE_iii[HEAP32[(HEAP32[i30 >> 2] | 0) + 36 >> 2] & 3](i30, i10) | 0);
+      i20 = i20 + 1 | 0;
+     } while ((i20 | 0) < (HEAP32[i16 >> 2] | 0));
+    } else {
+     i22 = 1;
+    }
+    i19 = i19 + 1 | 0;
+    if (i18 & i22) {
+     i10 = 0;
+     break L41;
+    }
+    if ((i19 | 0) >= (HEAP32[i11 >> 2] | 0)) {
+     i10 = 1;
+     break;
+    }
+   }
+  } else {
+   i10 = 1;
+  }
+ } while (0);
+ if ((HEAP32[i1 >> 2] | 0) > 0) {
+  i11 = i4 + 8 | 0;
+  i16 = 0;
+  do {
+   i30 = HEAP32[(HEAP32[i11 >> 2] | 0) + (i16 << 2) >> 2] | 0;
+   i22 = (HEAP32[i15 >> 2] | 0) + (i16 * 12 | 0) | 0;
+   i20 = HEAP32[i22 >> 2] | 0;
+   i22 = HEAP32[i22 + 4 >> 2] | 0;
+   i17 = i30 + 44 | 0;
+   HEAP32[i17 >> 2] = i20;
+   HEAP32[i17 + 4 >> 2] = i22;
+   d27 = +HEAPF32[(HEAP32[i15 >> 2] | 0) + (i16 * 12 | 0) + 8 >> 2];
+   HEAPF32[i30 + 56 >> 2] = d27;
+   i17 = (HEAP32[i14 >> 2] | 0) + (i16 * 12 | 0) | 0;
+   i18 = HEAP32[i17 + 4 >> 2] | 0;
+   i19 = i30 + 64 | 0;
+   HEAP32[i19 >> 2] = HEAP32[i17 >> 2];
+   HEAP32[i19 + 4 >> 2] = i18;
+   HEAPF32[i30 + 72 >> 2] = +HEAPF32[(HEAP32[i14 >> 2] | 0) + (i16 * 12 | 0) + 8 >> 2];
+   d25 = +Math_sin(+d27);
+   HEAPF32[i30 + 20 >> 2] = d25;
+   d27 = +Math_cos(+d27);
+   HEAPF32[i30 + 24 >> 2] = d27;
+   d26 = +HEAPF32[i30 + 28 >> 2];
+   d29 = +HEAPF32[i30 + 32 >> 2];
+   d28 = (HEAP32[tempDoublePtr >> 2] = i20, +HEAPF32[tempDoublePtr >> 2]) - (d27 * d26 - d25 * d29);
+   d29 = (HEAP32[tempDoublePtr >> 2] = i22, +HEAPF32[tempDoublePtr >> 2]) - (d25 * d26 + d27 * d29);
+   d28 = +d28;
+   d29 = +d29;
+   i30 = i30 + 12 | 0;
+   HEAPF32[i30 >> 2] = d28;
+   HEAPF32[i30 + 4 >> 2] = d29;
+   i16 = i16 + 1 | 0;
+  } while ((i16 | 0) < (HEAP32[i1 >> 2] | 0));
+ }
+ HEAPF32[i8 + 20 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i9);
+ i9 = HEAP32[i2 + 40 >> 2] | 0;
+ i8 = i4 + 4 | 0;
+ if ((HEAP32[i8 >> 2] | 0) != 0 ? (HEAP32[i12 >> 2] | 0) > 0 : 0) {
+  i11 = i6 + 16 | 0;
+  i14 = 0;
+  do {
+   i15 = HEAP32[(HEAP32[i13 >> 2] | 0) + (i14 << 2) >> 2] | 0;
+   i16 = HEAP32[i9 + (i14 * 152 | 0) + 144 >> 2] | 0;
+   HEAP32[i11 >> 2] = i16;
+   if ((i16 | 0) > 0) {
+    i17 = 0;
+    do {
+     HEAPF32[i6 + (i17 << 2) >> 2] = +HEAPF32[i9 + (i14 * 152 | 0) + (i17 * 36 | 0) + 16 >> 2];
+     HEAPF32[i6 + (i17 << 2) + 8 >> 2] = +HEAPF32[i9 + (i14 * 152 | 0) + (i17 * 36 | 0) + 20 >> 2];
+     i17 = i17 + 1 | 0;
+    } while ((i17 | 0) != (i16 | 0));
+   }
+   i30 = HEAP32[i8 >> 2] | 0;
+   FUNCTION_TABLE_viii[HEAP32[(HEAP32[i30 >> 2] | 0) + 20 >> 2] & 3](i30, i15, i6);
+   i14 = i14 + 1 | 0;
+  } while ((i14 | 0) < (HEAP32[i12 >> 2] | 0));
+ }
+ if (!i7) {
+  __ZN15b2ContactSolverD2Ev(i2);
+  STACKTOP = i3;
+  return;
+ }
+ i7 = HEAP32[i1 >> 2] | 0;
+ i6 = (i7 | 0) > 0;
+ if (i6) {
+  i8 = HEAP32[i4 + 8 >> 2] | 0;
+  i9 = 0;
+  d21 = 3.4028234663852886e+38;
+  do {
+   i11 = HEAP32[i8 + (i9 << 2) >> 2] | 0;
+   do {
+    if ((HEAP32[i11 >> 2] | 0) != 0) {
+     if ((!((HEAP16[i11 + 4 >> 1] & 4) == 0) ? (d29 = +HEAPF32[i11 + 72 >> 2], !(d29 * d29 > .001218469929881394)) : 0) ? (d28 = +HEAPF32[i11 + 64 >> 2], d29 = +HEAPF32[i11 + 68 >> 2], !(d28 * d28 + d29 * d29 > 9999999747378752.0e-20)) : 0) {
+      i30 = i11 + 144 | 0;
+      d23 = d5 + +HEAPF32[i30 >> 2];
+      HEAPF32[i30 >> 2] = d23;
+      d21 = d21 < d23 ? d21 : d23;
+      break;
+     }
+     HEAPF32[i11 + 144 >> 2] = 0.0;
+     d21 = 0.0;
+    }
+   } while (0);
+   i9 = i9 + 1 | 0;
+  } while ((i9 | 0) < (i7 | 0));
+ } else {
+  d21 = 3.4028234663852886e+38;
+ }
+ if (!(d21 >= .5) | i10 | i6 ^ 1) {
+  __ZN15b2ContactSolverD2Ev(i2);
+  STACKTOP = i3;
+  return;
+ }
+ i4 = i4 + 8 | 0;
+ i6 = 0;
+ do {
+  i30 = HEAP32[(HEAP32[i4 >> 2] | 0) + (i6 << 2) >> 2] | 0;
+  i22 = i30 + 4 | 0;
+  HEAP16[i22 >> 1] = HEAP16[i22 >> 1] & 65533;
+  HEAPF32[i30 + 144 >> 2] = 0.0;
+  i30 = i30 + 64 | 0;
+  HEAP32[i30 + 0 >> 2] = 0;
+  HEAP32[i30 + 4 >> 2] = 0;
+  HEAP32[i30 + 8 >> 2] = 0;
+  HEAP32[i30 + 12 >> 2] = 0;
+  HEAP32[i30 + 16 >> 2] = 0;
+  HEAP32[i30 + 20 >> 2] = 0;
+  i6 = i6 + 1 | 0;
+ } while ((i6 | 0) < (HEAP32[i1 >> 2] | 0));
+ __ZN15b2ContactSolverD2Ev(i2);
+ STACKTOP = i3;
+ return;
+}
+function __ZN15b2ContactSolver24SolveVelocityConstraintsEv(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, i19 = 0, d20 = 0.0, d21 = 0.0, i22 = 0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, d31 = 0.0, i32 = 0, i33 = 0, d34 = 0.0, d35 = 0.0, d36 = 0.0, d37 = 0.0, d38 = 0.0, d39 = 0.0, d40 = 0.0, i41 = 0, i42 = 0, d43 = 0.0, d44 = 0.0;
+ i1 = STACKTOP;
+ i2 = i4 + 48 | 0;
+ if ((HEAP32[i2 >> 2] | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i4 + 40 | 0;
+ i4 = i4 + 28 | 0;
+ i42 = HEAP32[i4 >> 2] | 0;
+ i5 = 0;
+ L4 : while (1) {
+  i19 = HEAP32[i3 >> 2] | 0;
+  i22 = i19 + (i5 * 152 | 0) | 0;
+  i8 = HEAP32[i19 + (i5 * 152 | 0) + 112 >> 2] | 0;
+  i6 = HEAP32[i19 + (i5 * 152 | 0) + 116 >> 2] | 0;
+  d12 = +HEAPF32[i19 + (i5 * 152 | 0) + 120 >> 2];
+  d10 = +HEAPF32[i19 + (i5 * 152 | 0) + 128 >> 2];
+  d11 = +HEAPF32[i19 + (i5 * 152 | 0) + 124 >> 2];
+  d9 = +HEAPF32[i19 + (i5 * 152 | 0) + 132 >> 2];
+  i32 = i19 + (i5 * 152 | 0) + 144 | 0;
+  i33 = HEAP32[i32 >> 2] | 0;
+  i7 = i42 + (i8 * 12 | 0) | 0;
+  i41 = i7;
+  d21 = +HEAPF32[i41 >> 2];
+  d20 = +HEAPF32[i41 + 4 >> 2];
+  i41 = i42 + (i6 * 12 | 0) | 0;
+  d14 = +HEAPF32[i41 >> 2];
+  d13 = +HEAPF32[i41 + 4 >> 2];
+  i41 = i19 + (i5 * 152 | 0) + 72 | 0;
+  d17 = +HEAPF32[i41 >> 2];
+  d16 = +HEAPF32[i41 + 4 >> 2];
+  d23 = -d17;
+  d24 = +HEAPF32[i19 + (i5 * 152 | 0) + 136 >> 2];
+  if ((i33 + -1 | 0) >>> 0 < 2) {
+   i41 = 0;
+   d18 = +HEAPF32[i42 + (i8 * 12 | 0) + 8 >> 2];
+   d15 = +HEAPF32[i42 + (i6 * 12 | 0) + 8 >> 2];
+  } else {
+   i2 = 4;
+   break;
+  }
+  do {
+   d30 = +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 12 >> 2];
+   d25 = +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 8 >> 2];
+   d26 = +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 4 >> 2];
+   d27 = +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) >> 2];
+   d34 = d24 * +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 16 >> 2];
+   i42 = i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 20 | 0;
+   d28 = +HEAPF32[i42 >> 2];
+   d31 = d28 - +HEAPF32[i19 + (i5 * 152 | 0) + (i41 * 36 | 0) + 28 >> 2] * (d16 * (d14 - d15 * d30 - d21 + d18 * d26) + (d13 + d15 * d25 - d20 - d18 * d27) * d23);
+   d29 = -d34;
+   d31 = d31 < d34 ? d31 : d34;
+   d40 = d31 < d29 ? d29 : d31;
+   d39 = d40 - d28;
+   HEAPF32[i42 >> 2] = d40;
+   d40 = d16 * d39;
+   d39 = d39 * d23;
+   d21 = d21 - d12 * d40;
+   d20 = d20 - d12 * d39;
+   d18 = d18 - d10 * (d27 * d39 - d26 * d40);
+   d14 = d14 + d11 * d40;
+   d13 = d13 + d11 * d39;
+   d15 = d15 + d9 * (d25 * d39 - d30 * d40);
+   i41 = i41 + 1 | 0;
+  } while ((i41 | 0) != (i33 | 0));
+  do {
+   if ((HEAP32[i32 >> 2] | 0) != 1) {
+    i32 = i19 + (i5 * 152 | 0) + 16 | 0;
+    d31 = +HEAPF32[i32 >> 2];
+    i33 = i19 + (i5 * 152 | 0) + 52 | 0;
+    d34 = +HEAPF32[i33 >> 2];
+    if (!(d31 >= 0.0) | !(d34 >= 0.0)) {
+     i2 = 9;
+     break L4;
+    }
+    d23 = +HEAPF32[i19 + (i5 * 152 | 0) + 12 >> 2];
+    d24 = +HEAPF32[i19 + (i5 * 152 | 0) + 8 >> 2];
+    d26 = +HEAPF32[i19 + (i5 * 152 | 0) + 4 >> 2];
+    d30 = +HEAPF32[i22 >> 2];
+    d27 = +HEAPF32[i19 + (i5 * 152 | 0) + 48 >> 2];
+    d25 = +HEAPF32[i19 + (i5 * 152 | 0) + 44 >> 2];
+    d28 = +HEAPF32[i19 + (i5 * 152 | 0) + 40 >> 2];
+    d29 = +HEAPF32[i19 + (i5 * 152 | 0) + 36 >> 2];
+    d37 = +HEAPF32[i19 + (i5 * 152 | 0) + 104 >> 2];
+    d38 = +HEAPF32[i19 + (i5 * 152 | 0) + 100 >> 2];
+    d35 = d17 * (d14 - d15 * d23 - d21 + d18 * d26) + d16 * (d13 + d15 * d24 - d20 - d18 * d30) - +HEAPF32[i19 + (i5 * 152 | 0) + 32 >> 2] - (d31 * +HEAPF32[i19 + (i5 * 152 | 0) + 96 >> 2] + d34 * d37);
+    d36 = d17 * (d14 - d15 * d27 - d21 + d18 * d28) + d16 * (d13 + d15 * d25 - d20 - d18 * d29) - +HEAPF32[i19 + (i5 * 152 | 0) + 68 >> 2] - (d31 * d38 + d34 * +HEAPF32[i19 + (i5 * 152 | 0) + 108 >> 2]);
+    d44 = +HEAPF32[i19 + (i5 * 152 | 0) + 80 >> 2] * d35 + +HEAPF32[i19 + (i5 * 152 | 0) + 88 >> 2] * d36;
+    d43 = d35 * +HEAPF32[i19 + (i5 * 152 | 0) + 84 >> 2] + d36 * +HEAPF32[i19 + (i5 * 152 | 0) + 92 >> 2];
+    d40 = -d44;
+    d39 = -d43;
+    if (!(!(d44 <= -0.0) | !(d43 <= -0.0))) {
+     d37 = d40 - d31;
+     d43 = d39 - d34;
+     d38 = d17 * d37;
+     d37 = d16 * d37;
+     d44 = d17 * d43;
+     d43 = d16 * d43;
+     d35 = d38 + d44;
+     d36 = d37 + d43;
+     HEAPF32[i32 >> 2] = d40;
+     HEAPF32[i33 >> 2] = d39;
+     d21 = d21 - d12 * d35;
+     d20 = d20 - d12 * d36;
+     d14 = d14 + d11 * d35;
+     d13 = d13 + d11 * d36;
+     d18 = d18 - d10 * (d30 * d37 - d26 * d38 + (d29 * d43 - d28 * d44));
+     d15 = d15 + d9 * (d24 * d37 - d23 * d38 + (d25 * d43 - d27 * d44));
+     break;
+    }
+    d44 = d35 * +HEAPF32[i19 + (i5 * 152 | 0) + 24 >> 2];
+    d39 = -d44;
+    if (d44 <= -0.0 ? d36 + d38 * d39 >= 0.0 : 0) {
+     d38 = d39 - d31;
+     d43 = 0.0 - d34;
+     d40 = d17 * d38;
+     d38 = d16 * d38;
+     d44 = d17 * d43;
+     d43 = d16 * d43;
+     d36 = d44 + d40;
+     d37 = d43 + d38;
+     HEAPF32[i32 >> 2] = d39;
+     HEAPF32[i33 >> 2] = 0.0;
+     d21 = d21 - d12 * d36;
+     d20 = d20 - d12 * d37;
+     d14 = d14 + d11 * d36;
+     d13 = d13 + d11 * d37;
+     d18 = d18 - d10 * (d38 * d30 - d40 * d26 + (d43 * d29 - d44 * d28));
+     d15 = d15 + d9 * (d38 * d24 - d40 * d23 + (d43 * d25 - d44 * d27));
+     break;
+    }
+    d44 = d36 * +HEAPF32[i19 + (i5 * 152 | 0) + 60 >> 2];
+    d38 = -d44;
+    if (d44 <= -0.0 ? d35 + d37 * d38 >= 0.0 : 0) {
+     d39 = 0.0 - d31;
+     d43 = d38 - d34;
+     d40 = d17 * d39;
+     d39 = d16 * d39;
+     d44 = d17 * d43;
+     d43 = d16 * d43;
+     d36 = d40 + d44;
+     d37 = d39 + d43;
+     HEAPF32[i32 >> 2] = 0.0;
+     HEAPF32[i33 >> 2] = d38;
+     d21 = d21 - d12 * d36;
+     d20 = d20 - d12 * d37;
+     d14 = d14 + d11 * d36;
+     d13 = d13 + d11 * d37;
+     d18 = d18 - d10 * (d39 * d30 - d40 * d26 + (d43 * d29 - d44 * d28));
+     d15 = d15 + d9 * (d39 * d24 - d40 * d23 + (d43 * d25 - d44 * d27));
+     break;
+    }
+    if (!(!(d35 >= 0.0) | !(d36 >= 0.0))) {
+     d39 = 0.0 - d31;
+     d43 = 0.0 - d34;
+     d40 = d17 * d39;
+     d39 = d16 * d39;
+     d44 = d17 * d43;
+     d43 = d16 * d43;
+     d37 = d40 + d44;
+     d38 = d39 + d43;
+     HEAPF32[i32 >> 2] = 0.0;
+     HEAPF32[i33 >> 2] = 0.0;
+     d21 = d21 - d12 * d37;
+     d20 = d20 - d12 * d38;
+     d14 = d14 + d11 * d37;
+     d13 = d13 + d11 * d38;
+     d18 = d18 - d10 * (d39 * d30 - d40 * d26 + (d43 * d29 - d44 * d28));
+     d15 = d15 + d9 * (d39 * d24 - d40 * d23 + (d43 * d25 - d44 * d27));
+    }
+   } else {
+    d23 = +HEAPF32[i19 + (i5 * 152 | 0) + 12 >> 2];
+    d24 = +HEAPF32[i19 + (i5 * 152 | 0) + 8 >> 2];
+    d25 = +HEAPF32[i19 + (i5 * 152 | 0) + 4 >> 2];
+    d26 = +HEAPF32[i22 >> 2];
+    i22 = i19 + (i5 * 152 | 0) + 16 | 0;
+    d27 = +HEAPF32[i22 >> 2];
+    d28 = d27 - +HEAPF32[i19 + (i5 * 152 | 0) + 24 >> 2] * (d17 * (d14 - d15 * d23 - d21 + d18 * d25) + d16 * (d13 + d15 * d24 - d20 - d18 * d26) - +HEAPF32[i19 + (i5 * 152 | 0) + 32 >> 2]);
+    d44 = d28 > 0.0 ? d28 : 0.0;
+    d43 = d44 - d27;
+    HEAPF32[i22 >> 2] = d44;
+    d44 = d17 * d43;
+    d43 = d16 * d43;
+    d21 = d21 - d12 * d44;
+    d20 = d20 - d12 * d43;
+    d14 = d14 + d11 * d44;
+    d13 = d13 + d11 * d43;
+    d18 = d18 - d10 * (d26 * d43 - d25 * d44);
+    d15 = d15 + d9 * (d24 * d43 - d23 * d44);
+   }
+  } while (0);
+  d44 = +d21;
+  d43 = +d20;
+  i42 = i7;
+  HEAPF32[i42 >> 2] = d44;
+  HEAPF32[i42 + 4 >> 2] = d43;
+  i42 = HEAP32[i4 >> 2] | 0;
+  HEAPF32[i42 + (i8 * 12 | 0) + 8 >> 2] = d18;
+  d43 = +d14;
+  d44 = +d13;
+  i42 = i42 + (i6 * 12 | 0) | 0;
+  HEAPF32[i42 >> 2] = d43;
+  HEAPF32[i42 + 4 >> 2] = d44;
+  i42 = HEAP32[i4 >> 2] | 0;
+  HEAPF32[i42 + (i6 * 12 | 0) + 8 >> 2] = d15;
+  i5 = i5 + 1 | 0;
+  if ((i5 | 0) >= (HEAP32[i2 >> 2] | 0)) {
+   i2 = 21;
+   break;
+  }
+ }
+ if ((i2 | 0) == 4) {
+  ___assert_fail(6648, 6520, 311, 6688);
+ } else if ((i2 | 0) == 9) {
+  ___assert_fail(6720, 6520, 406, 6688);
+ } else if ((i2 | 0) == 21) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function __Z14b2TimeOfImpactP11b2TOIOutputPK10b2TOIInput(i3, i11) {
+ i3 = i3 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, d14 = 0.0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, d28 = 0.0, i29 = 0, d30 = 0.0, d31 = 0.0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, i39 = 0, d40 = 0.0, i41 = 0, d42 = 0.0, d43 = 0.0, i44 = 0, i45 = 0, d46 = 0.0, i47 = 0, d48 = 0.0, d49 = 0.0, d50 = 0.0, d51 = 0.0, i52 = 0, d53 = 0.0, d54 = 0.0, d55 = 0.0, d56 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 320 | 0;
+ i12 = i1 + 276 | 0;
+ i10 = i1 + 240 | 0;
+ i13 = i1 + 228 | 0;
+ i5 = i1 + 136 | 0;
+ i7 = i1 + 112 | 0;
+ i8 = i1 + 8 | 0;
+ i9 = i1 + 4 | 0;
+ i4 = i1;
+ HEAP32[874] = (HEAP32[874] | 0) + 1;
+ HEAP32[i3 >> 2] = 0;
+ i19 = i11 + 128 | 0;
+ i2 = i3 + 4 | 0;
+ HEAPF32[i2 >> 2] = +HEAPF32[i19 >> 2];
+ i6 = i11 + 28 | 0;
+ i16 = i12 + 0 | 0;
+ i15 = i11 + 56 | 0;
+ i17 = i16 + 36 | 0;
+ do {
+  HEAP32[i16 >> 2] = HEAP32[i15 >> 2];
+  i16 = i16 + 4 | 0;
+  i15 = i15 + 4 | 0;
+ } while ((i16 | 0) < (i17 | 0));
+ i16 = i10 + 0 | 0;
+ i15 = i11 + 92 | 0;
+ i17 = i16 + 36 | 0;
+ do {
+  HEAP32[i16 >> 2] = HEAP32[i15 >> 2];
+  i16 = i16 + 4 | 0;
+  i15 = i15 + 4 | 0;
+ } while ((i16 | 0) < (i17 | 0));
+ i15 = i12 + 24 | 0;
+ d42 = +HEAPF32[i15 >> 2];
+ d43 = +Math_floor(+(d42 / 6.2831854820251465)) * 6.2831854820251465;
+ d42 = d42 - d43;
+ HEAPF32[i15 >> 2] = d42;
+ i16 = i12 + 28 | 0;
+ d43 = +HEAPF32[i16 >> 2] - d43;
+ HEAPF32[i16 >> 2] = d43;
+ i17 = i10 + 24 | 0;
+ d46 = +HEAPF32[i17 >> 2];
+ d40 = +Math_floor(+(d46 / 6.2831854820251465)) * 6.2831854820251465;
+ d46 = d46 - d40;
+ HEAPF32[i17 >> 2] = d46;
+ i18 = i10 + 28 | 0;
+ d40 = +HEAPF32[i18 >> 2] - d40;
+ HEAPF32[i18 >> 2] = d40;
+ d14 = +HEAPF32[i19 >> 2];
+ d28 = +HEAPF32[i11 + 24 >> 2] + +HEAPF32[i11 + 52 >> 2] + -.014999999664723873;
+ d28 = d28 < .004999999888241291 ? .004999999888241291 : d28;
+ if (!(d28 > .0012499999720603228)) {
+  ___assert_fail(3536, 3560, 280, 3600);
+ }
+ HEAP16[i13 + 4 >> 1] = 0;
+ HEAP32[i5 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+ HEAP32[i5 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+ HEAP32[i5 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+ HEAP32[i5 + 12 >> 2] = HEAP32[i11 + 12 >> 2];
+ HEAP32[i5 + 16 >> 2] = HEAP32[i11 + 16 >> 2];
+ HEAP32[i5 + 20 >> 2] = HEAP32[i11 + 20 >> 2];
+ HEAP32[i5 + 24 >> 2] = HEAP32[i11 + 24 >> 2];
+ i38 = i5 + 28 | 0;
+ HEAP32[i38 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+ HEAP32[i38 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+ HEAP32[i38 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+ HEAP32[i38 + 12 >> 2] = HEAP32[i6 + 12 >> 2];
+ HEAP32[i38 + 16 >> 2] = HEAP32[i6 + 16 >> 2];
+ HEAP32[i38 + 20 >> 2] = HEAP32[i6 + 20 >> 2];
+ HEAP32[i38 + 24 >> 2] = HEAP32[i6 + 24 >> 2];
+ HEAP8[i5 + 88 | 0] = 0;
+ i38 = i12 + 8 | 0;
+ i27 = i12 + 12 | 0;
+ i29 = i12 + 16 | 0;
+ i22 = i12 + 20 | 0;
+ i32 = i12 + 4 | 0;
+ i34 = i10 + 8 | 0;
+ i36 = i10 + 12 | 0;
+ i35 = i10 + 16 | 0;
+ i37 = i10 + 20 | 0;
+ i33 = i10 + 4 | 0;
+ i26 = i5 + 56 | 0;
+ i25 = i5 + 64 | 0;
+ i24 = i5 + 68 | 0;
+ i23 = i5 + 72 | 0;
+ i20 = i5 + 80 | 0;
+ i19 = i5 + 84 | 0;
+ i21 = i7 + 16 | 0;
+ d30 = d28 + .0012499999720603228;
+ d31 = d28 + -.0012499999720603228;
+ d48 = d40;
+ i39 = 0;
+ d40 = 0.0;
+ L4 : while (1) {
+  d56 = 1.0 - d40;
+  d49 = d56 * d42 + d40 * d43;
+  d43 = +Math_sin(+d49);
+  d49 = +Math_cos(+d49);
+  d55 = +HEAPF32[i12 >> 2];
+  d54 = +HEAPF32[i32 >> 2];
+  d42 = d56 * d46 + d40 * d48;
+  d53 = +Math_sin(+d42);
+  d42 = +Math_cos(+d42);
+  d46 = +HEAPF32[i10 >> 2];
+  d51 = +HEAPF32[i33 >> 2];
+  d50 = d56 * +HEAPF32[i34 >> 2] + d40 * +HEAPF32[i35 >> 2] - (d42 * d46 - d53 * d51);
+  d51 = d56 * +HEAPF32[i36 >> 2] + d40 * +HEAPF32[i37 >> 2] - (d53 * d46 + d42 * d51);
+  d46 = +(d56 * +HEAPF32[i38 >> 2] + d40 * +HEAPF32[i29 >> 2] - (d49 * d55 - d43 * d54));
+  d48 = +(d56 * +HEAPF32[i27 >> 2] + d40 * +HEAPF32[i22 >> 2] - (d43 * d55 + d49 * d54));
+  i52 = i26;
+  HEAPF32[i52 >> 2] = d46;
+  HEAPF32[i52 + 4 >> 2] = d48;
+  HEAPF32[i25 >> 2] = d43;
+  HEAPF32[i24 >> 2] = d49;
+  d50 = +d50;
+  d51 = +d51;
+  i52 = i23;
+  HEAPF32[i52 >> 2] = d50;
+  HEAPF32[i52 + 4 >> 2] = d51;
+  HEAPF32[i20 >> 2] = d53;
+  HEAPF32[i19 >> 2] = d42;
+  __Z10b2DistanceP16b2DistanceOutputP14b2SimplexCachePK15b2DistanceInput(i7, i13, i5);
+  d42 = +HEAPF32[i21 >> 2];
+  if (d42 <= 0.0) {
+   i4 = 5;
+   break;
+  }
+  if (d42 < d30) {
+   i4 = 7;
+   break;
+  }
+  +__ZN20b2SeparationFunction10InitializeEPK14b2SimplexCachePK15b2DistanceProxyRK7b2SweepS5_S8_f(i8, i13, i11, i12, i6, i10, d40);
+  i41 = 0;
+  d42 = d14;
+  do {
+   d50 = +__ZNK20b2SeparationFunction17FindMinSeparationEPiS0_f(i8, i9, i4, d42);
+   if (d50 > d30) {
+    i4 = 10;
+    break L4;
+   }
+   if (d50 > d31) {
+    d40 = d42;
+    break;
+   }
+   i45 = HEAP32[i9 >> 2] | 0;
+   i44 = HEAP32[i4 >> 2] | 0;
+   d48 = +__ZNK20b2SeparationFunction8EvaluateEiif(i8, i45, i44, d40);
+   if (d48 < d31) {
+    i4 = 13;
+    break L4;
+   }
+   if (!(d48 <= d30)) {
+    d43 = d40;
+    d46 = d42;
+    i47 = 0;
+   } else {
+    i4 = 15;
+    break L4;
+   }
+   while (1) {
+    if ((i47 & 1 | 0) == 0) {
+     d49 = (d43 + d46) * .5;
+    } else {
+     d49 = d43 + (d28 - d48) * (d46 - d43) / (d50 - d48);
+    }
+    d51 = +__ZNK20b2SeparationFunction8EvaluateEiif(i8, i45, i44, d49);
+    d53 = d51 - d28;
+    if (!(d53 > 0.0)) {
+     d53 = -d53;
+    }
+    if (d53 < .0012499999720603228) {
+     d42 = d49;
+     break;
+    }
+    i52 = d51 > d28;
+    i47 = i47 + 1 | 0;
+    HEAP32[880] = (HEAP32[880] | 0) + 1;
+    if ((i47 | 0) == 50) {
+     i47 = 50;
+     break;
+    } else {
+     d43 = i52 ? d49 : d43;
+     d46 = i52 ? d46 : d49;
+     d48 = i52 ? d51 : d48;
+     d50 = i52 ? d50 : d51;
+    }
+   }
+   i44 = HEAP32[882] | 0;
+   HEAP32[882] = (i44 | 0) > (i47 | 0) ? i44 : i47;
+   i41 = i41 + 1 | 0;
+  } while ((i41 | 0) != 8);
+  i39 = i39 + 1 | 0;
+  HEAP32[876] = (HEAP32[876] | 0) + 1;
+  if ((i39 | 0) == 20) {
+   i4 = 27;
+   break;
+  }
+  d42 = +HEAPF32[i15 >> 2];
+  d43 = +HEAPF32[i16 >> 2];
+  d46 = +HEAPF32[i17 >> 2];
+  d48 = +HEAPF32[i18 >> 2];
+ }
+ if ((i4 | 0) == 5) {
+  HEAP32[i3 >> 2] = 2;
+  HEAPF32[i2 >> 2] = 0.0;
+  i2 = HEAP32[878] | 0;
+  i52 = (i2 | 0) > (i39 | 0);
+  i52 = i52 ? i2 : i39;
+  HEAP32[878] = i52;
+  STACKTOP = i1;
+  return;
+ } else if ((i4 | 0) == 7) {
+  HEAP32[i3 >> 2] = 3;
+  HEAPF32[i2 >> 2] = d40;
+  i2 = HEAP32[878] | 0;
+  i52 = (i2 | 0) > (i39 | 0);
+  i52 = i52 ? i2 : i39;
+  HEAP32[878] = i52;
+  STACKTOP = i1;
+  return;
+ } else if ((i4 | 0) == 10) {
+  HEAP32[i3 >> 2] = 4;
+  HEAPF32[i2 >> 2] = d14;
+ } else if ((i4 | 0) == 13) {
+  HEAP32[i3 >> 2] = 1;
+  HEAPF32[i2 >> 2] = d40;
+ } else if ((i4 | 0) == 15) {
+  HEAP32[i3 >> 2] = 3;
+  HEAPF32[i2 >> 2] = d40;
+ } else if ((i4 | 0) == 27) {
+  HEAP32[i3 >> 2] = 1;
+  HEAPF32[i2 >> 2] = d40;
+  i39 = 20;
+  i2 = HEAP32[878] | 0;
+  i52 = (i2 | 0) > (i39 | 0);
+  i52 = i52 ? i2 : i39;
+  HEAP32[878] = i52;
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[876] = (HEAP32[876] | 0) + 1;
+ i39 = i39 + 1 | 0;
+ i2 = HEAP32[878] | 0;
+ i52 = (i2 | 0) > (i39 | 0);
+ i52 = i52 ? i2 : i39;
+ HEAP32[878] = i52;
+ STACKTOP = i1;
+ return;
+}
+function __ZN7b2World5SolveERK10b2TimeStep(i5, i15) {
+ i5 = i5 | 0;
+ i15 = i15 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, d39 = 0.0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 96 | 0;
+ i4 = i3 + 32 | 0;
+ i9 = i3;
+ i2 = i3 + 84 | 0;
+ i11 = i5 + 103008 | 0;
+ HEAPF32[i11 >> 2] = 0.0;
+ i14 = i5 + 103012 | 0;
+ HEAPF32[i14 >> 2] = 0.0;
+ i8 = i5 + 103016 | 0;
+ HEAPF32[i8 >> 2] = 0.0;
+ i16 = i5 + 102960 | 0;
+ i1 = i5 + 102872 | 0;
+ i6 = i5 + 68 | 0;
+ __ZN8b2IslandC2EiiiP16b2StackAllocatorP17b2ContactListener(i4, HEAP32[i16 >> 2] | 0, HEAP32[i5 + 102936 >> 2] | 0, HEAP32[i5 + 102964 >> 2] | 0, i6, HEAP32[i5 + 102944 >> 2] | 0);
+ i7 = i5 + 102952 | 0;
+ i17 = HEAP32[i7 >> 2] | 0;
+ if ((i17 | 0) != 0) {
+  do {
+   i38 = i17 + 4 | 0;
+   HEAP16[i38 >> 1] = HEAP16[i38 >> 1] & 65534;
+   i17 = HEAP32[i17 + 96 >> 2] | 0;
+  } while ((i17 | 0) != 0);
+ }
+ i17 = HEAP32[i5 + 102932 >> 2] | 0;
+ if ((i17 | 0) != 0) {
+  do {
+   i38 = i17 + 4 | 0;
+   HEAP32[i38 >> 2] = HEAP32[i38 >> 2] & -2;
+   i17 = HEAP32[i17 + 12 >> 2] | 0;
+  } while ((i17 | 0) != 0);
+ }
+ i17 = HEAP32[i5 + 102956 >> 2] | 0;
+ if ((i17 | 0) != 0) {
+  do {
+   HEAP8[i17 + 60 | 0] = 0;
+   i17 = HEAP32[i17 + 12 >> 2] | 0;
+  } while ((i17 | 0) != 0);
+ }
+ i24 = HEAP32[i16 >> 2] | 0;
+ i16 = __ZN16b2StackAllocator8AllocateEi(i6, i24 << 2) | 0;
+ i32 = HEAP32[i7 >> 2] | 0;
+ L13 : do {
+  if ((i32 | 0) != 0) {
+   i18 = i4 + 28 | 0;
+   i30 = i4 + 36 | 0;
+   i27 = i4 + 32 | 0;
+   i17 = i4 + 40 | 0;
+   i23 = i4 + 8 | 0;
+   i29 = i4 + 48 | 0;
+   i28 = i4 + 16 | 0;
+   i26 = i4 + 44 | 0;
+   i31 = i4 + 12 | 0;
+   i25 = i5 + 102968 | 0;
+   i22 = i5 + 102976 | 0;
+   i21 = i9 + 12 | 0;
+   i20 = i9 + 16 | 0;
+   i19 = i9 + 20 | 0;
+   L15 : while (1) {
+    i33 = i32 + 4 | 0;
+    i34 = HEAP16[i33 >> 1] | 0;
+    if ((i34 & 35) == 34 ? (HEAP32[i32 >> 2] | 0) != 0 : 0) {
+     HEAP32[i18 >> 2] = 0;
+     HEAP32[i30 >> 2] = 0;
+     HEAP32[i27 >> 2] = 0;
+     HEAP32[i16 >> 2] = i32;
+     HEAP16[i33 >> 1] = i34 & 65535 | 1;
+     i35 = 1;
+     do {
+      i35 = i35 + -1 | 0;
+      i33 = HEAP32[i16 + (i35 << 2) >> 2] | 0;
+      i34 = i33 + 4 | 0;
+      i36 = HEAP16[i34 >> 1] | 0;
+      if ((i36 & 32) == 0) {
+       i8 = 13;
+       break L15;
+      }
+      i37 = HEAP32[i18 >> 2] | 0;
+      if ((i37 | 0) >= (HEAP32[i17 >> 2] | 0)) {
+       i8 = 15;
+       break L15;
+      }
+      HEAP32[i33 + 8 >> 2] = i37;
+      i38 = HEAP32[i18 >> 2] | 0;
+      HEAP32[(HEAP32[i23 >> 2] | 0) + (i38 << 2) >> 2] = i33;
+      HEAP32[i18 >> 2] = i38 + 1;
+      i36 = i36 & 65535;
+      if ((i36 & 2 | 0) == 0) {
+       HEAP16[i34 >> 1] = i36 | 2;
+       HEAPF32[i33 + 144 >> 2] = 0.0;
+      }
+      if ((HEAP32[i33 >> 2] | 0) != 0) {
+       i34 = HEAP32[i33 + 112 >> 2] | 0;
+       if ((i34 | 0) != 0) {
+        do {
+         i38 = HEAP32[i34 + 4 >> 2] | 0;
+         i36 = i38 + 4 | 0;
+         if (((HEAP32[i36 >> 2] & 7 | 0) == 6 ? (HEAP8[(HEAP32[i38 + 48 >> 2] | 0) + 38 | 0] | 0) == 0 : 0) ? (HEAP8[(HEAP32[i38 + 52 >> 2] | 0) + 38 | 0] | 0) == 0 : 0) {
+          i37 = HEAP32[i30 >> 2] | 0;
+          if ((i37 | 0) >= (HEAP32[i26 >> 2] | 0)) {
+           i8 = 25;
+           break L15;
+          }
+          HEAP32[i30 >> 2] = i37 + 1;
+          HEAP32[(HEAP32[i31 >> 2] | 0) + (i37 << 2) >> 2] = i38;
+          HEAP32[i36 >> 2] = HEAP32[i36 >> 2] | 1;
+          i38 = HEAP32[i34 >> 2] | 0;
+          i36 = i38 + 4 | 0;
+          i37 = HEAP16[i36 >> 1] | 0;
+          if ((i37 & 1) == 0) {
+           if ((i35 | 0) >= (i24 | 0)) {
+            i8 = 28;
+            break L15;
+           }
+           HEAP32[i16 + (i35 << 2) >> 2] = i38;
+           HEAP16[i36 >> 1] = i37 & 65535 | 1;
+           i35 = i35 + 1 | 0;
+          }
+         }
+         i34 = HEAP32[i34 + 12 >> 2] | 0;
+        } while ((i34 | 0) != 0);
+       }
+       i33 = HEAP32[i33 + 108 >> 2] | 0;
+       if ((i33 | 0) != 0) {
+        do {
+         i37 = i33 + 4 | 0;
+         i36 = HEAP32[i37 >> 2] | 0;
+         if ((HEAP8[i36 + 60 | 0] | 0) == 0 ? (i10 = HEAP32[i33 >> 2] | 0, i13 = i10 + 4 | 0, i12 = HEAP16[i13 >> 1] | 0, !((i12 & 32) == 0)) : 0) {
+          i34 = HEAP32[i27 >> 2] | 0;
+          if ((i34 | 0) >= (HEAP32[i29 >> 2] | 0)) {
+           i8 = 35;
+           break L15;
+          }
+          HEAP32[i27 >> 2] = i34 + 1;
+          HEAP32[(HEAP32[i28 >> 2] | 0) + (i34 << 2) >> 2] = i36;
+          HEAP8[(HEAP32[i37 >> 2] | 0) + 60 | 0] = 1;
+          if ((i12 & 1) == 0) {
+           if ((i35 | 0) >= (i24 | 0)) {
+            i8 = 38;
+            break L15;
+           }
+           HEAP32[i16 + (i35 << 2) >> 2] = i10;
+           HEAP16[i13 >> 1] = i12 & 65535 | 1;
+           i35 = i35 + 1 | 0;
+          }
+         }
+         i33 = HEAP32[i33 + 12 >> 2] | 0;
+        } while ((i33 | 0) != 0);
+       }
+      }
+     } while ((i35 | 0) > 0);
+     __ZN8b2Island5SolveEP9b2ProfileRK10b2TimeStepRK6b2Vec2b(i4, i9, i15, i25, (HEAP8[i22] | 0) != 0);
+     HEAPF32[i11 >> 2] = +HEAPF32[i21 >> 2] + +HEAPF32[i11 >> 2];
+     HEAPF32[i14 >> 2] = +HEAPF32[i20 >> 2] + +HEAPF32[i14 >> 2];
+     HEAPF32[i8 >> 2] = +HEAPF32[i19 >> 2] + +HEAPF32[i8 >> 2];
+     i35 = HEAP32[i18 >> 2] | 0;
+     if ((i35 | 0) > 0) {
+      i33 = HEAP32[i23 >> 2] | 0;
+      i36 = 0;
+      do {
+       i34 = HEAP32[i33 + (i36 << 2) >> 2] | 0;
+       if ((HEAP32[i34 >> 2] | 0) == 0) {
+        i38 = i34 + 4 | 0;
+        HEAP16[i38 >> 1] = HEAP16[i38 >> 1] & 65534;
+       }
+       i36 = i36 + 1 | 0;
+      } while ((i36 | 0) < (i35 | 0));
+     }
+    }
+    i32 = HEAP32[i32 + 96 >> 2] | 0;
+    if ((i32 | 0) == 0) {
+     break L13;
+    }
+   }
+   if ((i8 | 0) == 13) {
+    ___assert_fail(2232, 2184, 445, 2256);
+   } else if ((i8 | 0) == 15) {
+    ___assert_fail(2520, 2440, 54, 2472);
+   } else if ((i8 | 0) == 25) {
+    ___assert_fail(2480, 2440, 62, 2472);
+   } else if ((i8 | 0) == 28) {
+    ___assert_fail(2264, 2184, 495, 2256);
+   } else if ((i8 | 0) == 35) {
+    ___assert_fail(2408, 2440, 68, 2472);
+   } else if ((i8 | 0) == 38) {
+    ___assert_fail(2264, 2184, 524, 2256);
+   }
+  }
+ } while (0);
+ __ZN16b2StackAllocator4FreeEPv(i6, i16);
+ __ZN7b2TimerC2Ev(i2);
+ i6 = HEAP32[i7 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  __ZN16b2ContactManager15FindNewContactsEv(i1);
+  d39 = +__ZNK7b2Timer15GetMillisecondsEv(i2);
+  i38 = i5 + 103020 | 0;
+  HEAPF32[i38 >> 2] = d39;
+  __ZN8b2IslandD2Ev(i4);
+  STACKTOP = i3;
+  return;
+ }
+ do {
+  if (!((HEAP16[i6 + 4 >> 1] & 1) == 0) ? (HEAP32[i6 >> 2] | 0) != 0 : 0) {
+   __ZN6b2Body19SynchronizeFixturesEv(i6);
+  }
+  i6 = HEAP32[i6 + 96 >> 2] | 0;
+ } while ((i6 | 0) != 0);
+ __ZN16b2ContactManager15FindNewContactsEv(i1);
+ d39 = +__ZNK7b2Timer15GetMillisecondsEv(i2);
+ i38 = i5 + 103020 | 0;
+ HEAPF32[i38 >> 2] = d39;
+ __ZN8b2IslandD2Ev(i4);
+ STACKTOP = i3;
+ return;
+}
+function __ZN15b2ContactSolver29InitializeVelocityConstraintsEv(i10) {
+ i10 = i10 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, i31 = 0, d32 = 0.0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, d38 = 0.0, d39 = 0.0, d40 = 0.0, d41 = 0.0, i42 = 0, d43 = 0.0, d44 = 0.0, d45 = 0.0, d46 = 0.0, d47 = 0.0, d48 = 0.0, i49 = 0, i50 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i8 = i1 + 40 | 0;
+ i3 = i1 + 24 | 0;
+ i5 = i1;
+ i4 = i10 + 48 | 0;
+ if ((HEAP32[i4 >> 2] | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i9 = i10 + 40 | 0;
+ i2 = i10 + 36 | 0;
+ i7 = i10 + 44 | 0;
+ i6 = i10 + 24 | 0;
+ i13 = i10 + 28 | 0;
+ i14 = i8 + 8 | 0;
+ i12 = i8 + 12 | 0;
+ i11 = i3 + 8 | 0;
+ i10 = i3 + 12 | 0;
+ i16 = 0;
+ while (1) {
+  i15 = HEAP32[i9 >> 2] | 0;
+  i33 = HEAP32[i2 >> 2] | 0;
+  i31 = HEAP32[(HEAP32[i7 >> 2] | 0) + (HEAP32[i15 + (i16 * 152 | 0) + 148 >> 2] << 2) >> 2] | 0;
+  i35 = HEAP32[i15 + (i16 * 152 | 0) + 112 >> 2] | 0;
+  i42 = HEAP32[i15 + (i16 * 152 | 0) + 116 >> 2] | 0;
+  d30 = +HEAPF32[i15 + (i16 * 152 | 0) + 120 >> 2];
+  d24 = +HEAPF32[i15 + (i16 * 152 | 0) + 124 >> 2];
+  d17 = +HEAPF32[i15 + (i16 * 152 | 0) + 128 >> 2];
+  d18 = +HEAPF32[i15 + (i16 * 152 | 0) + 132 >> 2];
+  i36 = i33 + (i16 * 88 | 0) + 48 | 0;
+  d39 = +HEAPF32[i36 >> 2];
+  d40 = +HEAPF32[i36 + 4 >> 2];
+  i36 = i33 + (i16 * 88 | 0) + 56 | 0;
+  d41 = +HEAPF32[i36 >> 2];
+  d43 = +HEAPF32[i36 + 4 >> 2];
+  i36 = HEAP32[i6 >> 2] | 0;
+  i37 = i36 + (i35 * 12 | 0) | 0;
+  d26 = +HEAPF32[i37 >> 2];
+  d27 = +HEAPF32[i37 + 4 >> 2];
+  d32 = +HEAPF32[i36 + (i35 * 12 | 0) + 8 >> 2];
+  i37 = HEAP32[i13 >> 2] | 0;
+  i34 = i37 + (i35 * 12 | 0) | 0;
+  d22 = +HEAPF32[i34 >> 2];
+  d25 = +HEAPF32[i34 + 4 >> 2];
+  d23 = +HEAPF32[i37 + (i35 * 12 | 0) + 8 >> 2];
+  i35 = i36 + (i42 * 12 | 0) | 0;
+  d28 = +HEAPF32[i35 >> 2];
+  d29 = +HEAPF32[i35 + 4 >> 2];
+  d38 = +HEAPF32[i36 + (i42 * 12 | 0) + 8 >> 2];
+  i36 = i37 + (i42 * 12 | 0) | 0;
+  d20 = +HEAPF32[i36 >> 2];
+  d19 = +HEAPF32[i36 + 4 >> 2];
+  d21 = +HEAPF32[i37 + (i42 * 12 | 0) + 8 >> 2];
+  if ((HEAP32[i31 + 124 >> 2] | 0) <= 0) {
+   i2 = 4;
+   break;
+  }
+  d44 = +HEAPF32[i33 + (i16 * 88 | 0) + 80 >> 2];
+  d45 = +HEAPF32[i33 + (i16 * 88 | 0) + 76 >> 2];
+  d47 = +Math_sin(+d32);
+  HEAPF32[i14 >> 2] = d47;
+  d48 = +Math_cos(+d32);
+  HEAPF32[i12 >> 2] = d48;
+  d32 = +Math_sin(+d38);
+  HEAPF32[i11 >> 2] = d32;
+  d38 = +Math_cos(+d38);
+  HEAPF32[i10 >> 2] = d38;
+  d46 = +(d26 - (d39 * d48 - d40 * d47));
+  d40 = +(d27 - (d40 * d48 + d39 * d47));
+  i37 = i8;
+  HEAPF32[i37 >> 2] = d46;
+  HEAPF32[i37 + 4 >> 2] = d40;
+  d40 = +(d28 - (d41 * d38 - d43 * d32));
+  d43 = +(d29 - (d43 * d38 + d41 * d32));
+  i37 = i3;
+  HEAPF32[i37 >> 2] = d40;
+  HEAPF32[i37 + 4 >> 2] = d43;
+  __ZN15b2WorldManifold10InitializeEPK10b2ManifoldRK11b2TransformfS5_f(i5, i31 + 64 | 0, i8, d45, i3, d44);
+  i37 = i15 + (i16 * 152 | 0) + 72 | 0;
+  i42 = i5;
+  i33 = HEAP32[i42 + 4 >> 2] | 0;
+  i31 = i37;
+  HEAP32[i31 >> 2] = HEAP32[i42 >> 2];
+  HEAP32[i31 + 4 >> 2] = i33;
+  i31 = i15 + (i16 * 152 | 0) + 144 | 0;
+  i33 = HEAP32[i31 >> 2] | 0;
+  do {
+   if ((i33 | 0) > 0) {
+    i36 = i15 + (i16 * 152 | 0) + 76 | 0;
+    d32 = d30 + d24;
+    i35 = i15 + (i16 * 152 | 0) + 140 | 0;
+    i34 = 0;
+    do {
+     i49 = i5 + (i34 << 3) + 8 | 0;
+     d41 = +HEAPF32[i49 >> 2] - d26;
+     i42 = i5 + (i34 << 3) + 12 | 0;
+     d39 = +d41;
+     d40 = +(+HEAPF32[i42 >> 2] - d27);
+     i50 = i15 + (i16 * 152 | 0) + (i34 * 36 | 0) | 0;
+     HEAPF32[i50 >> 2] = d39;
+     HEAPF32[i50 + 4 >> 2] = d40;
+     d40 = +HEAPF32[i49 >> 2] - d28;
+     d39 = +d40;
+     d47 = +(+HEAPF32[i42 >> 2] - d29);
+     i42 = i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 8 | 0;
+     HEAPF32[i42 >> 2] = d39;
+     HEAPF32[i42 + 4 >> 2] = d47;
+     d47 = +HEAPF32[i36 >> 2];
+     d39 = +HEAPF32[i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 4 >> 2];
+     d43 = +HEAPF32[i37 >> 2];
+     d48 = d41 * d47 - d39 * d43;
+     d38 = +HEAPF32[i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 12 >> 2];
+     d43 = d47 * d40 - d43 * d38;
+     d43 = d32 + d48 * d17 * d48 + d43 * d18 * d43;
+     if (d43 > 0.0) {
+      d43 = 1.0 / d43;
+     } else {
+      d43 = 0.0;
+     }
+     HEAPF32[i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 24 >> 2] = d43;
+     d43 = +HEAPF32[i36 >> 2];
+     d47 = -+HEAPF32[i37 >> 2];
+     d48 = d41 * d47 - d43 * d39;
+     d43 = d40 * d47 - d43 * d38;
+     d43 = d32 + d48 * d17 * d48 + d43 * d18 * d43;
+     if (d43 > 0.0) {
+      d43 = 1.0 / d43;
+     } else {
+      d43 = 0.0;
+     }
+     HEAPF32[i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 28 >> 2] = d43;
+     i42 = i15 + (i16 * 152 | 0) + (i34 * 36 | 0) + 32 | 0;
+     HEAPF32[i42 >> 2] = 0.0;
+     d38 = +HEAPF32[i37 >> 2] * (d20 - d21 * d38 - d22 + d23 * d39) + +HEAPF32[i36 >> 2] * (d19 + d21 * d40 - d25 - d23 * d41);
+     if (d38 < -1.0) {
+      HEAPF32[i42 >> 2] = -(d38 * +HEAPF32[i35 >> 2]);
+     }
+     i34 = i34 + 1 | 0;
+    } while ((i34 | 0) != (i33 | 0));
+    if ((HEAP32[i31 >> 2] | 0) == 2) {
+     d45 = +HEAPF32[i15 + (i16 * 152 | 0) + 76 >> 2];
+     d20 = +HEAPF32[i37 >> 2];
+     d44 = +HEAPF32[i15 + (i16 * 152 | 0) >> 2] * d45 - +HEAPF32[i15 + (i16 * 152 | 0) + 4 >> 2] * d20;
+     d19 = d45 * +HEAPF32[i15 + (i16 * 152 | 0) + 8 >> 2] - d20 * +HEAPF32[i15 + (i16 * 152 | 0) + 12 >> 2];
+     d47 = d45 * +HEAPF32[i15 + (i16 * 152 | 0) + 36 >> 2] - d20 * +HEAPF32[i15 + (i16 * 152 | 0) + 40 >> 2];
+     d20 = d45 * +HEAPF32[i15 + (i16 * 152 | 0) + 44 >> 2] - d20 * +HEAPF32[i15 + (i16 * 152 | 0) + 48 >> 2];
+     d45 = d30 + d24;
+     d46 = d17 * d44;
+     d48 = d18 * d19;
+     d19 = d45 + d44 * d46 + d19 * d48;
+     d18 = d45 + d47 * d17 * d47 + d20 * d18 * d20;
+     d17 = d45 + d46 * d47 + d48 * d20;
+     d20 = d19 * d18 - d17 * d17;
+     if (!(d19 * d19 < d20 * 1.0e3)) {
+      HEAP32[i31 >> 2] = 1;
+      break;
+     }
+     HEAPF32[i15 + (i16 * 152 | 0) + 96 >> 2] = d19;
+     HEAPF32[i15 + (i16 * 152 | 0) + 100 >> 2] = d17;
+     HEAPF32[i15 + (i16 * 152 | 0) + 104 >> 2] = d17;
+     HEAPF32[i15 + (i16 * 152 | 0) + 108 >> 2] = d18;
+     if (d20 != 0.0) {
+      d20 = 1.0 / d20;
+     }
+     d48 = -(d20 * d17);
+     HEAPF32[i15 + (i16 * 152 | 0) + 80 >> 2] = d18 * d20;
+     HEAPF32[i15 + (i16 * 152 | 0) + 84 >> 2] = d48;
+     HEAPF32[i15 + (i16 * 152 | 0) + 88 >> 2] = d48;
+     HEAPF32[i15 + (i16 * 152 | 0) + 92 >> 2] = d19 * d20;
+    }
+   }
+  } while (0);
+  i16 = i16 + 1 | 0;
+  if ((i16 | 0) >= (HEAP32[i4 >> 2] | 0)) {
+   i2 = 21;
+   break;
+  }
+ }
+ if ((i2 | 0) == 4) {
+  ___assert_fail(6584, 6520, 168, 6616);
+ } else if ((i2 | 0) == 21) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function __Z17b2CollidePolygonsP10b2ManifoldPK14b2PolygonShapeRK11b2TransformS3_S6_(i5, i27, i28, i24, i14) {
+ i5 = i5 | 0;
+ i27 = i27 | 0;
+ i28 = i28 | 0;
+ i24 = i24 | 0;
+ i14 = i14 | 0;
+ var i1 = 0, i2 = 0, d3 = 0.0, i4 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, d15 = 0.0, d16 = 0.0, i17 = 0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0, d22 = 0.0, d23 = 0.0, d25 = 0.0, d26 = 0.0, d29 = 0.0, d30 = 0.0, i31 = 0, d32 = 0.0, i33 = 0, i34 = 0, d35 = 0.0, d36 = 0.0, d37 = 0.0, d38 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 96 | 0;
+ i17 = i1 + 92 | 0;
+ i20 = i1 + 88 | 0;
+ i13 = i1;
+ i11 = i1 + 80 | 0;
+ i12 = i1 + 56 | 0;
+ i4 = i1 + 32 | 0;
+ i10 = i1 + 24 | 0;
+ i2 = i5 + 60 | 0;
+ HEAP32[i2 >> 2] = 0;
+ d3 = +HEAPF32[i27 + 8 >> 2] + +HEAPF32[i24 + 8 >> 2];
+ HEAP32[i17 >> 2] = 0;
+ d7 = +__ZL19b2FindMaxSeparationPiPK14b2PolygonShapeRK11b2TransformS2_S5_(i17, i27, i28, i24, i14);
+ if (d7 > d3) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i20 >> 2] = 0;
+ d6 = +__ZL19b2FindMaxSeparationPiPK14b2PolygonShapeRK11b2TransformS2_S5_(i20, i24, i14, i27, i28);
+ if (d6 > d3) {
+  STACKTOP = i1;
+  return;
+ }
+ if (d6 > d7 * .9800000190734863 + .0010000000474974513) {
+  d18 = +HEAPF32[i14 >> 2];
+  d19 = +HEAPF32[i14 + 4 >> 2];
+  d15 = +HEAPF32[i14 + 8 >> 2];
+  d16 = +HEAPF32[i14 + 12 >> 2];
+  d9 = +HEAPF32[i28 >> 2];
+  d6 = +HEAPF32[i28 + 4 >> 2];
+  d7 = +HEAPF32[i28 + 8 >> 2];
+  d8 = +HEAPF32[i28 + 12 >> 2];
+  i17 = HEAP32[i20 >> 2] | 0;
+  HEAP32[i5 + 56 >> 2] = 2;
+  i14 = 1;
+  i20 = i24;
+ } else {
+  d18 = +HEAPF32[i28 >> 2];
+  d19 = +HEAPF32[i28 + 4 >> 2];
+  d15 = +HEAPF32[i28 + 8 >> 2];
+  d16 = +HEAPF32[i28 + 12 >> 2];
+  d9 = +HEAPF32[i14 >> 2];
+  d6 = +HEAPF32[i14 + 4 >> 2];
+  d7 = +HEAPF32[i14 + 8 >> 2];
+  d8 = +HEAPF32[i14 + 12 >> 2];
+  i17 = HEAP32[i17 >> 2] | 0;
+  HEAP32[i5 + 56 >> 2] = 1;
+  i14 = 0;
+  i20 = i27;
+  i27 = i24;
+ }
+ i28 = HEAP32[i27 + 148 >> 2] | 0;
+ if (!((i17 | 0) > -1)) {
+  ___assert_fail(5640, 5688, 151, 5728);
+ }
+ i24 = HEAP32[i20 + 148 >> 2] | 0;
+ if ((i24 | 0) <= (i17 | 0)) {
+  ___assert_fail(5640, 5688, 151, 5728);
+ }
+ d21 = +HEAPF32[i20 + (i17 << 3) + 84 >> 2];
+ d36 = +HEAPF32[i20 + (i17 << 3) + 88 >> 2];
+ d22 = d16 * d21 - d15 * d36;
+ d36 = d15 * d21 + d16 * d36;
+ d21 = d8 * d22 + d7 * d36;
+ d22 = d8 * d36 - d7 * d22;
+ if ((i28 | 0) > 0) {
+  i33 = 0;
+  i34 = 0;
+  d23 = 3.4028234663852886e+38;
+  while (1) {
+   d25 = d21 * +HEAPF32[i27 + (i33 << 3) + 84 >> 2] + d22 * +HEAPF32[i27 + (i33 << 3) + 88 >> 2];
+   i31 = d25 < d23;
+   i34 = i31 ? i33 : i34;
+   i33 = i33 + 1 | 0;
+   if ((i33 | 0) == (i28 | 0)) {
+    break;
+   } else {
+    d23 = i31 ? d25 : d23;
+   }
+  }
+ } else {
+  i34 = 0;
+ }
+ i31 = i34 + 1 | 0;
+ i33 = (i31 | 0) < (i28 | 0) ? i31 : 0;
+ d35 = +HEAPF32[i27 + (i34 << 3) + 20 >> 2];
+ d32 = +HEAPF32[i27 + (i34 << 3) + 24 >> 2];
+ d36 = +(d9 + (d8 * d35 - d7 * d32));
+ d32 = +(d6 + (d7 * d35 + d8 * d32));
+ i31 = i13;
+ HEAPF32[i31 >> 2] = d36;
+ HEAPF32[i31 + 4 >> 2] = d32;
+ i31 = i17 & 255;
+ i28 = i13 + 8 | 0;
+ HEAP8[i28] = i31;
+ HEAP8[i28 + 1 | 0] = i34;
+ HEAP8[i28 + 2 | 0] = 1;
+ HEAP8[i28 + 3 | 0] = 0;
+ d32 = +HEAPF32[i27 + (i33 << 3) + 20 >> 2];
+ d36 = +HEAPF32[i27 + (i33 << 3) + 24 >> 2];
+ d35 = +(d9 + (d8 * d32 - d7 * d36));
+ d36 = +(d6 + (d7 * d32 + d8 * d36));
+ i27 = i13 + 12 | 0;
+ HEAPF32[i27 >> 2] = d35;
+ HEAPF32[i27 + 4 >> 2] = d36;
+ i27 = i13 + 20 | 0;
+ HEAP8[i27] = i31;
+ HEAP8[i27 + 1 | 0] = i33;
+ HEAP8[i27 + 2 | 0] = 1;
+ HEAP8[i27 + 3 | 0] = 0;
+ i27 = i17 + 1 | 0;
+ i24 = (i27 | 0) < (i24 | 0) ? i27 : 0;
+ i34 = i20 + (i17 << 3) + 20 | 0;
+ d26 = +HEAPF32[i34 >> 2];
+ d25 = +HEAPF32[i34 + 4 >> 2];
+ i34 = i20 + (i24 << 3) + 20 | 0;
+ d30 = +HEAPF32[i34 >> 2];
+ d29 = +HEAPF32[i34 + 4 >> 2];
+ d32 = d30 - d26;
+ d35 = d29 - d25;
+ d21 = +Math_sqrt(+(d32 * d32 + d35 * d35));
+ if (!(d21 < 1.1920928955078125e-7)) {
+  d36 = 1.0 / d21;
+  d32 = d32 * d36;
+  d35 = d35 * d36;
+ }
+ d36 = d16 * d32 - d15 * d35;
+ d21 = d16 * d35 + d15 * d32;
+ HEAPF32[i11 >> 2] = d36;
+ HEAPF32[i11 + 4 >> 2] = d21;
+ d22 = -d36;
+ d38 = d18 + (d16 * d26 - d15 * d25);
+ d37 = d19 + (d15 * d26 + d16 * d25);
+ d23 = d38 * d21 + d37 * d22;
+ HEAPF32[i10 >> 2] = d22;
+ HEAPF32[i10 + 4 >> 2] = -d21;
+ if ((__Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i12, i13, i10, d3 - (d38 * d36 + d37 * d21), i17) | 0) < 2) {
+  STACKTOP = i1;
+  return;
+ }
+ if ((__Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i4, i12, i11, d3 + ((d18 + (d16 * d30 - d15 * d29)) * d36 + (d19 + (d15 * d30 + d16 * d29)) * d21), i24) | 0) < 2) {
+  STACKTOP = i1;
+  return;
+ }
+ d16 = +d35;
+ d15 = +-d32;
+ i10 = i5 + 40 | 0;
+ HEAPF32[i10 >> 2] = d16;
+ HEAPF32[i10 + 4 >> 2] = d15;
+ d15 = +((d26 + d30) * .5);
+ d16 = +((d25 + d29) * .5);
+ i10 = i5 + 48 | 0;
+ HEAPF32[i10 >> 2] = d15;
+ HEAPF32[i10 + 4 >> 2] = d16;
+ d16 = +HEAPF32[i4 >> 2];
+ d15 = +HEAPF32[i4 + 4 >> 2];
+ i10 = !(d21 * d16 + d15 * d22 - d23 <= d3);
+ if (i14 << 24 >> 24 == 0) {
+  if (i10) {
+   i10 = 0;
+  } else {
+   d38 = d16 - d9;
+   d36 = d15 - d6;
+   d37 = +(d8 * d38 + d7 * d36);
+   d38 = +(d8 * d36 - d7 * d38);
+   i10 = i5;
+   HEAPF32[i10 >> 2] = d37;
+   HEAPF32[i10 + 4 >> 2] = d38;
+   HEAP32[i5 + 16 >> 2] = HEAP32[i4 + 8 >> 2];
+   i10 = 1;
+  }
+  d16 = +HEAPF32[i4 + 12 >> 2];
+  d15 = +HEAPF32[i4 + 16 >> 2];
+  if (d21 * d16 + d15 * d22 - d23 <= d3) {
+   d38 = d16 - d9;
+   d36 = d15 - d6;
+   d37 = +(d8 * d38 + d7 * d36);
+   d38 = +(d8 * d36 - d7 * d38);
+   i34 = i5 + (i10 * 20 | 0) | 0;
+   HEAPF32[i34 >> 2] = d37;
+   HEAPF32[i34 + 4 >> 2] = d38;
+   HEAP32[i5 + (i10 * 20 | 0) + 16 >> 2] = HEAP32[i4 + 20 >> 2];
+   i10 = i10 + 1 | 0;
+  }
+ } else {
+  if (i10) {
+   i10 = 0;
+  } else {
+   d38 = d16 - d9;
+   d36 = d15 - d6;
+   d37 = +(d8 * d38 + d7 * d36);
+   d38 = +(d8 * d36 - d7 * d38);
+   i10 = i5;
+   HEAPF32[i10 >> 2] = d37;
+   HEAPF32[i10 + 4 >> 2] = d38;
+   i10 = i5 + 16 | 0;
+   i34 = HEAP32[i4 + 8 >> 2] | 0;
+   HEAP32[i10 >> 2] = i34;
+   HEAP8[i10] = i34 >>> 8;
+   HEAP8[i10 + 1 | 0] = i34;
+   HEAP8[i10 + 2 | 0] = i34 >>> 24;
+   HEAP8[i10 + 3 | 0] = i34 >>> 16;
+   i10 = 1;
+  }
+  d16 = +HEAPF32[i4 + 12 >> 2];
+  d15 = +HEAPF32[i4 + 16 >> 2];
+  if (d21 * d16 + d15 * d22 - d23 <= d3) {
+   d38 = d16 - d9;
+   d36 = d15 - d6;
+   d37 = +(d8 * d38 + d7 * d36);
+   d38 = +(d8 * d36 - d7 * d38);
+   i34 = i5 + (i10 * 20 | 0) | 0;
+   HEAPF32[i34 >> 2] = d37;
+   HEAPF32[i34 + 4 >> 2] = d38;
+   i34 = i5 + (i10 * 20 | 0) + 16 | 0;
+   i33 = HEAP32[i4 + 20 >> 2] | 0;
+   HEAP32[i34 >> 2] = i33;
+   HEAP8[i34] = i33 >>> 8;
+   HEAP8[i34 + 1 | 0] = i33;
+   HEAP8[i34 + 2 | 0] = i33 >>> 24;
+   HEAP8[i34 + 3 | 0] = i33 >>> 16;
+   i10 = i10 + 1 | 0;
+  }
+ }
+ HEAP32[i2 >> 2] = i10;
+ STACKTOP = i1;
+ return;
+}
+function __ZN8b2Island8SolveTOIERK10b2TimeStepii(i4, i11, i15, i18) {
+ i4 = i4 | 0;
+ i11 = i11 | 0;
+ i15 = i15 | 0;
+ i18 = i18 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d16 = 0.0, d17 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, d26 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 128 | 0;
+ i2 = i1 + 96 | 0;
+ i10 = i1 + 52 | 0;
+ i3 = i1;
+ i6 = i4 + 28 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ if ((i5 | 0) <= (i15 | 0)) {
+  ___assert_fail(5464, 5488, 386, 5520);
+ }
+ if ((i5 | 0) <= (i18 | 0)) {
+  ___assert_fail(5536, 5488, 387, 5520);
+ }
+ if ((i5 | 0) > 0) {
+  i9 = i4 + 8 | 0;
+  i8 = i4 + 20 | 0;
+  i7 = i4 + 24 | 0;
+  i22 = 0;
+  while (1) {
+   i23 = HEAP32[(HEAP32[i9 >> 2] | 0) + (i22 << 2) >> 2] | 0;
+   i5 = i23 + 44 | 0;
+   i24 = HEAP32[i5 + 4 >> 2] | 0;
+   i25 = (HEAP32[i8 >> 2] | 0) + (i22 * 12 | 0) | 0;
+   HEAP32[i25 >> 2] = HEAP32[i5 >> 2];
+   HEAP32[i25 + 4 >> 2] = i24;
+   HEAPF32[(HEAP32[i8 >> 2] | 0) + (i22 * 12 | 0) + 8 >> 2] = +HEAPF32[i23 + 56 >> 2];
+   i25 = i23 + 64 | 0;
+   i24 = HEAP32[i25 + 4 >> 2] | 0;
+   i5 = (HEAP32[i7 >> 2] | 0) + (i22 * 12 | 0) | 0;
+   HEAP32[i5 >> 2] = HEAP32[i25 >> 2];
+   HEAP32[i5 + 4 >> 2] = i24;
+   i5 = HEAP32[i7 >> 2] | 0;
+   HEAPF32[i5 + (i22 * 12 | 0) + 8 >> 2] = +HEAPF32[i23 + 72 >> 2];
+   i22 = i22 + 1 | 0;
+   if ((i22 | 0) >= (HEAP32[i6 >> 2] | 0)) {
+    i22 = i5;
+    break;
+   }
+  }
+ } else {
+  i8 = i4 + 20 | 0;
+  i22 = HEAP32[i4 + 24 >> 2] | 0;
+ }
+ i5 = i4 + 12 | 0;
+ HEAP32[i10 + 24 >> 2] = HEAP32[i5 >> 2];
+ i7 = i4 + 36 | 0;
+ HEAP32[i10 + 28 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i10 + 40 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i10 + 0 >> 2] = HEAP32[i11 + 0 >> 2];
+ HEAP32[i10 + 4 >> 2] = HEAP32[i11 + 4 >> 2];
+ HEAP32[i10 + 8 >> 2] = HEAP32[i11 + 8 >> 2];
+ HEAP32[i10 + 12 >> 2] = HEAP32[i11 + 12 >> 2];
+ HEAP32[i10 + 16 >> 2] = HEAP32[i11 + 16 >> 2];
+ HEAP32[i10 + 20 >> 2] = HEAP32[i11 + 20 >> 2];
+ HEAP32[i10 + 32 >> 2] = HEAP32[i8 >> 2];
+ i9 = i4 + 24 | 0;
+ HEAP32[i10 + 36 >> 2] = i22;
+ __ZN15b2ContactSolverC2EP18b2ContactSolverDef(i3, i10);
+ i10 = i11 + 16 | 0;
+ L13 : do {
+  if ((HEAP32[i10 >> 2] | 0) > 0) {
+   i22 = 0;
+   do {
+    i22 = i22 + 1 | 0;
+    if (__ZN15b2ContactSolver27SolveTOIPositionConstraintsEii(i3, i15, i18) | 0) {
+     break L13;
+    }
+   } while ((i22 | 0) < (HEAP32[i10 >> 2] | 0));
+  }
+ } while (0);
+ i10 = i4 + 8 | 0;
+ i24 = (HEAP32[i8 >> 2] | 0) + (i15 * 12 | 0) | 0;
+ i25 = HEAP32[i24 + 4 >> 2] | 0;
+ i23 = (HEAP32[(HEAP32[i10 >> 2] | 0) + (i15 << 2) >> 2] | 0) + 36 | 0;
+ HEAP32[i23 >> 2] = HEAP32[i24 >> 2];
+ HEAP32[i23 + 4 >> 2] = i25;
+ i23 = HEAP32[i8 >> 2] | 0;
+ i25 = HEAP32[i10 >> 2] | 0;
+ HEAPF32[(HEAP32[i25 + (i15 << 2) >> 2] | 0) + 52 >> 2] = +HEAPF32[i23 + (i15 * 12 | 0) + 8 >> 2];
+ i23 = i23 + (i18 * 12 | 0) | 0;
+ i24 = HEAP32[i23 + 4 >> 2] | 0;
+ i25 = (HEAP32[i25 + (i18 << 2) >> 2] | 0) + 36 | 0;
+ HEAP32[i25 >> 2] = HEAP32[i23 >> 2];
+ HEAP32[i25 + 4 >> 2] = i24;
+ HEAPF32[(HEAP32[(HEAP32[i10 >> 2] | 0) + (i18 << 2) >> 2] | 0) + 52 >> 2] = +HEAPF32[(HEAP32[i8 >> 2] | 0) + (i18 * 12 | 0) + 8 >> 2];
+ __ZN15b2ContactSolver29InitializeVelocityConstraintsEv(i3);
+ i18 = i11 + 12 | 0;
+ if ((HEAP32[i18 >> 2] | 0) > 0) {
+  i15 = 0;
+  do {
+   __ZN15b2ContactSolver24SolveVelocityConstraintsEv(i3);
+   i15 = i15 + 1 | 0;
+  } while ((i15 | 0) < (HEAP32[i18 >> 2] | 0));
+ }
+ d16 = +HEAPF32[i11 >> 2];
+ if ((HEAP32[i6 >> 2] | 0) > 0) {
+  i15 = 0;
+  do {
+   i25 = HEAP32[i8 >> 2] | 0;
+   i11 = i25 + (i15 * 12 | 0) | 0;
+   i24 = i11;
+   d12 = +HEAPF32[i24 >> 2];
+   d14 = +HEAPF32[i24 + 4 >> 2];
+   d13 = +HEAPF32[i25 + (i15 * 12 | 0) + 8 >> 2];
+   i25 = HEAP32[i9 >> 2] | 0;
+   i24 = i25 + (i15 * 12 | 0) | 0;
+   d19 = +HEAPF32[i24 >> 2];
+   d20 = +HEAPF32[i24 + 4 >> 2];
+   d17 = +HEAPF32[i25 + (i15 * 12 | 0) + 8 >> 2];
+   d26 = d16 * d19;
+   d21 = d16 * d20;
+   d21 = d26 * d26 + d21 * d21;
+   if (d21 > 4.0) {
+    d26 = 2.0 / +Math_sqrt(+d21);
+    d19 = d19 * d26;
+    d20 = d20 * d26;
+   }
+   d21 = d16 * d17;
+   if (d21 * d21 > 2.4674012660980225) {
+    if (!(d21 > 0.0)) {
+     d21 = -d21;
+    }
+    d17 = d17 * (1.5707963705062866 / d21);
+   }
+   d21 = d12 + d16 * d19;
+   d14 = d14 + d16 * d20;
+   d26 = d13 + d16 * d17;
+   d12 = +d21;
+   d13 = +d14;
+   i25 = i11;
+   HEAPF32[i25 >> 2] = d12;
+   HEAPF32[i25 + 4 >> 2] = d13;
+   HEAPF32[(HEAP32[i8 >> 2] | 0) + (i15 * 12 | 0) + 8 >> 2] = d26;
+   d19 = +d19;
+   d20 = +d20;
+   i25 = (HEAP32[i9 >> 2] | 0) + (i15 * 12 | 0) | 0;
+   HEAPF32[i25 >> 2] = d19;
+   HEAPF32[i25 + 4 >> 2] = d20;
+   HEAPF32[(HEAP32[i9 >> 2] | 0) + (i15 * 12 | 0) + 8 >> 2] = d17;
+   i25 = HEAP32[(HEAP32[i10 >> 2] | 0) + (i15 << 2) >> 2] | 0;
+   i24 = i25 + 44 | 0;
+   HEAPF32[i24 >> 2] = d12;
+   HEAPF32[i24 + 4 >> 2] = d13;
+   HEAPF32[i25 + 56 >> 2] = d26;
+   i24 = i25 + 64 | 0;
+   HEAPF32[i24 >> 2] = d19;
+   HEAPF32[i24 + 4 >> 2] = d20;
+   HEAPF32[i25 + 72 >> 2] = d17;
+   d17 = +Math_sin(+d26);
+   HEAPF32[i25 + 20 >> 2] = d17;
+   d20 = +Math_cos(+d26);
+   HEAPF32[i25 + 24 >> 2] = d20;
+   d19 = +HEAPF32[i25 + 28 >> 2];
+   d26 = +HEAPF32[i25 + 32 >> 2];
+   d21 = +(d21 - (d20 * d19 - d17 * d26));
+   d26 = +(d14 - (d17 * d19 + d20 * d26));
+   i25 = i25 + 12 | 0;
+   HEAPF32[i25 >> 2] = d21;
+   HEAPF32[i25 + 4 >> 2] = d26;
+   i15 = i15 + 1 | 0;
+  } while ((i15 | 0) < (HEAP32[i6 >> 2] | 0));
+ }
+ i6 = HEAP32[i3 + 40 >> 2] | 0;
+ i4 = i4 + 4 | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  __ZN15b2ContactSolverD2Ev(i3);
+  STACKTOP = i1;
+  return;
+ }
+ if ((HEAP32[i7 >> 2] | 0) <= 0) {
+  __ZN15b2ContactSolverD2Ev(i3);
+  STACKTOP = i1;
+  return;
+ }
+ i8 = i2 + 16 | 0;
+ i9 = 0;
+ do {
+  i10 = HEAP32[(HEAP32[i5 >> 2] | 0) + (i9 << 2) >> 2] | 0;
+  i11 = HEAP32[i6 + (i9 * 152 | 0) + 144 >> 2] | 0;
+  HEAP32[i8 >> 2] = i11;
+  if ((i11 | 0) > 0) {
+   i15 = 0;
+   do {
+    HEAPF32[i2 + (i15 << 2) >> 2] = +HEAPF32[i6 + (i9 * 152 | 0) + (i15 * 36 | 0) + 16 >> 2];
+    HEAPF32[i2 + (i15 << 2) + 8 >> 2] = +HEAPF32[i6 + (i9 * 152 | 0) + (i15 * 36 | 0) + 20 >> 2];
+    i15 = i15 + 1 | 0;
+   } while ((i15 | 0) != (i11 | 0));
+  }
+  i25 = HEAP32[i4 >> 2] | 0;
+  FUNCTION_TABLE_viii[HEAP32[(HEAP32[i25 >> 2] | 0) + 20 >> 2] & 3](i25, i10, i2);
+  i9 = i9 + 1 | 0;
+ } while ((i9 | 0) < (HEAP32[i7 >> 2] | 0));
+ __ZN15b2ContactSolverD2Ev(i3);
+ STACKTOP = i1;
+ return;
+}
+function __ZN20b2SeparationFunction10InitializeEPK14b2SimplexCachePK15b2DistanceProxyRK7b2SweepS5_S8_f(i2, i11, i13, i21, i12, i24, d9) {
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ i13 = i13 | 0;
+ i21 = i21 | 0;
+ i12 = i12 | 0;
+ i24 = i24 | 0;
+ d9 = +d9;
+ var i1 = 0, d3 = 0.0, d4 = 0.0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d10 = 0.0, i14 = 0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d22 = 0.0, i23 = 0, i25 = 0, i26 = 0, i27 = 0, d28 = 0.0, d29 = 0.0;
+ i1 = STACKTOP;
+ HEAP32[i2 >> 2] = i13;
+ HEAP32[i2 + 4 >> 2] = i12;
+ i14 = HEAP16[i11 + 4 >> 1] | 0;
+ if (!(i14 << 16 >> 16 != 0 & (i14 & 65535) < 3)) {
+  ___assert_fail(3744, 3560, 50, 3768);
+ }
+ i23 = i2 + 8 | 0;
+ i25 = i23 + 0 | 0;
+ i27 = i21 + 0 | 0;
+ i26 = i25 + 36 | 0;
+ do {
+  HEAP32[i25 >> 2] = HEAP32[i27 >> 2];
+  i25 = i25 + 4 | 0;
+  i27 = i27 + 4 | 0;
+ } while ((i25 | 0) < (i26 | 0));
+ i21 = i2 + 44 | 0;
+ i25 = i21 + 0 | 0;
+ i27 = i24 + 0 | 0;
+ i26 = i25 + 36 | 0;
+ do {
+  HEAP32[i25 >> 2] = HEAP32[i27 >> 2];
+  i25 = i25 + 4 | 0;
+  i27 = i27 + 4 | 0;
+ } while ((i25 | 0) < (i26 | 0));
+ d19 = 1.0 - d9;
+ d4 = d19 * +HEAPF32[i2 + 32 >> 2] + +HEAPF32[i2 + 36 >> 2] * d9;
+ d3 = +Math_sin(+d4);
+ d4 = +Math_cos(+d4);
+ d7 = +HEAPF32[i23 >> 2];
+ d5 = +HEAPF32[i2 + 12 >> 2];
+ d8 = d19 * +HEAPF32[i2 + 16 >> 2] + +HEAPF32[i2 + 24 >> 2] * d9 - (d4 * d7 - d3 * d5);
+ d5 = d19 * +HEAPF32[i2 + 20 >> 2] + +HEAPF32[i2 + 28 >> 2] * d9 - (d3 * d7 + d4 * d5);
+ d7 = d19 * +HEAPF32[i2 + 68 >> 2] + +HEAPF32[i2 + 72 >> 2] * d9;
+ d6 = +Math_sin(+d7);
+ d7 = +Math_cos(+d7);
+ d20 = +HEAPF32[i21 >> 2];
+ d22 = +HEAPF32[i2 + 48 >> 2];
+ d10 = d19 * +HEAPF32[i2 + 52 >> 2] + +HEAPF32[i2 + 60 >> 2] * d9 - (d7 * d20 - d6 * d22);
+ d9 = d19 * +HEAPF32[i2 + 56 >> 2] + +HEAPF32[i2 + 64 >> 2] * d9 - (d6 * d20 + d7 * d22);
+ if (i14 << 16 >> 16 == 1) {
+  HEAP32[i2 + 80 >> 2] = 0;
+  i14 = HEAPU8[i11 + 6 | 0] | 0;
+  if ((HEAP32[i13 + 20 >> 2] | 0) <= (i14 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i13 + 16 >> 2] | 0) + (i14 << 3) | 0;
+  d15 = +HEAPF32[i27 >> 2];
+  d16 = +HEAPF32[i27 + 4 >> 2];
+  i11 = HEAPU8[i11 + 9 | 0] | 0;
+  if ((HEAP32[i12 + 20 >> 2] | 0) <= (i11 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i11 = (HEAP32[i12 + 16 >> 2] | 0) + (i11 << 3) | 0;
+  d20 = +HEAPF32[i11 >> 2];
+  d22 = +HEAPF32[i11 + 4 >> 2];
+  i11 = i2 + 92 | 0;
+  d8 = d10 + (d7 * d20 - d6 * d22) - (d8 + (d4 * d15 - d3 * d16));
+  d4 = d9 + (d6 * d20 + d7 * d22) - (d5 + (d3 * d15 + d4 * d16));
+  d22 = +d8;
+  d3 = +d4;
+  i27 = i11;
+  HEAPF32[i27 >> 2] = d22;
+  HEAPF32[i27 + 4 >> 2] = d3;
+  d3 = +Math_sqrt(+(d8 * d8 + d4 * d4));
+  if (d3 < 1.1920928955078125e-7) {
+   d22 = 0.0;
+   STACKTOP = i1;
+   return +d22;
+  }
+  d22 = 1.0 / d3;
+  HEAPF32[i11 >> 2] = d8 * d22;
+  HEAPF32[i2 + 96 >> 2] = d4 * d22;
+  d22 = d3;
+  STACKTOP = i1;
+  return +d22;
+ }
+ i14 = i11 + 6 | 0;
+ i21 = i11 + 7 | 0;
+ i23 = i2 + 80 | 0;
+ if ((HEAP8[i14] | 0) == (HEAP8[i21] | 0)) {
+  HEAP32[i23 >> 2] = 2;
+  i23 = HEAPU8[i11 + 9 | 0] | 0;
+  i21 = HEAP32[i12 + 20 >> 2] | 0;
+  if ((i21 | 0) <= (i23 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i12 = HEAP32[i12 + 16 >> 2] | 0;
+  i27 = i12 + (i23 << 3) | 0;
+  d16 = +HEAPF32[i27 >> 2];
+  d15 = +HEAPF32[i27 + 4 >> 2];
+  i11 = HEAPU8[i11 + 10 | 0] | 0;
+  if ((i21 | 0) <= (i11 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i11 = i12 + (i11 << 3) | 0;
+  d20 = +HEAPF32[i11 >> 2];
+  d18 = +HEAPF32[i11 + 4 >> 2];
+  i11 = i2 + 92 | 0;
+  d22 = d20 - d16;
+  d19 = d18 - d15;
+  d17 = -d22;
+  d29 = +d19;
+  d28 = +d17;
+  i27 = i11;
+  HEAPF32[i27 >> 2] = d29;
+  HEAPF32[i27 + 4 >> 2] = d28;
+  d22 = +Math_sqrt(+(d19 * d19 + d22 * d22));
+  if (!(d22 < 1.1920928955078125e-7)) {
+   d29 = 1.0 / d22;
+   d19 = d19 * d29;
+   HEAPF32[i11 >> 2] = d19;
+   d17 = d29 * d17;
+   HEAPF32[i2 + 96 >> 2] = d17;
+  }
+  d16 = (d16 + d20) * .5;
+  d15 = (d15 + d18) * .5;
+  d28 = +d16;
+  d29 = +d15;
+  i2 = i2 + 84 | 0;
+  HEAPF32[i2 >> 2] = d28;
+  HEAPF32[i2 + 4 >> 2] = d29;
+  i2 = HEAPU8[i14] | 0;
+  if ((HEAP32[i13 + 20 >> 2] | 0) <= (i2 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i13 + 16 >> 2] | 0) + (i2 << 3) | 0;
+  d28 = +HEAPF32[i27 >> 2];
+  d29 = +HEAPF32[i27 + 4 >> 2];
+  d3 = (d7 * d19 - d6 * d17) * (d8 + (d4 * d28 - d3 * d29) - (d10 + (d7 * d16 - d6 * d15))) + (d6 * d19 + d7 * d17) * (d5 + (d3 * d28 + d4 * d29) - (d9 + (d6 * d16 + d7 * d15)));
+  if (!(d3 < 0.0)) {
+   d29 = d3;
+   STACKTOP = i1;
+   return +d29;
+  }
+  d28 = +-d19;
+  d29 = +-d17;
+  i27 = i11;
+  HEAPF32[i27 >> 2] = d28;
+  HEAPF32[i27 + 4 >> 2] = d29;
+  d29 = -d3;
+  STACKTOP = i1;
+  return +d29;
+ } else {
+  HEAP32[i23 >> 2] = 1;
+  i23 = HEAPU8[i14] | 0;
+  i14 = HEAP32[i13 + 20 >> 2] | 0;
+  if ((i14 | 0) <= (i23 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i13 = HEAP32[i13 + 16 >> 2] | 0;
+  i27 = i13 + (i23 << 3) | 0;
+  d16 = +HEAPF32[i27 >> 2];
+  d15 = +HEAPF32[i27 + 4 >> 2];
+  i21 = HEAPU8[i21] | 0;
+  if ((i14 | 0) <= (i21 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i13 = i13 + (i21 << 3) | 0;
+  d20 = +HEAPF32[i13 >> 2];
+  d18 = +HEAPF32[i13 + 4 >> 2];
+  i13 = i2 + 92 | 0;
+  d22 = d20 - d16;
+  d19 = d18 - d15;
+  d17 = -d22;
+  d28 = +d19;
+  d29 = +d17;
+  i27 = i13;
+  HEAPF32[i27 >> 2] = d28;
+  HEAPF32[i27 + 4 >> 2] = d29;
+  d22 = +Math_sqrt(+(d19 * d19 + d22 * d22));
+  if (!(d22 < 1.1920928955078125e-7)) {
+   d29 = 1.0 / d22;
+   d19 = d19 * d29;
+   HEAPF32[i13 >> 2] = d19;
+   d17 = d29 * d17;
+   HEAPF32[i2 + 96 >> 2] = d17;
+  }
+  d16 = (d16 + d20) * .5;
+  d15 = (d15 + d18) * .5;
+  d28 = +d16;
+  d29 = +d15;
+  i2 = i2 + 84 | 0;
+  HEAPF32[i2 >> 2] = d28;
+  HEAPF32[i2 + 4 >> 2] = d29;
+  i2 = HEAPU8[i11 + 9 | 0] | 0;
+  if ((HEAP32[i12 + 20 >> 2] | 0) <= (i2 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i12 + 16 >> 2] | 0) + (i2 << 3) | 0;
+  d28 = +HEAPF32[i27 >> 2];
+  d29 = +HEAPF32[i27 + 4 >> 2];
+  d3 = (d4 * d19 - d3 * d17) * (d10 + (d7 * d28 - d6 * d29) - (d8 + (d4 * d16 - d3 * d15))) + (d3 * d19 + d4 * d17) * (d9 + (d6 * d28 + d7 * d29) - (d5 + (d3 * d16 + d4 * d15)));
+  if (!(d3 < 0.0)) {
+   d29 = d3;
+   STACKTOP = i1;
+   return +d29;
+  }
+  d28 = +-d19;
+  d29 = +-d17;
+  i27 = i13;
+  HEAPF32[i27 >> 2] = d28;
+  HEAPF32[i27 + 4 >> 2] = d29;
+  d29 = -d3;
+  STACKTOP = i1;
+  return +d29;
+ }
+ return 0.0;
+}
+function __ZNK20b2SeparationFunction17FindMinSeparationEPiS0_f(i12, i10, i9, d5) {
+ i12 = i12 | 0;
+ i10 = i10 | 0;
+ i9 = i9 | 0;
+ d5 = +d5;
+ var i1 = 0, d2 = 0.0, d3 = 0.0, d4 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d11 = 0.0, d13 = 0.0, d14 = 0.0, i15 = 0, i16 = 0, d17 = 0.0, d18 = 0.0, i19 = 0, d20 = 0.0, d21 = 0.0, i22 = 0, d23 = 0.0, d24 = 0.0, i25 = 0, i26 = 0, i27 = 0;
+ i1 = STACKTOP;
+ d21 = 1.0 - d5;
+ d6 = d21 * +HEAPF32[i12 + 32 >> 2] + +HEAPF32[i12 + 36 >> 2] * d5;
+ d7 = +Math_sin(+d6);
+ d6 = +Math_cos(+d6);
+ d3 = +HEAPF32[i12 + 8 >> 2];
+ d8 = +HEAPF32[i12 + 12 >> 2];
+ d11 = d21 * +HEAPF32[i12 + 16 >> 2] + +HEAPF32[i12 + 24 >> 2] * d5 - (d6 * d3 - d7 * d8);
+ d8 = d21 * +HEAPF32[i12 + 20 >> 2] + +HEAPF32[i12 + 28 >> 2] * d5 - (d7 * d3 + d6 * d8);
+ d3 = d21 * +HEAPF32[i12 + 68 >> 2] + +HEAPF32[i12 + 72 >> 2] * d5;
+ d2 = +Math_sin(+d3);
+ d3 = +Math_cos(+d3);
+ d23 = +HEAPF32[i12 + 44 >> 2];
+ d24 = +HEAPF32[i12 + 48 >> 2];
+ d4 = d21 * +HEAPF32[i12 + 52 >> 2] + +HEAPF32[i12 + 60 >> 2] * d5 - (d3 * d23 - d2 * d24);
+ d5 = d21 * +HEAPF32[i12 + 56 >> 2] + +HEAPF32[i12 + 64 >> 2] * d5 - (d2 * d23 + d3 * d24);
+ i19 = HEAP32[i12 + 80 >> 2] | 0;
+ if ((i19 | 0) == 1) {
+  d23 = +HEAPF32[i12 + 92 >> 2];
+  d14 = +HEAPF32[i12 + 96 >> 2];
+  d13 = d6 * d23 - d7 * d14;
+  d14 = d7 * d23 + d6 * d14;
+  d23 = +HEAPF32[i12 + 84 >> 2];
+  d24 = +HEAPF32[i12 + 88 >> 2];
+  d11 = d11 + (d6 * d23 - d7 * d24);
+  d6 = d8 + (d7 * d23 + d6 * d24);
+  d7 = -d13;
+  d24 = -d14;
+  d8 = d3 * d7 + d2 * d24;
+  d7 = d3 * d24 - d2 * d7;
+  HEAP32[i10 >> 2] = -1;
+  i25 = i12 + 4 | 0;
+  i22 = HEAP32[i25 >> 2] | 0;
+  i19 = HEAP32[i22 + 16 >> 2] | 0;
+  i22 = HEAP32[i22 + 20 >> 2] | 0;
+  if ((i22 | 0) > 1) {
+   i10 = 0;
+   d18 = d7 * +HEAPF32[i19 + 4 >> 2] + d8 * +HEAPF32[i19 >> 2];
+   i12 = 1;
+   while (1) {
+    d17 = d8 * +HEAPF32[i19 + (i12 << 3) >> 2] + d7 * +HEAPF32[i19 + (i12 << 3) + 4 >> 2];
+    i16 = d17 > d18;
+    i10 = i16 ? i12 : i10;
+    i12 = i12 + 1 | 0;
+    if ((i12 | 0) == (i22 | 0)) {
+     break;
+    } else {
+     d18 = i16 ? d17 : d18;
+    }
+   }
+   HEAP32[i9 >> 2] = i10;
+   if ((i10 | 0) > -1) {
+    i15 = i10;
+   } else {
+    ___assert_fail(3640, 3672, 103, 3704);
+   }
+  } else {
+   HEAP32[i9 >> 2] = 0;
+   i15 = 0;
+  }
+  i9 = HEAP32[i25 >> 2] | 0;
+  if ((HEAP32[i9 + 20 >> 2] | 0) <= (i15 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i9 + 16 >> 2] | 0) + (i15 << 3) | 0;
+  d23 = +HEAPF32[i27 >> 2];
+  d24 = +HEAPF32[i27 + 4 >> 2];
+  d24 = d13 * (d4 + (d3 * d23 - d2 * d24) - d11) + d14 * (d5 + (d2 * d23 + d3 * d24) - d6);
+  STACKTOP = i1;
+  return +d24;
+ } else if ((i19 | 0) == 0) {
+  d13 = +HEAPF32[i12 + 92 >> 2];
+  d14 = +HEAPF32[i12 + 96 >> 2];
+  d21 = d6 * d13 + d7 * d14;
+  d24 = d6 * d14 - d7 * d13;
+  d17 = -d13;
+  d23 = -d14;
+  d18 = d3 * d17 + d2 * d23;
+  d17 = d3 * d23 - d2 * d17;
+  i15 = HEAP32[i12 >> 2] | 0;
+  i16 = HEAP32[i15 + 16 >> 2] | 0;
+  i15 = i15 + 20 | 0;
+  i19 = HEAP32[i15 >> 2] | 0;
+  if ((i19 | 0) > 1) {
+   i25 = 0;
+   d23 = d24 * +HEAPF32[i16 + 4 >> 2] + d21 * +HEAPF32[i16 >> 2];
+   i26 = 1;
+   while (1) {
+    d20 = d21 * +HEAPF32[i16 + (i26 << 3) >> 2] + d24 * +HEAPF32[i16 + (i26 << 3) + 4 >> 2];
+    i22 = d20 > d23;
+    i25 = i22 ? i26 : i25;
+    i26 = i26 + 1 | 0;
+    if ((i26 | 0) == (i19 | 0)) {
+     break;
+    } else {
+     d23 = i22 ? d20 : d23;
+    }
+   }
+  } else {
+   i25 = 0;
+  }
+  HEAP32[i10 >> 2] = i25;
+  i19 = HEAP32[i12 + 4 >> 2] | 0;
+  i12 = HEAP32[i19 + 16 >> 2] | 0;
+  i19 = i19 + 20 | 0;
+  i25 = HEAP32[i19 >> 2] | 0;
+  if ((i25 | 0) > 1) {
+   i27 = 0;
+   d20 = d17 * +HEAPF32[i12 + 4 >> 2] + d18 * +HEAPF32[i12 >> 2];
+   i26 = 1;
+   while (1) {
+    d21 = d18 * +HEAPF32[i12 + (i26 << 3) >> 2] + d17 * +HEAPF32[i12 + (i26 << 3) + 4 >> 2];
+    i22 = d21 > d20;
+    i27 = i22 ? i26 : i27;
+    i26 = i26 + 1 | 0;
+    if ((i26 | 0) == (i25 | 0)) {
+     break;
+    } else {
+     d20 = i22 ? d21 : d20;
+    }
+   }
+  } else {
+   i27 = 0;
+  }
+  HEAP32[i9 >> 2] = i27;
+  i9 = HEAP32[i10 >> 2] | 0;
+  if (!((i9 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i15 >> 2] | 0) <= (i9 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i26 = i16 + (i9 << 3) | 0;
+  d18 = +HEAPF32[i26 >> 2];
+  d17 = +HEAPF32[i26 + 4 >> 2];
+  if (!((i27 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i19 >> 2] | 0) <= (i27 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = i12 + (i27 << 3) | 0;
+  d23 = +HEAPF32[i27 >> 2];
+  d24 = +HEAPF32[i27 + 4 >> 2];
+  d24 = d13 * (d4 + (d3 * d23 - d2 * d24) - (d11 + (d6 * d18 - d7 * d17))) + d14 * (d5 + (d2 * d23 + d3 * d24) - (d8 + (d7 * d18 + d6 * d17)));
+  STACKTOP = i1;
+  return +d24;
+ } else if ((i19 | 0) == 2) {
+  d23 = +HEAPF32[i12 + 92 >> 2];
+  d13 = +HEAPF32[i12 + 96 >> 2];
+  d14 = d3 * d23 - d2 * d13;
+  d13 = d2 * d23 + d3 * d13;
+  d23 = +HEAPF32[i12 + 84 >> 2];
+  d24 = +HEAPF32[i12 + 88 >> 2];
+  d4 = d4 + (d3 * d23 - d2 * d24);
+  d2 = d5 + (d2 * d23 + d3 * d24);
+  d3 = -d14;
+  d24 = -d13;
+  d5 = d6 * d3 + d7 * d24;
+  d3 = d6 * d24 - d7 * d3;
+  HEAP32[i9 >> 2] = -1;
+  i22 = HEAP32[i12 >> 2] | 0;
+  i15 = HEAP32[i22 + 16 >> 2] | 0;
+  i22 = HEAP32[i22 + 20 >> 2] | 0;
+  if ((i22 | 0) > 1) {
+   i9 = 0;
+   d17 = d3 * +HEAPF32[i15 + 4 >> 2] + d5 * +HEAPF32[i15 >> 2];
+   i19 = 1;
+   while (1) {
+    d18 = d5 * +HEAPF32[i15 + (i19 << 3) >> 2] + d3 * +HEAPF32[i15 + (i19 << 3) + 4 >> 2];
+    i25 = d18 > d17;
+    i9 = i25 ? i19 : i9;
+    i19 = i19 + 1 | 0;
+    if ((i19 | 0) == (i22 | 0)) {
+     break;
+    } else {
+     d17 = i25 ? d18 : d17;
+    }
+   }
+   HEAP32[i10 >> 2] = i9;
+   if ((i9 | 0) > -1) {
+    i16 = i9;
+   } else {
+    ___assert_fail(3640, 3672, 103, 3704);
+   }
+  } else {
+   HEAP32[i10 >> 2] = 0;
+   i16 = 0;
+  }
+  i9 = HEAP32[i12 >> 2] | 0;
+  if ((HEAP32[i9 + 20 >> 2] | 0) <= (i16 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i27 = (HEAP32[i9 + 16 >> 2] | 0) + (i16 << 3) | 0;
+  d23 = +HEAPF32[i27 >> 2];
+  d24 = +HEAPF32[i27 + 4 >> 2];
+  d24 = d14 * (d11 + (d6 * d23 - d7 * d24) - d4) + d13 * (d8 + (d7 * d23 + d6 * d24) - d2);
+  STACKTOP = i1;
+  return +d24;
+ } else {
+  ___assert_fail(3616, 3560, 183, 3720);
+ }
+ return 0.0;
+}
+function __ZN13b2DynamicTree10InsertLeafEi(i3, i4) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, d22 = 0.0, d23 = 0.0, i24 = 0;
+ i1 = STACKTOP;
+ i11 = i3 + 24 | 0;
+ HEAP32[i11 >> 2] = (HEAP32[i11 >> 2] | 0) + 1;
+ i11 = HEAP32[i3 >> 2] | 0;
+ if ((i11 | 0) == -1) {
+  HEAP32[i3 >> 2] = i4;
+  HEAP32[(HEAP32[i3 + 4 >> 2] | 0) + (i4 * 36 | 0) + 20 >> 2] = -1;
+  STACKTOP = i1;
+  return;
+ }
+ i2 = i3 + 4 | 0;
+ i9 = HEAP32[i2 >> 2] | 0;
+ d8 = +HEAPF32[i9 + (i4 * 36 | 0) >> 2];
+ d7 = +HEAPF32[i9 + (i4 * 36 | 0) + 4 >> 2];
+ d6 = +HEAPF32[i9 + (i4 * 36 | 0) + 8 >> 2];
+ d5 = +HEAPF32[i9 + (i4 * 36 | 0) + 12 >> 2];
+ i10 = HEAP32[i9 + (i11 * 36 | 0) + 24 >> 2] | 0;
+ L5 : do {
+  if (!((i10 | 0) == -1)) {
+   do {
+    i12 = HEAP32[i9 + (i11 * 36 | 0) + 28 >> 2] | 0;
+    d14 = +HEAPF32[i9 + (i11 * 36 | 0) + 8 >> 2];
+    d15 = +HEAPF32[i9 + (i11 * 36 | 0) >> 2];
+    d17 = +HEAPF32[i9 + (i11 * 36 | 0) + 12 >> 2];
+    d16 = +HEAPF32[i9 + (i11 * 36 | 0) + 4 >> 2];
+    d21 = ((d14 > d6 ? d14 : d6) - (d15 < d8 ? d15 : d8) + ((d17 > d5 ? d17 : d5) - (d16 < d7 ? d16 : d7))) * 2.0;
+    d13 = d21 * 2.0;
+    d14 = (d21 - (d14 - d15 + (d17 - d16)) * 2.0) * 2.0;
+    d21 = +HEAPF32[i9 + (i10 * 36 | 0) >> 2];
+    d16 = d8 < d21 ? d8 : d21;
+    d17 = +HEAPF32[i9 + (i10 * 36 | 0) + 4 >> 2];
+    d18 = d7 < d17 ? d7 : d17;
+    d19 = +HEAPF32[i9 + (i10 * 36 | 0) + 8 >> 2];
+    d20 = d6 > d19 ? d6 : d19;
+    d15 = +HEAPF32[i9 + (i10 * 36 | 0) + 12 >> 2];
+    d22 = d5 > d15 ? d5 : d15;
+    if ((HEAP32[i9 + (i10 * 36 | 0) + 24 >> 2] | 0) == -1) {
+     d15 = (d20 - d16 + (d22 - d18)) * 2.0;
+    } else {
+     d15 = (d20 - d16 + (d22 - d18)) * 2.0 - (d19 - d21 + (d15 - d17)) * 2.0;
+    }
+    d15 = d14 + d15;
+    d17 = +HEAPF32[i9 + (i12 * 36 | 0) >> 2];
+    d18 = d8 < d17 ? d8 : d17;
+    d23 = +HEAPF32[i9 + (i12 * 36 | 0) + 4 >> 2];
+    d22 = d7 < d23 ? d7 : d23;
+    d21 = +HEAPF32[i9 + (i12 * 36 | 0) + 8 >> 2];
+    d20 = d6 > d21 ? d6 : d21;
+    d19 = +HEAPF32[i9 + (i12 * 36 | 0) + 12 >> 2];
+    d16 = d5 > d19 ? d5 : d19;
+    if ((HEAP32[i9 + (i12 * 36 | 0) + 24 >> 2] | 0) == -1) {
+     d16 = (d20 - d18 + (d16 - d22)) * 2.0;
+    } else {
+     d16 = (d20 - d18 + (d16 - d22)) * 2.0 - (d21 - d17 + (d19 - d23)) * 2.0;
+    }
+    d14 = d14 + d16;
+    if (d13 < d15 & d13 < d14) {
+     break L5;
+    }
+    i11 = d15 < d14 ? i10 : i12;
+    i10 = HEAP32[i9 + (i11 * 36 | 0) + 24 >> 2] | 0;
+   } while (!((i10 | 0) == -1));
+  }
+ } while (0);
+ i9 = HEAP32[i9 + (i11 * 36 | 0) + 20 >> 2] | 0;
+ i10 = __ZN13b2DynamicTree12AllocateNodeEv(i3) | 0;
+ i12 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i12 + (i10 * 36 | 0) + 20 >> 2] = i9;
+ HEAP32[i12 + (i10 * 36 | 0) + 16 >> 2] = 0;
+ i12 = HEAP32[i2 >> 2] | 0;
+ d14 = +HEAPF32[i12 + (i11 * 36 | 0) >> 2];
+ d13 = +HEAPF32[i12 + (i11 * 36 | 0) + 4 >> 2];
+ d8 = +(d8 < d14 ? d8 : d14);
+ d7 = +(d7 < d13 ? d7 : d13);
+ i24 = i12 + (i10 * 36 | 0) | 0;
+ HEAPF32[i24 >> 2] = d8;
+ HEAPF32[i24 + 4 >> 2] = d7;
+ d8 = +HEAPF32[i12 + (i11 * 36 | 0) + 8 >> 2];
+ d7 = +HEAPF32[i12 + (i11 * 36 | 0) + 12 >> 2];
+ d6 = +(d6 > d8 ? d6 : d8);
+ d23 = +(d5 > d7 ? d5 : d7);
+ i12 = i12 + (i10 * 36 | 0) + 8 | 0;
+ HEAPF32[i12 >> 2] = d6;
+ HEAPF32[i12 + 4 >> 2] = d23;
+ i12 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i12 + (i10 * 36 | 0) + 32 >> 2] = (HEAP32[i12 + (i11 * 36 | 0) + 32 >> 2] | 0) + 1;
+ if ((i9 | 0) == -1) {
+  HEAP32[i12 + (i10 * 36 | 0) + 24 >> 2] = i11;
+  HEAP32[i12 + (i10 * 36 | 0) + 28 >> 2] = i4;
+  HEAP32[i12 + (i11 * 36 | 0) + 20 >> 2] = i10;
+  i24 = i12 + (i4 * 36 | 0) + 20 | 0;
+  HEAP32[i24 >> 2] = i10;
+  HEAP32[i3 >> 2] = i10;
+  i10 = HEAP32[i24 >> 2] | 0;
+ } else {
+  i24 = i12 + (i9 * 36 | 0) + 24 | 0;
+  if ((HEAP32[i24 >> 2] | 0) == (i11 | 0)) {
+   HEAP32[i24 >> 2] = i10;
+  } else {
+   HEAP32[i12 + (i9 * 36 | 0) + 28 >> 2] = i10;
+  }
+  HEAP32[i12 + (i10 * 36 | 0) + 24 >> 2] = i11;
+  HEAP32[i12 + (i10 * 36 | 0) + 28 >> 2] = i4;
+  HEAP32[i12 + (i11 * 36 | 0) + 20 >> 2] = i10;
+  HEAP32[i12 + (i4 * 36 | 0) + 20 >> 2] = i10;
+ }
+ if ((i10 | 0) == -1) {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i9 = __ZN13b2DynamicTree7BalanceEi(i3, i10) | 0;
+  i4 = HEAP32[i2 >> 2] | 0;
+  i11 = HEAP32[i4 + (i9 * 36 | 0) + 24 >> 2] | 0;
+  i10 = HEAP32[i4 + (i9 * 36 | 0) + 28 >> 2] | 0;
+  if ((i11 | 0) == -1) {
+   i2 = 20;
+   break;
+  }
+  if ((i10 | 0) == -1) {
+   i2 = 22;
+   break;
+  }
+  i12 = HEAP32[i4 + (i11 * 36 | 0) + 32 >> 2] | 0;
+  i24 = HEAP32[i4 + (i10 * 36 | 0) + 32 >> 2] | 0;
+  HEAP32[i4 + (i9 * 36 | 0) + 32 >> 2] = ((i12 | 0) > (i24 | 0) ? i12 : i24) + 1;
+  d7 = +HEAPF32[i4 + (i11 * 36 | 0) >> 2];
+  d8 = +HEAPF32[i4 + (i10 * 36 | 0) >> 2];
+  d5 = +HEAPF32[i4 + (i11 * 36 | 0) + 4 >> 2];
+  d6 = +HEAPF32[i4 + (i10 * 36 | 0) + 4 >> 2];
+  d7 = +(d7 < d8 ? d7 : d8);
+  d5 = +(d5 < d6 ? d5 : d6);
+  i24 = i4 + (i9 * 36 | 0) | 0;
+  HEAPF32[i24 >> 2] = d7;
+  HEAPF32[i24 + 4 >> 2] = d5;
+  d5 = +HEAPF32[i4 + (i11 * 36 | 0) + 8 >> 2];
+  d6 = +HEAPF32[i4 + (i10 * 36 | 0) + 8 >> 2];
+  d7 = +HEAPF32[i4 + (i11 * 36 | 0) + 12 >> 2];
+  d8 = +HEAPF32[i4 + (i10 * 36 | 0) + 12 >> 2];
+  d5 = +(d5 > d6 ? d5 : d6);
+  d23 = +(d7 > d8 ? d7 : d8);
+  i10 = i4 + (i9 * 36 | 0) + 8 | 0;
+  HEAPF32[i10 >> 2] = d5;
+  HEAPF32[i10 + 4 >> 2] = d23;
+  i10 = HEAP32[(HEAP32[i2 >> 2] | 0) + (i9 * 36 | 0) + 20 >> 2] | 0;
+  if ((i10 | 0) == -1) {
+   i2 = 24;
+   break;
+  }
+ }
+ if ((i2 | 0) == 20) {
+  ___assert_fail(3168, 2944, 307, 3184);
+ } else if ((i2 | 0) == 22) {
+  ___assert_fail(3200, 2944, 308, 3184);
+ } else if ((i2 | 0) == 24) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function __ZN15b2ContactSolverC2EP18b2ContactSolverDef(i7, i5) {
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, d15 = 0.0, d16 = 0.0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0;
+ i1 = STACKTOP;
+ HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+ HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+ HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ HEAP32[i7 + 12 >> 2] = HEAP32[i5 + 12 >> 2];
+ HEAP32[i7 + 16 >> 2] = HEAP32[i5 + 16 >> 2];
+ HEAP32[i7 + 20 >> 2] = HEAP32[i5 + 20 >> 2];
+ i14 = HEAP32[i5 + 40 >> 2] | 0;
+ i9 = i7 + 32 | 0;
+ HEAP32[i9 >> 2] = i14;
+ i2 = HEAP32[i5 + 28 >> 2] | 0;
+ i4 = i7 + 48 | 0;
+ HEAP32[i4 >> 2] = i2;
+ i3 = i7 + 36 | 0;
+ HEAP32[i3 >> 2] = __ZN16b2StackAllocator8AllocateEi(i14, i2 * 88 | 0) | 0;
+ i2 = i7 + 40 | 0;
+ HEAP32[i2 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i9 >> 2] | 0, (HEAP32[i4 >> 2] | 0) * 152 | 0) | 0;
+ HEAP32[i7 + 24 >> 2] = HEAP32[i5 + 32 >> 2];
+ HEAP32[i7 + 28 >> 2] = HEAP32[i5 + 36 >> 2];
+ i9 = HEAP32[i5 + 24 >> 2] | 0;
+ i5 = i7 + 44 | 0;
+ HEAP32[i5 >> 2] = i9;
+ if ((HEAP32[i4 >> 2] | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i6 = i7 + 20 | 0;
+ i7 = i7 + 8 | 0;
+ i8 = 0;
+ while (1) {
+  i10 = HEAP32[i9 + (i8 << 2) >> 2] | 0;
+  i11 = HEAP32[i10 + 48 >> 2] | 0;
+  i12 = HEAP32[i10 + 52 >> 2] | 0;
+  i14 = HEAP32[i11 + 8 >> 2] | 0;
+  i13 = HEAP32[i12 + 8 >> 2] | 0;
+  i9 = HEAP32[i10 + 124 >> 2] | 0;
+  if ((i9 | 0) <= 0) {
+   i2 = 4;
+   break;
+  }
+  d15 = +HEAPF32[(HEAP32[i12 + 12 >> 2] | 0) + 8 >> 2];
+  d16 = +HEAPF32[(HEAP32[i11 + 12 >> 2] | 0) + 8 >> 2];
+  i12 = HEAP32[i2 >> 2] | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 136 >> 2] = +HEAPF32[i10 + 136 >> 2];
+  HEAPF32[i12 + (i8 * 152 | 0) + 140 >> 2] = +HEAPF32[i10 + 140 >> 2];
+  i22 = i14 + 8 | 0;
+  HEAP32[i12 + (i8 * 152 | 0) + 112 >> 2] = HEAP32[i22 >> 2];
+  i21 = i13 + 8 | 0;
+  HEAP32[i12 + (i8 * 152 | 0) + 116 >> 2] = HEAP32[i21 >> 2];
+  i19 = i14 + 120 | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 120 >> 2] = +HEAPF32[i19 >> 2];
+  i20 = i13 + 120 | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 124 >> 2] = +HEAPF32[i20 >> 2];
+  i18 = i14 + 128 | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 128 >> 2] = +HEAPF32[i18 >> 2];
+  i17 = i13 + 128 | 0;
+  HEAPF32[i12 + (i8 * 152 | 0) + 132 >> 2] = +HEAPF32[i17 >> 2];
+  HEAP32[i12 + (i8 * 152 | 0) + 148 >> 2] = i8;
+  HEAP32[i12 + (i8 * 152 | 0) + 144 >> 2] = i9;
+  i11 = i12 + (i8 * 152 | 0) + 80 | 0;
+  HEAP32[i11 + 0 >> 2] = 0;
+  HEAP32[i11 + 4 >> 2] = 0;
+  HEAP32[i11 + 8 >> 2] = 0;
+  HEAP32[i11 + 12 >> 2] = 0;
+  HEAP32[i11 + 16 >> 2] = 0;
+  HEAP32[i11 + 20 >> 2] = 0;
+  HEAP32[i11 + 24 >> 2] = 0;
+  HEAP32[i11 + 28 >> 2] = 0;
+  i11 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i11 + (i8 * 88 | 0) + 32 >> 2] = HEAP32[i22 >> 2];
+  HEAP32[i11 + (i8 * 88 | 0) + 36 >> 2] = HEAP32[i21 >> 2];
+  HEAPF32[i11 + (i8 * 88 | 0) + 40 >> 2] = +HEAPF32[i19 >> 2];
+  HEAPF32[i11 + (i8 * 88 | 0) + 44 >> 2] = +HEAPF32[i20 >> 2];
+  i20 = i14 + 28 | 0;
+  i14 = HEAP32[i20 + 4 >> 2] | 0;
+  i19 = i11 + (i8 * 88 | 0) + 48 | 0;
+  HEAP32[i19 >> 2] = HEAP32[i20 >> 2];
+  HEAP32[i19 + 4 >> 2] = i14;
+  i19 = i13 + 28 | 0;
+  i14 = HEAP32[i19 + 4 >> 2] | 0;
+  i13 = i11 + (i8 * 88 | 0) + 56 | 0;
+  HEAP32[i13 >> 2] = HEAP32[i19 >> 2];
+  HEAP32[i13 + 4 >> 2] = i14;
+  HEAPF32[i11 + (i8 * 88 | 0) + 64 >> 2] = +HEAPF32[i18 >> 2];
+  HEAPF32[i11 + (i8 * 88 | 0) + 68 >> 2] = +HEAPF32[i17 >> 2];
+  i13 = i10 + 104 | 0;
+  i14 = HEAP32[i13 + 4 >> 2] | 0;
+  i17 = i11 + (i8 * 88 | 0) + 16 | 0;
+  HEAP32[i17 >> 2] = HEAP32[i13 >> 2];
+  HEAP32[i17 + 4 >> 2] = i14;
+  i17 = i10 + 112 | 0;
+  i14 = HEAP32[i17 + 4 >> 2] | 0;
+  i13 = i11 + (i8 * 88 | 0) + 24 | 0;
+  HEAP32[i13 >> 2] = HEAP32[i17 >> 2];
+  HEAP32[i13 + 4 >> 2] = i14;
+  HEAP32[i11 + (i8 * 88 | 0) + 84 >> 2] = i9;
+  HEAPF32[i11 + (i8 * 88 | 0) + 76 >> 2] = d16;
+  HEAPF32[i11 + (i8 * 88 | 0) + 80 >> 2] = d15;
+  HEAP32[i11 + (i8 * 88 | 0) + 72 >> 2] = HEAP32[i10 + 120 >> 2];
+  i13 = 0;
+  do {
+   i14 = i10 + (i13 * 20 | 0) + 64 | 0;
+   if ((HEAP8[i6] | 0) == 0) {
+    HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 16 >> 2] = 0.0;
+    HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 20 >> 2] = 0.0;
+   } else {
+    HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 16 >> 2] = +HEAPF32[i7 >> 2] * +HEAPF32[i10 + (i13 * 20 | 0) + 72 >> 2];
+    HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 20 >> 2] = +HEAPF32[i7 >> 2] * +HEAPF32[i10 + (i13 * 20 | 0) + 76 >> 2];
+   }
+   i20 = i12 + (i8 * 152 | 0) + (i13 * 36 | 0) | 0;
+   HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 24 >> 2] = 0.0;
+   HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 28 >> 2] = 0.0;
+   HEAPF32[i12 + (i8 * 152 | 0) + (i13 * 36 | 0) + 32 >> 2] = 0.0;
+   i22 = i11 + (i8 * 88 | 0) + (i13 << 3) | 0;
+   HEAP32[i20 + 0 >> 2] = 0;
+   HEAP32[i20 + 4 >> 2] = 0;
+   HEAP32[i20 + 8 >> 2] = 0;
+   HEAP32[i20 + 12 >> 2] = 0;
+   i20 = i14;
+   i21 = HEAP32[i20 + 4 >> 2] | 0;
+   HEAP32[i22 >> 2] = HEAP32[i20 >> 2];
+   HEAP32[i22 + 4 >> 2] = i21;
+   i13 = i13 + 1 | 0;
+  } while ((i13 | 0) != (i9 | 0));
+  i8 = i8 + 1 | 0;
+  if ((i8 | 0) >= (HEAP32[i4 >> 2] | 0)) {
+   i2 = 12;
+   break;
+  }
+  i9 = HEAP32[i5 >> 2] | 0;
+ }
+ if ((i2 | 0) == 4) {
+  ___assert_fail(6504, 6520, 71, 6568);
+ } else if ((i2 | 0) == 12) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function __Z25b2CollidePolygonAndCircleP10b2ManifoldPK14b2PolygonShapeRK11b2TransformPK13b2CircleShapeS6_(i1, i4, i11, i9, i10) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i11 = i11 | 0;
+ i9 = i9 | 0;
+ i10 = i10 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, i12 = 0, d13 = 0.0, d14 = 0.0, i15 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, i22 = 0;
+ i3 = STACKTOP;
+ i5 = i1 + 60 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i2 = i9 + 12 | 0;
+ d20 = +HEAPF32[i10 + 12 >> 2];
+ d7 = +HEAPF32[i2 >> 2];
+ d6 = +HEAPF32[i10 + 8 >> 2];
+ d21 = +HEAPF32[i9 + 16 >> 2];
+ d8 = +HEAPF32[i10 >> 2] + (d20 * d7 - d6 * d21) - +HEAPF32[i11 >> 2];
+ d21 = d7 * d6 + d20 * d21 + +HEAPF32[i10 + 4 >> 2] - +HEAPF32[i11 + 4 >> 2];
+ d20 = +HEAPF32[i11 + 12 >> 2];
+ d6 = +HEAPF32[i11 + 8 >> 2];
+ d7 = d8 * d20 + d21 * d6;
+ d6 = d20 * d21 - d8 * d6;
+ d8 = +HEAPF32[i4 + 8 >> 2] + +HEAPF32[i9 + 8 >> 2];
+ i12 = HEAP32[i4 + 148 >> 2] | 0;
+ do {
+  if ((i12 | 0) > 0) {
+   i10 = 0;
+   i9 = 0;
+   d13 = -3.4028234663852886e+38;
+   while (1) {
+    d14 = (d7 - +HEAPF32[i4 + (i10 << 3) + 20 >> 2]) * +HEAPF32[i4 + (i10 << 3) + 84 >> 2] + (d6 - +HEAPF32[i4 + (i10 << 3) + 24 >> 2]) * +HEAPF32[i4 + (i10 << 3) + 88 >> 2];
+    if (d14 > d8) {
+     i10 = 19;
+     break;
+    }
+    i11 = d14 > d13;
+    d13 = i11 ? d14 : d13;
+    i9 = i11 ? i10 : i9;
+    i10 = i10 + 1 | 0;
+    if ((i10 | 0) >= (i12 | 0)) {
+     i10 = 4;
+     break;
+    }
+   }
+   if ((i10 | 0) == 4) {
+    i22 = d13 < 1.1920928955078125e-7;
+    break;
+   } else if ((i10 | 0) == 19) {
+    STACKTOP = i3;
+    return;
+   }
+  } else {
+   i9 = 0;
+   i22 = 1;
+  }
+ } while (0);
+ i15 = i9 + 1 | 0;
+ i11 = i4 + (i9 << 3) + 20 | 0;
+ i10 = HEAP32[i11 >> 2] | 0;
+ i11 = HEAP32[i11 + 4 >> 2] | 0;
+ d14 = (HEAP32[tempDoublePtr >> 2] = i10, +HEAPF32[tempDoublePtr >> 2]);
+ d13 = (HEAP32[tempDoublePtr >> 2] = i11, +HEAPF32[tempDoublePtr >> 2]);
+ i12 = i4 + (((i15 | 0) < (i12 | 0) ? i15 : 0) << 3) + 20 | 0;
+ i15 = HEAP32[i12 >> 2] | 0;
+ i12 = HEAP32[i12 + 4 >> 2] | 0;
+ d21 = (HEAP32[tempDoublePtr >> 2] = i15, +HEAPF32[tempDoublePtr >> 2]);
+ d18 = (HEAP32[tempDoublePtr >> 2] = i12, +HEAPF32[tempDoublePtr >> 2]);
+ if (i22) {
+  HEAP32[i5 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 1;
+  i22 = i4 + (i9 << 3) + 84 | 0;
+  i15 = HEAP32[i22 + 4 >> 2] | 0;
+  i12 = i1 + 40 | 0;
+  HEAP32[i12 >> 2] = HEAP32[i22 >> 2];
+  HEAP32[i12 + 4 >> 2] = i15;
+  d20 = +((d14 + d21) * .5);
+  d21 = +((d13 + d18) * .5);
+  i12 = i1 + 48 | 0;
+  HEAPF32[i12 >> 2] = d20;
+  HEAPF32[i12 + 4 >> 2] = d21;
+  i12 = i2;
+  i15 = HEAP32[i12 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i12 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  HEAP32[i1 + 16 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ }
+ d16 = d7 - d14;
+ d20 = d6 - d13;
+ d19 = d7 - d21;
+ d17 = d6 - d18;
+ if (d16 * (d21 - d14) + d20 * (d18 - d13) <= 0.0) {
+  if (d16 * d16 + d20 * d20 > d8 * d8) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i5 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 1;
+  i4 = i1 + 40 | 0;
+  d21 = +d16;
+  d6 = +d20;
+  i22 = i4;
+  HEAPF32[i22 >> 2] = d21;
+  HEAPF32[i22 + 4 >> 2] = d6;
+  d6 = +Math_sqrt(+(d16 * d16 + d20 * d20));
+  if (!(d6 < 1.1920928955078125e-7)) {
+   d21 = 1.0 / d6;
+   HEAPF32[i4 >> 2] = d16 * d21;
+   HEAPF32[i1 + 44 >> 2] = d20 * d21;
+  }
+  i12 = i1 + 48 | 0;
+  HEAP32[i12 >> 2] = i10;
+  HEAP32[i12 + 4 >> 2] = i11;
+  i12 = i2;
+  i15 = HEAP32[i12 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i12 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  HEAP32[i1 + 16 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ }
+ if (!(d19 * (d14 - d21) + d17 * (d13 - d18) <= 0.0)) {
+  d14 = (d14 + d21) * .5;
+  d13 = (d13 + d18) * .5;
+  i10 = i4 + (i9 << 3) + 84 | 0;
+  if ((d7 - d14) * +HEAPF32[i10 >> 2] + (d6 - d13) * +HEAPF32[i4 + (i9 << 3) + 88 >> 2] > d8) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP32[i5 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 1;
+  i22 = i10;
+  i15 = HEAP32[i22 + 4 >> 2] | 0;
+  i12 = i1 + 40 | 0;
+  HEAP32[i12 >> 2] = HEAP32[i22 >> 2];
+  HEAP32[i12 + 4 >> 2] = i15;
+  d20 = +d14;
+  d21 = +d13;
+  i12 = i1 + 48 | 0;
+  HEAPF32[i12 >> 2] = d20;
+  HEAPF32[i12 + 4 >> 2] = d21;
+  i12 = i2;
+  i15 = HEAP32[i12 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i12 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  HEAP32[i1 + 16 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ }
+ if (d19 * d19 + d17 * d17 > d8 * d8) {
+  STACKTOP = i3;
+  return;
+ }
+ HEAP32[i5 >> 2] = 1;
+ HEAP32[i1 + 56 >> 2] = 1;
+ i4 = i1 + 40 | 0;
+ d21 = +d19;
+ d6 = +d17;
+ i22 = i4;
+ HEAPF32[i22 >> 2] = d21;
+ HEAPF32[i22 + 4 >> 2] = d6;
+ d6 = +Math_sqrt(+(d19 * d19 + d17 * d17));
+ if (!(d6 < 1.1920928955078125e-7)) {
+  d21 = 1.0 / d6;
+  HEAPF32[i4 >> 2] = d19 * d21;
+  HEAPF32[i1 + 44 >> 2] = d17 * d21;
+ }
+ i22 = i1 + 48 | 0;
+ HEAP32[i22 >> 2] = i15;
+ HEAP32[i22 + 4 >> 2] = i12;
+ i12 = i2;
+ i15 = HEAP32[i12 + 4 >> 2] | 0;
+ i22 = i1;
+ HEAP32[i22 >> 2] = HEAP32[i12 >> 2];
+ HEAP32[i22 + 4 >> 2] = i15;
+ HEAP32[i1 + 16 >> 2] = 0;
+ STACKTOP = i3;
+ return;
+}
+function __ZN15b2WorldManifold10InitializeEPK10b2ManifoldRK11b2TransformfS5_f(i1, i5, i7, d4, i8, d3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ d4 = +d4;
+ i8 = i8 | 0;
+ d3 = +d3;
+ var i2 = 0, i6 = 0, d9 = 0.0, d10 = 0.0, i11 = 0, i12 = 0, i13 = 0, d14 = 0.0, d15 = 0.0, i16 = 0, d17 = 0.0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0, d22 = 0.0;
+ i2 = STACKTOP;
+ i6 = i5 + 60 | 0;
+ if ((HEAP32[i6 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i11 = HEAP32[i5 + 56 >> 2] | 0;
+ if ((i11 | 0) == 2) {
+  i13 = i8 + 12 | 0;
+  d17 = +HEAPF32[i13 >> 2];
+  d18 = +HEAPF32[i5 + 40 >> 2];
+  i16 = i8 + 8 | 0;
+  d19 = +HEAPF32[i16 >> 2];
+  d15 = +HEAPF32[i5 + 44 >> 2];
+  d14 = d17 * d18 - d19 * d15;
+  d15 = d18 * d19 + d17 * d15;
+  d17 = +d14;
+  d19 = +d15;
+  i12 = i1;
+  HEAPF32[i12 >> 2] = d17;
+  HEAPF32[i12 + 4 >> 2] = d19;
+  d19 = +HEAPF32[i13 >> 2];
+  d17 = +HEAPF32[i5 + 48 >> 2];
+  d18 = +HEAPF32[i16 >> 2];
+  d10 = +HEAPF32[i5 + 52 >> 2];
+  d9 = +HEAPF32[i8 >> 2] + (d19 * d17 - d18 * d10);
+  d10 = d17 * d18 + d19 * d10 + +HEAPF32[i8 + 4 >> 2];
+  if ((HEAP32[i6 >> 2] | 0) > 0) {
+   i8 = i7 + 12 | 0;
+   i11 = i7 + 8 | 0;
+   i12 = i7 + 4 | 0;
+   i13 = i1 + 4 | 0;
+   i16 = 0;
+   do {
+    d18 = +HEAPF32[i8 >> 2];
+    d22 = +HEAPF32[i5 + (i16 * 20 | 0) >> 2];
+    d21 = +HEAPF32[i11 >> 2];
+    d17 = +HEAPF32[i5 + (i16 * 20 | 0) + 4 >> 2];
+    d19 = +HEAPF32[i7 >> 2] + (d18 * d22 - d21 * d17);
+    d17 = d22 * d21 + d18 * d17 + +HEAPF32[i12 >> 2];
+    d18 = d3 - (d14 * (d19 - d9) + (d17 - d10) * d15);
+    d19 = +((d19 - d14 * d4 + (d19 + d14 * d18)) * .5);
+    d14 = +((d17 - d15 * d4 + (d17 + d15 * d18)) * .5);
+    i20 = i1 + (i16 << 3) + 8 | 0;
+    HEAPF32[i20 >> 2] = d19;
+    HEAPF32[i20 + 4 >> 2] = d14;
+    i16 = i16 + 1 | 0;
+    d14 = +HEAPF32[i1 >> 2];
+    d15 = +HEAPF32[i13 >> 2];
+   } while ((i16 | 0) < (HEAP32[i6 >> 2] | 0));
+  }
+  d21 = +-d14;
+  d22 = +-d15;
+  i20 = i1;
+  HEAPF32[i20 >> 2] = d21;
+  HEAPF32[i20 + 4 >> 2] = d22;
+  STACKTOP = i2;
+  return;
+ } else if ((i11 | 0) == 1) {
+  i16 = i7 + 12 | 0;
+  d19 = +HEAPF32[i16 >> 2];
+  d21 = +HEAPF32[i5 + 40 >> 2];
+  i20 = i7 + 8 | 0;
+  d22 = +HEAPF32[i20 >> 2];
+  d15 = +HEAPF32[i5 + 44 >> 2];
+  d14 = d19 * d21 - d22 * d15;
+  d15 = d21 * d22 + d19 * d15;
+  d19 = +d14;
+  d22 = +d15;
+  i13 = i1;
+  HEAPF32[i13 >> 2] = d19;
+  HEAPF32[i13 + 4 >> 2] = d22;
+  d22 = +HEAPF32[i16 >> 2];
+  d19 = +HEAPF32[i5 + 48 >> 2];
+  d21 = +HEAPF32[i20 >> 2];
+  d10 = +HEAPF32[i5 + 52 >> 2];
+  d9 = +HEAPF32[i7 >> 2] + (d22 * d19 - d21 * d10);
+  d10 = d19 * d21 + d22 * d10 + +HEAPF32[i7 + 4 >> 2];
+  if ((HEAP32[i6 >> 2] | 0) <= 0) {
+   STACKTOP = i2;
+   return;
+  }
+  i12 = i8 + 12 | 0;
+  i11 = i8 + 8 | 0;
+  i7 = i8 + 4 | 0;
+  i13 = i1 + 4 | 0;
+  i16 = 0;
+  while (1) {
+   d22 = +HEAPF32[i12 >> 2];
+   d17 = +HEAPF32[i5 + (i16 * 20 | 0) >> 2];
+   d18 = +HEAPF32[i11 >> 2];
+   d19 = +HEAPF32[i5 + (i16 * 20 | 0) + 4 >> 2];
+   d21 = +HEAPF32[i8 >> 2] + (d22 * d17 - d18 * d19);
+   d19 = d17 * d18 + d22 * d19 + +HEAPF32[i7 >> 2];
+   d22 = d4 - (d14 * (d21 - d9) + (d19 - d10) * d15);
+   d21 = +((d21 - d14 * d3 + (d21 + d14 * d22)) * .5);
+   d22 = +((d19 - d15 * d3 + (d19 + d15 * d22)) * .5);
+   i20 = i1 + (i16 << 3) + 8 | 0;
+   HEAPF32[i20 >> 2] = d21;
+   HEAPF32[i20 + 4 >> 2] = d22;
+   i16 = i16 + 1 | 0;
+   if ((i16 | 0) >= (HEAP32[i6 >> 2] | 0)) {
+    break;
+   }
+   d14 = +HEAPF32[i1 >> 2];
+   d15 = +HEAPF32[i13 >> 2];
+  }
+  STACKTOP = i2;
+  return;
+ } else if ((i11 | 0) == 0) {
+  HEAPF32[i1 >> 2] = 1.0;
+  i6 = i1 + 4 | 0;
+  HEAPF32[i6 >> 2] = 0.0;
+  d21 = +HEAPF32[i7 + 12 >> 2];
+  d22 = +HEAPF32[i5 + 48 >> 2];
+  d19 = +HEAPF32[i7 + 8 >> 2];
+  d10 = +HEAPF32[i5 + 52 >> 2];
+  d9 = +HEAPF32[i7 >> 2] + (d21 * d22 - d19 * d10);
+  d10 = d22 * d19 + d21 * d10 + +HEAPF32[i7 + 4 >> 2];
+  d21 = +HEAPF32[i8 + 12 >> 2];
+  d19 = +HEAPF32[i5 >> 2];
+  d22 = +HEAPF32[i8 + 8 >> 2];
+  d15 = +HEAPF32[i5 + 4 >> 2];
+  d14 = +HEAPF32[i8 >> 2] + (d21 * d19 - d22 * d15);
+  d15 = d19 * d22 + d21 * d15 + +HEAPF32[i8 + 4 >> 2];
+  d21 = d9 - d14;
+  d22 = d10 - d15;
+  if (d21 * d21 + d22 * d22 > 1.4210854715202004e-14) {
+   d19 = d14 - d9;
+   d17 = d15 - d10;
+   d22 = +d19;
+   d18 = +d17;
+   i20 = i1;
+   HEAPF32[i20 >> 2] = d22;
+   HEAPF32[i20 + 4 >> 2] = d18;
+   d18 = +Math_sqrt(+(d19 * d19 + d17 * d17));
+   if (!(d18 < 1.1920928955078125e-7)) {
+    d22 = 1.0 / d18;
+    d19 = d19 * d22;
+    HEAPF32[i1 >> 2] = d19;
+    d17 = d17 * d22;
+    HEAPF32[i6 >> 2] = d17;
+   }
+  } else {
+   d19 = 1.0;
+   d17 = 0.0;
+  }
+  d21 = +((d9 + d19 * d4 + (d14 - d19 * d3)) * .5);
+  d22 = +((d10 + d17 * d4 + (d15 - d17 * d3)) * .5);
+  i20 = i1 + 8 | 0;
+  HEAPF32[i20 >> 2] = d21;
+  HEAPF32[i20 + 4 >> 2] = d22;
+  STACKTOP = i2;
+  return;
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _main(i3, i2) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, d6 = 0.0, d7 = 0.0, i8 = 0, i9 = 0, d10 = 0.0, d11 = 0.0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, d22 = 0.0, d23 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 240 | 0;
+ i5 = i1;
+ i12 = i1 + 224 | 0;
+ i4 = i1 + 168 | 0;
+ i9 = i1 + 160 | 0;
+ i8 = i1 + 152 | 0;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i14 = HEAP8[HEAP32[i2 + 4 >> 2] | 0] | 0;
+   switch (i14 | 0) {
+   case 49:
+    {
+     HEAP32[2] = 5;
+     HEAP32[4] = 35;
+     i15 = 35;
+     i14 = 5;
+     break L1;
+    }
+   case 50:
+    {
+     HEAP32[2] = 32;
+     HEAP32[4] = 161;
+     i15 = 161;
+     i14 = 32;
+     break L1;
+    }
+   case 51:
+    {
+     i13 = 5;
+     break L1;
+    }
+   case 52:
+    {
+     HEAP32[2] = 320;
+     HEAP32[4] = 2331;
+     i15 = 2331;
+     i14 = 320;
+     break L1;
+    }
+   case 53:
+    {
+     HEAP32[2] = 640;
+     HEAP32[4] = 5661;
+     i15 = 5661;
+     i14 = 640;
+     break L1;
+    }
+   case 48:
+    {
+     i20 = 0;
+     STACKTOP = i1;
+     return i20 | 0;
+    }
+   default:
+    {
+     HEAP32[i5 >> 2] = i14 + -48;
+     _printf(80, i5 | 0) | 0;
+     i20 = -1;
+     STACKTOP = i1;
+     return i20 | 0;
+    }
+   }
+  } else {
+   i13 = 5;
+  }
+ } while (0);
+ if ((i13 | 0) == 5) {
+  HEAP32[2] = 64;
+  HEAP32[4] = 333;
+  i15 = 333;
+  i14 = 64;
+ }
+ i13 = i15 + i14 | 0;
+ HEAP32[4] = i13;
+ HEAP32[2] = 0;
+ HEAP32[8] = __Znaj(i13 >>> 0 > 1073741823 ? -1 : i13 << 2) | 0;
+ HEAPF32[i12 >> 2] = 0.0;
+ HEAPF32[i12 + 4 >> 2] = -10.0;
+ i15 = __Znwj(103028) | 0;
+ __ZN7b2WorldC2ERK6b2Vec2(i15, i12);
+ HEAP32[6] = i15;
+ __ZN7b2World16SetAllowSleepingEb(i15, 0);
+ HEAP32[i5 + 44 >> 2] = 0;
+ i15 = i5 + 4 | 0;
+ i14 = i5 + 36 | 0;
+ HEAP32[i15 + 0 >> 2] = 0;
+ HEAP32[i15 + 4 >> 2] = 0;
+ HEAP32[i15 + 8 >> 2] = 0;
+ HEAP32[i15 + 12 >> 2] = 0;
+ HEAP32[i15 + 16 >> 2] = 0;
+ HEAP32[i15 + 20 >> 2] = 0;
+ HEAP32[i15 + 24 >> 2] = 0;
+ HEAP32[i15 + 28 >> 2] = 0;
+ HEAP8[i14] = 1;
+ HEAP8[i5 + 37 | 0] = 1;
+ HEAP8[i5 + 38 | 0] = 0;
+ HEAP8[i5 + 39 | 0] = 0;
+ HEAP32[i5 >> 2] = 0;
+ HEAP8[i5 + 40 | 0] = 1;
+ HEAPF32[i5 + 48 >> 2] = 1.0;
+ i14 = __ZN7b2World10CreateBodyEPK9b2BodyDef(HEAP32[6] | 0, i5) | 0;
+ HEAP32[i4 >> 2] = 240;
+ HEAP32[i4 + 4 >> 2] = 1;
+ HEAPF32[i4 + 8 >> 2] = .009999999776482582;
+ i15 = i4 + 28 | 0;
+ HEAP32[i15 + 0 >> 2] = 0;
+ HEAP32[i15 + 4 >> 2] = 0;
+ HEAP32[i15 + 8 >> 2] = 0;
+ HEAP32[i15 + 12 >> 2] = 0;
+ HEAP16[i15 + 16 >> 1] = 0;
+ HEAPF32[i9 >> 2] = -40.0;
+ HEAPF32[i9 + 4 >> 2] = 0.0;
+ HEAPF32[i8 >> 2] = 40.0;
+ HEAPF32[i8 + 4 >> 2] = 0.0;
+ __ZN11b2EdgeShape3SetERK6b2Vec2S2_(i4, i9, i8);
+ __ZN6b2Body13CreateFixtureEPK7b2Shapef(i14, i4, 0.0) | 0;
+ HEAP32[i5 >> 2] = 504;
+ HEAP32[i5 + 4 >> 2] = 2;
+ HEAPF32[i5 + 8 >> 2] = .009999999776482582;
+ HEAP32[i5 + 148 >> 2] = 0;
+ HEAPF32[i5 + 12 >> 2] = 0.0;
+ HEAPF32[i5 + 16 >> 2] = 0.0;
+ __ZN14b2PolygonShape8SetAsBoxEff(i5, .5, .5);
+ i14 = i4 + 44 | 0;
+ i15 = i4 + 4 | 0;
+ i8 = i4 + 36 | 0;
+ i17 = i4 + 37 | 0;
+ i18 = i4 + 38 | 0;
+ i19 = i4 + 39 | 0;
+ i20 = i4 + 40 | 0;
+ i13 = i4 + 48 | 0;
+ i12 = i4 + 4 | 0;
+ d11 = -7.0;
+ d10 = .75;
+ i9 = 0;
+ while (1) {
+  d7 = d11;
+  d6 = d10;
+  i16 = i9;
+  while (1) {
+   HEAP32[i14 >> 2] = 0;
+   HEAP32[i15 + 0 >> 2] = 0;
+   HEAP32[i15 + 4 >> 2] = 0;
+   HEAP32[i15 + 8 >> 2] = 0;
+   HEAP32[i15 + 12 >> 2] = 0;
+   HEAP32[i15 + 16 >> 2] = 0;
+   HEAP32[i15 + 20 >> 2] = 0;
+   HEAP32[i15 + 24 >> 2] = 0;
+   HEAP32[i15 + 28 >> 2] = 0;
+   HEAP8[i8] = 1;
+   HEAP8[i17] = 1;
+   HEAP8[i18] = 0;
+   HEAP8[i19] = 0;
+   HEAP8[i20] = 1;
+   HEAPF32[i13 >> 2] = 1.0;
+   HEAP32[i4 >> 2] = 2;
+   d23 = +d7;
+   d22 = +d6;
+   i21 = i12;
+   HEAPF32[i21 >> 2] = d23;
+   HEAPF32[i21 + 4 >> 2] = d22;
+   i21 = __ZN7b2World10CreateBodyEPK9b2BodyDef(HEAP32[6] | 0, i4) | 0;
+   __ZN6b2Body13CreateFixtureEPK7b2Shapef(i21, i5, 5.0) | 0;
+   HEAP32[14] = i21;
+   i16 = i16 + 1 | 0;
+   if ((i16 | 0) >= 40) {
+    break;
+   } else {
+    d7 = d7 + 1.125;
+    d6 = d6 + 0.0;
+   }
+  }
+  i9 = i9 + 1 | 0;
+  if ((i9 | 0) >= 40) {
+   break;
+  } else {
+   d11 = d11 + .5625;
+   d10 = d10 + 1.0;
+  }
+ }
+ if ((HEAP32[2] | 0) > 0) {
+  i4 = 0;
+  do {
+   __ZN7b2World4StepEfii(HEAP32[6] | 0, .01666666753590107, 3, 3);
+   i4 = i4 + 1 | 0;
+  } while ((i4 | 0) < (HEAP32[2] | 0));
+ }
+ if ((i3 | 0) > 2) {
+  i21 = (HEAP8[HEAP32[i2 + 8 >> 2] | 0] | 0) + -48 | 0;
+  HEAP32[18] = i21;
+  if ((i21 | 0) != 0) {
+   _puts(208) | 0;
+   _emscripten_set_main_loop(2, 60, 1);
+   i21 = 0;
+   STACKTOP = i1;
+   return i21 | 0;
+  }
+ } else {
+  HEAP32[18] = 0;
+ }
+ while (1) {
+  __Z4iterv();
+  if ((HEAP32[16] | 0) > (HEAP32[4] | 0)) {
+   i2 = 0;
+   break;
+  }
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function __ZN9b2Simplex9ReadCacheEPK14b2SimplexCachePK15b2DistanceProxyRK11b2TransformS5_S8_(i2, i11, i10, i4, i3, i5) {
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ i10 = i10 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i6 = 0, i7 = 0, d8 = 0.0, i9 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, d24 = 0.0, d25 = 0.0, i26 = 0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, d31 = 0.0, d32 = 0.0;
+ i1 = STACKTOP;
+ i13 = HEAP16[i11 + 4 >> 1] | 0;
+ if (!((i13 & 65535) < 4)) {
+  ___assert_fail(2872, 2672, 102, 2896);
+ }
+ i12 = i13 & 65535;
+ i6 = i2 + 108 | 0;
+ HEAP32[i6 >> 2] = i12;
+ L4 : do {
+  if (!(i13 << 16 >> 16 == 0)) {
+   i17 = i10 + 20 | 0;
+   i21 = i10 + 16 | 0;
+   i13 = i3 + 20 | 0;
+   i14 = i3 + 16 | 0;
+   i15 = i4 + 12 | 0;
+   i16 = i4 + 8 | 0;
+   i12 = i4 + 4 | 0;
+   i18 = i5 + 12 | 0;
+   i19 = i5 + 8 | 0;
+   i20 = i5 + 4 | 0;
+   i22 = 0;
+   while (1) {
+    i26 = HEAPU8[i11 + i22 + 6 | 0] | 0;
+    HEAP32[i2 + (i22 * 36 | 0) + 28 >> 2] = i26;
+    i23 = HEAPU8[i11 + i22 + 9 | 0] | 0;
+    HEAP32[i2 + (i22 * 36 | 0) + 32 >> 2] = i23;
+    if ((HEAP32[i17 >> 2] | 0) <= (i26 | 0)) {
+     i9 = 6;
+     break;
+    }
+    i26 = (HEAP32[i21 >> 2] | 0) + (i26 << 3) | 0;
+    d25 = +HEAPF32[i26 >> 2];
+    d24 = +HEAPF32[i26 + 4 >> 2];
+    if ((HEAP32[i13 >> 2] | 0) <= (i23 | 0)) {
+     i9 = 8;
+     break;
+    }
+    i23 = (HEAP32[i14 >> 2] | 0) + (i23 << 3) | 0;
+    d29 = +HEAPF32[i23 >> 2];
+    d31 = +HEAPF32[i23 + 4 >> 2];
+    d32 = +HEAPF32[i15 >> 2];
+    d30 = +HEAPF32[i16 >> 2];
+    d27 = +HEAPF32[i4 >> 2] + (d25 * d32 - d24 * d30);
+    d28 = +d27;
+    d30 = +(d24 * d32 + d25 * d30 + +HEAPF32[i12 >> 2]);
+    i23 = i2 + (i22 * 36 | 0) | 0;
+    HEAPF32[i23 >> 2] = d28;
+    HEAPF32[i23 + 4 >> 2] = d30;
+    d30 = +HEAPF32[i18 >> 2];
+    d25 = +HEAPF32[i19 >> 2];
+    d24 = +HEAPF32[i5 >> 2] + (d29 * d30 - d31 * d25);
+    d28 = +d24;
+    d25 = +(d31 * d30 + d29 * d25 + +HEAPF32[i20 >> 2]);
+    i23 = i2 + (i22 * 36 | 0) + 8 | 0;
+    HEAPF32[i23 >> 2] = d28;
+    HEAPF32[i23 + 4 >> 2] = d25;
+    d24 = +(d24 - d27);
+    d25 = +(+HEAPF32[i2 + (i22 * 36 | 0) + 12 >> 2] - +HEAPF32[i2 + (i22 * 36 | 0) + 4 >> 2]);
+    i23 = i2 + (i22 * 36 | 0) + 16 | 0;
+    HEAPF32[i23 >> 2] = d24;
+    HEAPF32[i23 + 4 >> 2] = d25;
+    HEAPF32[i2 + (i22 * 36 | 0) + 24 >> 2] = 0.0;
+    i22 = i22 + 1 | 0;
+    i23 = HEAP32[i6 >> 2] | 0;
+    if ((i22 | 0) >= (i23 | 0)) {
+     i7 = i23;
+     break L4;
+    }
+   }
+   if ((i9 | 0) == 6) {
+    ___assert_fail(2776, 2808, 103, 2840);
+   } else if ((i9 | 0) == 8) {
+    ___assert_fail(2776, 2808, 103, 2840);
+   }
+  } else {
+   i7 = i12;
+  }
+ } while (0);
+ do {
+  if ((i7 | 0) > 1) {
+   d24 = +HEAPF32[i11 >> 2];
+   if ((i7 | 0) == 2) {
+    d32 = +HEAPF32[i2 + 16 >> 2] - +HEAPF32[i2 + 52 >> 2];
+    d8 = +HEAPF32[i2 + 20 >> 2] - +HEAPF32[i2 + 56 >> 2];
+    d8 = +Math_sqrt(+(d32 * d32 + d8 * d8));
+   } else if ((i7 | 0) == 3) {
+    d8 = +HEAPF32[i2 + 16 >> 2];
+    d32 = +HEAPF32[i2 + 20 >> 2];
+    d8 = (+HEAPF32[i2 + 52 >> 2] - d8) * (+HEAPF32[i2 + 92 >> 2] - d32) - (+HEAPF32[i2 + 56 >> 2] - d32) * (+HEAPF32[i2 + 88 >> 2] - d8);
+   } else {
+    ___assert_fail(2712, 2672, 259, 2736);
+   }
+   if (!(d8 < d24 * .5) ? !(d24 * 2.0 < d8 | d8 < 1.1920928955078125e-7) : 0) {
+    i9 = 18;
+    break;
+   }
+   HEAP32[i6 >> 2] = 0;
+  } else {
+   i9 = 18;
+  }
+ } while (0);
+ if ((i9 | 0) == 18 ? (i7 | 0) != 0 : 0) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i2 + 28 >> 2] = 0;
+ HEAP32[i2 + 32 >> 2] = 0;
+ if ((HEAP32[i10 + 20 >> 2] | 0) <= 0) {
+  ___assert_fail(2776, 2808, 103, 2840);
+ }
+ i26 = HEAP32[i10 + 16 >> 2] | 0;
+ d8 = +HEAPF32[i26 >> 2];
+ d24 = +HEAPF32[i26 + 4 >> 2];
+ if ((HEAP32[i3 + 20 >> 2] | 0) <= 0) {
+  ___assert_fail(2776, 2808, 103, 2840);
+ }
+ i26 = HEAP32[i3 + 16 >> 2] | 0;
+ d27 = +HEAPF32[i26 >> 2];
+ d25 = +HEAPF32[i26 + 4 >> 2];
+ d30 = +HEAPF32[i4 + 12 >> 2];
+ d32 = +HEAPF32[i4 + 8 >> 2];
+ d31 = +HEAPF32[i4 >> 2] + (d8 * d30 - d24 * d32);
+ d32 = d24 * d30 + d8 * d32 + +HEAPF32[i4 + 4 >> 2];
+ d30 = +d31;
+ d28 = +d32;
+ i26 = i2;
+ HEAPF32[i26 >> 2] = d30;
+ HEAPF32[i26 + 4 >> 2] = d28;
+ d28 = +HEAPF32[i5 + 12 >> 2];
+ d30 = +HEAPF32[i5 + 8 >> 2];
+ d29 = +HEAPF32[i5 >> 2] + (d27 * d28 - d25 * d30);
+ d30 = d25 * d28 + d27 * d30 + +HEAPF32[i5 + 4 >> 2];
+ d27 = +d29;
+ d28 = +d30;
+ i26 = i2 + 8 | 0;
+ HEAPF32[i26 >> 2] = d27;
+ HEAPF32[i26 + 4 >> 2] = d28;
+ d31 = +(d29 - d31);
+ d32 = +(d30 - d32);
+ i26 = i2 + 16 | 0;
+ HEAPF32[i26 >> 2] = d31;
+ HEAPF32[i26 + 4 >> 2] = d32;
+ HEAP32[i6 >> 2] = 1;
+ STACKTOP = i1;
+ return;
+}
+function __ZNSt3__17__sort4IRPFbRK6b2PairS3_EPS1_EEjT0_S8_S8_S8_T_(i6, i7, i5, i4, i1) {
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i9 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i7, i6) | 0;
+ i8 = FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i7) | 0;
+ do {
+  if (i9) {
+   if (i8) {
+    HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+    HEAP32[i6 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i6 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i6 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    i8 = 1;
+    break;
+   }
+   HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+   if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i7) | 0) {
+    HEAP32[i3 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    i8 = 2;
+   } else {
+    i8 = 1;
+   }
+  } else {
+   if (i8) {
+    HEAP32[i3 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+    if (FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i7, i6) | 0) {
+     HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+     HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+     HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+     HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+     HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+     HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+     HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+     HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+     HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+     i8 = 2;
+    } else {
+     i8 = 1;
+    }
+   } else {
+    i8 = 0;
+   }
+  }
+ } while (0);
+ if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i4, i5) | 0)) {
+  i9 = i8;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ HEAP32[i3 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+ HEAP32[i3 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+ HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ HEAP32[i5 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+ HEAP32[i5 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+ HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+ HEAP32[i4 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+ HEAP32[i4 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+ HEAP32[i4 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i5, i7) | 0)) {
+  i9 = i8 + 1 | 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ HEAP32[i3 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+ HEAP32[i3 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+ HEAP32[i3 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+ HEAP32[i7 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+ HEAP32[i7 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+ HEAP32[i7 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ HEAP32[i5 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+ HEAP32[i5 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+ HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ if (!(FUNCTION_TABLE_iii[HEAP32[i1 >> 2] & 3](i7, i6) | 0)) {
+  i9 = i8 + 2 | 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+ HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+ HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+ HEAP32[i6 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+ HEAP32[i6 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+ HEAP32[i6 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+ HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+ HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+ HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ i9 = i8 + 3 | 0;
+ STACKTOP = i2;
+ return i9 | 0;
+}
+function __ZN15b2ContactSolver27SolveTOIPositionConstraintsEii(i9, i2, i5) {
+ i9 = i9 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, d21 = 0.0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, d31 = 0.0, d32 = 0.0, d33 = 0.0, d34 = 0.0, d35 = 0.0, d36 = 0.0, i37 = 0, d38 = 0.0, d39 = 0.0, d40 = 0.0, d41 = 0.0, d42 = 0.0, d43 = 0.0, d44 = 0.0, d45 = 0.0, i46 = 0, d47 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i8 = i1 + 40 | 0;
+ i3 = i1 + 24 | 0;
+ i4 = i1;
+ i6 = i9 + 48 | 0;
+ if ((HEAP32[i6 >> 2] | 0) <= 0) {
+  d45 = 0.0;
+  i37 = d45 >= -.007499999832361937;
+  STACKTOP = i1;
+  return i37 | 0;
+ }
+ i7 = i9 + 36 | 0;
+ i14 = i9 + 24 | 0;
+ i9 = i8 + 8 | 0;
+ i15 = i8 + 12 | 0;
+ i10 = i3 + 8 | 0;
+ i11 = i3 + 12 | 0;
+ i12 = i4 + 8 | 0;
+ i13 = i4 + 16 | 0;
+ i16 = 0;
+ d34 = 0.0;
+ do {
+  i37 = HEAP32[i7 >> 2] | 0;
+  i19 = i37 + (i16 * 88 | 0) | 0;
+  i17 = HEAP32[i37 + (i16 * 88 | 0) + 32 >> 2] | 0;
+  i18 = HEAP32[i37 + (i16 * 88 | 0) + 36 >> 2] | 0;
+  i20 = i37 + (i16 * 88 | 0) + 48 | 0;
+  d21 = +HEAPF32[i20 >> 2];
+  d22 = +HEAPF32[i20 + 4 >> 2];
+  i20 = i37 + (i16 * 88 | 0) + 56 | 0;
+  d23 = +HEAPF32[i20 >> 2];
+  d24 = +HEAPF32[i20 + 4 >> 2];
+  i20 = HEAP32[i37 + (i16 * 88 | 0) + 84 >> 2] | 0;
+  if ((i17 | 0) == (i2 | 0) | (i17 | 0) == (i5 | 0)) {
+   d26 = +HEAPF32[i37 + (i16 * 88 | 0) + 64 >> 2];
+   d27 = +HEAPF32[i37 + (i16 * 88 | 0) + 40 >> 2];
+  } else {
+   d26 = 0.0;
+   d27 = 0.0;
+  }
+  d25 = +HEAPF32[i37 + (i16 * 88 | 0) + 44 >> 2];
+  d28 = +HEAPF32[i37 + (i16 * 88 | 0) + 68 >> 2];
+  i37 = HEAP32[i14 >> 2] | 0;
+  i46 = i37 + (i17 * 12 | 0) | 0;
+  d33 = +HEAPF32[i46 >> 2];
+  d35 = +HEAPF32[i46 + 4 >> 2];
+  d29 = +HEAPF32[i37 + (i17 * 12 | 0) + 8 >> 2];
+  i46 = i37 + (i18 * 12 | 0) | 0;
+  d32 = +HEAPF32[i46 >> 2];
+  d36 = +HEAPF32[i46 + 4 >> 2];
+  d31 = +HEAPF32[i37 + (i18 * 12 | 0) + 8 >> 2];
+  if ((i20 | 0) > 0) {
+   d30 = d27 + d25;
+   i37 = 0;
+   do {
+    d38 = +Math_sin(+d29);
+    HEAPF32[i9 >> 2] = d38;
+    d44 = +Math_cos(+d29);
+    HEAPF32[i15 >> 2] = d44;
+    d43 = +Math_sin(+d31);
+    HEAPF32[i10 >> 2] = d43;
+    d41 = +Math_cos(+d31);
+    HEAPF32[i11 >> 2] = d41;
+    d40 = +(d33 - (d21 * d44 - d22 * d38));
+    d38 = +(d35 - (d22 * d44 + d21 * d38));
+    i46 = i8;
+    HEAPF32[i46 >> 2] = d40;
+    HEAPF32[i46 + 4 >> 2] = d38;
+    d38 = +(d32 - (d23 * d41 - d24 * d43));
+    d43 = +(d36 - (d24 * d41 + d23 * d43));
+    i46 = i3;
+    HEAPF32[i46 >> 2] = d38;
+    HEAPF32[i46 + 4 >> 2] = d43;
+    __ZN24b2PositionSolverManifold10InitializeEP27b2ContactPositionConstraintRK11b2TransformS4_i(i4, i19, i8, i3, i37);
+    i46 = i4;
+    d43 = +HEAPF32[i46 >> 2];
+    d38 = +HEAPF32[i46 + 4 >> 2];
+    i46 = i12;
+    d41 = +HEAPF32[i46 >> 2];
+    d40 = +HEAPF32[i46 + 4 >> 2];
+    d44 = +HEAPF32[i13 >> 2];
+    d39 = d41 - d33;
+    d42 = d40 - d35;
+    d41 = d41 - d32;
+    d40 = d40 - d36;
+    d34 = d34 < d44 ? d34 : d44;
+    d44 = (d44 + .004999999888241291) * .75;
+    d44 = d44 < 0.0 ? d44 : 0.0;
+    d45 = d38 * d39 - d43 * d42;
+    d47 = d38 * d41 - d43 * d40;
+    d45 = d47 * d28 * d47 + (d30 + d45 * d26 * d45);
+    if (d45 > 0.0) {
+     d44 = -(d44 < -.20000000298023224 ? -.20000000298023224 : d44) / d45;
+    } else {
+     d44 = 0.0;
+    }
+    d47 = d43 * d44;
+    d45 = d38 * d44;
+    d33 = d33 - d27 * d47;
+    d35 = d35 - d27 * d45;
+    d29 = d29 - d26 * (d39 * d45 - d42 * d47);
+    d32 = d32 + d25 * d47;
+    d36 = d36 + d25 * d45;
+    d31 = d31 + d28 * (d41 * d45 - d40 * d47);
+    i37 = i37 + 1 | 0;
+   } while ((i37 | 0) != (i20 | 0));
+   i37 = HEAP32[i14 >> 2] | 0;
+  }
+  d47 = +d33;
+  d45 = +d35;
+  i46 = i37 + (i17 * 12 | 0) | 0;
+  HEAPF32[i46 >> 2] = d47;
+  HEAPF32[i46 + 4 >> 2] = d45;
+  i46 = HEAP32[i14 >> 2] | 0;
+  HEAPF32[i46 + (i17 * 12 | 0) + 8 >> 2] = d29;
+  d45 = +d32;
+  d47 = +d36;
+  i46 = i46 + (i18 * 12 | 0) | 0;
+  HEAPF32[i46 >> 2] = d45;
+  HEAPF32[i46 + 4 >> 2] = d47;
+  HEAPF32[(HEAP32[i14 >> 2] | 0) + (i18 * 12 | 0) + 8 >> 2] = d31;
+  i16 = i16 + 1 | 0;
+ } while ((i16 | 0) < (HEAP32[i6 >> 2] | 0));
+ i46 = d34 >= -.007499999832361937;
+ STACKTOP = i1;
+ return i46 | 0;
+}
+function __ZN15b2ContactSolver24SolvePositionConstraintsEv(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, i21 = 0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, i26 = 0, d27 = 0.0, d28 = 0.0, d29 = 0.0, d30 = 0.0, d31 = 0.0, d32 = 0.0, d33 = 0.0, d34 = 0.0, i35 = 0, d36 = 0.0, d37 = 0.0, d38 = 0.0, d39 = 0.0, d40 = 0.0, d41 = 0.0, d42 = 0.0, d43 = 0.0, i44 = 0, d45 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i4 = i1 + 40 | 0;
+ i5 = i1 + 24 | 0;
+ i3 = i1;
+ i2 = i7 + 48 | 0;
+ if ((HEAP32[i2 >> 2] | 0) <= 0) {
+  d43 = 0.0;
+  i35 = d43 >= -.014999999664723873;
+  STACKTOP = i1;
+  return i35 | 0;
+ }
+ i6 = i7 + 36 | 0;
+ i9 = i7 + 24 | 0;
+ i13 = i4 + 8 | 0;
+ i7 = i4 + 12 | 0;
+ i8 = i5 + 8 | 0;
+ i12 = i5 + 12 | 0;
+ i10 = i3 + 8 | 0;
+ i11 = i3 + 16 | 0;
+ i35 = HEAP32[i9 >> 2] | 0;
+ i15 = 0;
+ d32 = 0.0;
+ do {
+  i21 = HEAP32[i6 >> 2] | 0;
+  i26 = i21 + (i15 * 88 | 0) | 0;
+  i16 = HEAP32[i21 + (i15 * 88 | 0) + 32 >> 2] | 0;
+  i14 = HEAP32[i21 + (i15 * 88 | 0) + 36 >> 2] | 0;
+  i44 = i21 + (i15 * 88 | 0) + 48 | 0;
+  d22 = +HEAPF32[i44 >> 2];
+  d23 = +HEAPF32[i44 + 4 >> 2];
+  d25 = +HEAPF32[i21 + (i15 * 88 | 0) + 40 >> 2];
+  d18 = +HEAPF32[i21 + (i15 * 88 | 0) + 64 >> 2];
+  i44 = i21 + (i15 * 88 | 0) + 56 | 0;
+  d24 = +HEAPF32[i44 >> 2];
+  d19 = +HEAPF32[i44 + 4 >> 2];
+  d17 = +HEAPF32[i21 + (i15 * 88 | 0) + 44 >> 2];
+  d20 = +HEAPF32[i21 + (i15 * 88 | 0) + 68 >> 2];
+  i21 = HEAP32[i21 + (i15 * 88 | 0) + 84 >> 2] | 0;
+  i44 = i35 + (i16 * 12 | 0) | 0;
+  d28 = +HEAPF32[i44 >> 2];
+  d33 = +HEAPF32[i44 + 4 >> 2];
+  d29 = +HEAPF32[i35 + (i16 * 12 | 0) + 8 >> 2];
+  i44 = i35 + (i14 * 12 | 0) | 0;
+  d30 = +HEAPF32[i44 >> 2];
+  d34 = +HEAPF32[i44 + 4 >> 2];
+  d31 = +HEAPF32[i35 + (i14 * 12 | 0) + 8 >> 2];
+  if ((i21 | 0) > 0) {
+   d27 = d25 + d17;
+   i35 = 0;
+   do {
+    d41 = +Math_sin(+d29);
+    HEAPF32[i13 >> 2] = d41;
+    d42 = +Math_cos(+d29);
+    HEAPF32[i7 >> 2] = d42;
+    d39 = +Math_sin(+d31);
+    HEAPF32[i8 >> 2] = d39;
+    d38 = +Math_cos(+d31);
+    HEAPF32[i12 >> 2] = d38;
+    d40 = +(d28 - (d22 * d42 - d23 * d41));
+    d41 = +(d33 - (d23 * d42 + d22 * d41));
+    i44 = i4;
+    HEAPF32[i44 >> 2] = d40;
+    HEAPF32[i44 + 4 >> 2] = d41;
+    d41 = +(d30 - (d24 * d38 - d19 * d39));
+    d39 = +(d34 - (d19 * d38 + d24 * d39));
+    i44 = i5;
+    HEAPF32[i44 >> 2] = d41;
+    HEAPF32[i44 + 4 >> 2] = d39;
+    __ZN24b2PositionSolverManifold10InitializeEP27b2ContactPositionConstraintRK11b2TransformS4_i(i3, i26, i4, i5, i35);
+    i44 = i3;
+    d39 = +HEAPF32[i44 >> 2];
+    d41 = +HEAPF32[i44 + 4 >> 2];
+    i44 = i10;
+    d38 = +HEAPF32[i44 >> 2];
+    d40 = +HEAPF32[i44 + 4 >> 2];
+    d42 = +HEAPF32[i11 >> 2];
+    d36 = d38 - d28;
+    d37 = d40 - d33;
+    d38 = d38 - d30;
+    d40 = d40 - d34;
+    d32 = d32 < d42 ? d32 : d42;
+    d42 = (d42 + .004999999888241291) * .20000000298023224;
+    d43 = d42 < 0.0 ? d42 : 0.0;
+    d42 = d41 * d36 - d39 * d37;
+    d45 = d41 * d38 - d39 * d40;
+    d42 = d45 * d20 * d45 + (d27 + d42 * d18 * d42);
+    if (d42 > 0.0) {
+     d42 = -(d43 < -.20000000298023224 ? -.20000000298023224 : d43) / d42;
+    } else {
+     d42 = 0.0;
+    }
+    d45 = d39 * d42;
+    d43 = d41 * d42;
+    d28 = d28 - d25 * d45;
+    d33 = d33 - d25 * d43;
+    d29 = d29 - d18 * (d36 * d43 - d37 * d45);
+    d30 = d30 + d17 * d45;
+    d34 = d34 + d17 * d43;
+    d31 = d31 + d20 * (d38 * d43 - d40 * d45);
+    i35 = i35 + 1 | 0;
+   } while ((i35 | 0) != (i21 | 0));
+   i35 = HEAP32[i9 >> 2] | 0;
+  }
+  d45 = +d28;
+  d43 = +d33;
+  i35 = i35 + (i16 * 12 | 0) | 0;
+  HEAPF32[i35 >> 2] = d45;
+  HEAPF32[i35 + 4 >> 2] = d43;
+  i35 = HEAP32[i9 >> 2] | 0;
+  HEAPF32[i35 + (i16 * 12 | 0) + 8 >> 2] = d29;
+  d43 = +d30;
+  d45 = +d34;
+  i35 = i35 + (i14 * 12 | 0) | 0;
+  HEAPF32[i35 >> 2] = d43;
+  HEAPF32[i35 + 4 >> 2] = d45;
+  i35 = HEAP32[i9 >> 2] | 0;
+  HEAPF32[i35 + (i14 * 12 | 0) + 8 >> 2] = d31;
+  i15 = i15 + 1 | 0;
+ } while ((i15 | 0) < (HEAP32[i2 >> 2] | 0));
+ i44 = d32 >= -.014999999664723873;
+ STACKTOP = i1;
+ return i44 | 0;
+}
+function __Z22b2CollideEdgeAndCircleP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK13b2CircleShapeS6_(i1, i7, i6, i22, i5) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i22 = i22 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, i14 = 0, i15 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, d23 = 0.0, d24 = 0.0;
+ i4 = STACKTOP;
+ i2 = i1 + 60 | 0;
+ HEAP32[i2 >> 2] = 0;
+ i3 = i22 + 12 | 0;
+ d9 = +HEAPF32[i5 + 12 >> 2];
+ d23 = +HEAPF32[i3 >> 2];
+ d17 = +HEAPF32[i5 + 8 >> 2];
+ d18 = +HEAPF32[i22 + 16 >> 2];
+ d21 = +HEAPF32[i5 >> 2] + (d9 * d23 - d17 * d18) - +HEAPF32[i6 >> 2];
+ d18 = d23 * d17 + d9 * d18 + +HEAPF32[i5 + 4 >> 2] - +HEAPF32[i6 + 4 >> 2];
+ d9 = +HEAPF32[i6 + 12 >> 2];
+ d17 = +HEAPF32[i6 + 8 >> 2];
+ d23 = d21 * d9 + d18 * d17;
+ d17 = d9 * d18 - d21 * d17;
+ i6 = i7 + 12 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ i6 = HEAP32[i6 + 4 >> 2] | 0;
+ d21 = (HEAP32[tempDoublePtr >> 2] = i5, +HEAPF32[tempDoublePtr >> 2]);
+ d18 = (HEAP32[tempDoublePtr >> 2] = i6, +HEAPF32[tempDoublePtr >> 2]);
+ i15 = i7 + 20 | 0;
+ i14 = HEAP32[i15 >> 2] | 0;
+ i15 = HEAP32[i15 + 4 >> 2] | 0;
+ d9 = (HEAP32[tempDoublePtr >> 2] = i14, +HEAPF32[tempDoublePtr >> 2]);
+ d10 = (HEAP32[tempDoublePtr >> 2] = i15, +HEAPF32[tempDoublePtr >> 2]);
+ d8 = d9 - d21;
+ d16 = d10 - d18;
+ d19 = d8 * (d9 - d23) + d16 * (d10 - d17);
+ d13 = d23 - d21;
+ d12 = d17 - d18;
+ d20 = d13 * d8 + d12 * d16;
+ d11 = +HEAPF32[i7 + 8 >> 2] + +HEAPF32[i22 + 8 >> 2];
+ if (d20 <= 0.0) {
+  if (d13 * d13 + d12 * d12 > d11 * d11) {
+   STACKTOP = i4;
+   return;
+  }
+  if ((HEAP8[i7 + 44 | 0] | 0) != 0 ? (i22 = i7 + 28 | 0, d24 = +HEAPF32[i22 >> 2], (d21 - d23) * (d21 - d24) + (d18 - d17) * (d18 - +HEAPF32[i22 + 4 >> 2]) > 0.0) : 0) {
+   STACKTOP = i4;
+   return;
+  }
+  HEAP32[i2 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 0;
+  HEAPF32[i1 + 40 >> 2] = 0.0;
+  HEAPF32[i1 + 44 >> 2] = 0.0;
+  i14 = i1 + 48 | 0;
+  HEAP32[i14 >> 2] = i5;
+  HEAP32[i14 + 4 >> 2] = i6;
+  i14 = i1 + 16 | 0;
+  HEAP32[i14 >> 2] = 0;
+  HEAP8[i14] = 0;
+  HEAP8[i14 + 1 | 0] = 0;
+  HEAP8[i14 + 2 | 0] = 0;
+  HEAP8[i14 + 3 | 0] = 0;
+  i14 = i3;
+  i15 = HEAP32[i14 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i14 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  STACKTOP = i4;
+  return;
+ }
+ if (d19 <= 0.0) {
+  d8 = d23 - d9;
+  d12 = d17 - d10;
+  if (d8 * d8 + d12 * d12 > d11 * d11) {
+   STACKTOP = i4;
+   return;
+  }
+  if ((HEAP8[i7 + 45 | 0] | 0) != 0 ? (i22 = i7 + 36 | 0, d24 = +HEAPF32[i22 >> 2], d8 * (d24 - d9) + d12 * (+HEAPF32[i22 + 4 >> 2] - d10) > 0.0) : 0) {
+   STACKTOP = i4;
+   return;
+  }
+  HEAP32[i2 >> 2] = 1;
+  HEAP32[i1 + 56 >> 2] = 0;
+  HEAPF32[i1 + 40 >> 2] = 0.0;
+  HEAPF32[i1 + 44 >> 2] = 0.0;
+  i22 = i1 + 48 | 0;
+  HEAP32[i22 >> 2] = i14;
+  HEAP32[i22 + 4 >> 2] = i15;
+  i14 = i1 + 16 | 0;
+  HEAP32[i14 >> 2] = 0;
+  HEAP8[i14] = 1;
+  HEAP8[i14 + 1 | 0] = 0;
+  HEAP8[i14 + 2 | 0] = 0;
+  HEAP8[i14 + 3 | 0] = 0;
+  i14 = i3;
+  i15 = HEAP32[i14 + 4 >> 2] | 0;
+  i22 = i1;
+  HEAP32[i22 >> 2] = HEAP32[i14 >> 2];
+  HEAP32[i22 + 4 >> 2] = i15;
+  STACKTOP = i4;
+  return;
+ }
+ d24 = d8 * d8 + d16 * d16;
+ if (!(d24 > 0.0)) {
+  ___assert_fail(5560, 5576, 127, 5616);
+ }
+ d24 = 1.0 / d24;
+ d23 = d23 - (d21 * d19 + d9 * d20) * d24;
+ d24 = d17 - (d18 * d19 + d10 * d20) * d24;
+ if (d23 * d23 + d24 * d24 > d11 * d11) {
+  STACKTOP = i4;
+  return;
+ }
+ d9 = -d16;
+ if (d8 * d12 + d13 * d9 < 0.0) {
+  d8 = -d8;
+ } else {
+  d16 = d9;
+ }
+ d9 = +Math_sqrt(+(d8 * d8 + d16 * d16));
+ if (!(d9 < 1.1920928955078125e-7)) {
+  d24 = 1.0 / d9;
+  d16 = d16 * d24;
+  d8 = d8 * d24;
+ }
+ HEAP32[i2 >> 2] = 1;
+ HEAP32[i1 + 56 >> 2] = 1;
+ d23 = +d16;
+ d24 = +d8;
+ i14 = i1 + 40 | 0;
+ HEAPF32[i14 >> 2] = d23;
+ HEAPF32[i14 + 4 >> 2] = d24;
+ i14 = i1 + 48 | 0;
+ HEAP32[i14 >> 2] = i5;
+ HEAP32[i14 + 4 >> 2] = i6;
+ i14 = i1 + 16 | 0;
+ HEAP32[i14 >> 2] = 0;
+ HEAP8[i14] = 0;
+ HEAP8[i14 + 1 | 0] = 0;
+ HEAP8[i14 + 2 | 0] = 1;
+ HEAP8[i14 + 3 | 0] = 0;
+ i14 = i3;
+ i15 = HEAP32[i14 + 4 >> 2] | 0;
+ i22 = i1;
+ HEAP32[i22 >> 2] = HEAP32[i14 >> 2];
+ HEAP32[i22 + 4 >> 2] = i15;
+ STACKTOP = i4;
+ return;
+}
+function __ZN6b2BodyC2EPK9b2BodyDefP7b2World(i1, i2, i5) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, d13 = 0.0;
+ i3 = STACKTOP;
+ i9 = i2 + 4 | 0;
+ d13 = +HEAPF32[i9 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1496, 1520, 27, 1552);
+ }
+ d13 = +HEAPF32[i2 + 8 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1496, 1520, 27, 1552);
+ }
+ i6 = i2 + 16 | 0;
+ d13 = +HEAPF32[i6 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1560, 1520, 28, 1552);
+ }
+ d13 = +HEAPF32[i2 + 20 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1560, 1520, 28, 1552);
+ }
+ i7 = i2 + 12 | 0;
+ d13 = +HEAPF32[i7 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1592, 1520, 29, 1552);
+ }
+ i8 = i2 + 24 | 0;
+ d13 = +HEAPF32[i8 >> 2];
+ if (!(d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf)) {
+  ___assert_fail(1616, 1520, 30, 1552);
+ }
+ i4 = i2 + 32 | 0;
+ d13 = +HEAPF32[i4 >> 2];
+ if (!(d13 >= 0.0) | d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf ^ 1) {
+  ___assert_fail(1648, 1520, 31, 1552);
+ }
+ i10 = i2 + 28 | 0;
+ d13 = +HEAPF32[i10 >> 2];
+ if (!(d13 >= 0.0) | d13 == d13 & 0.0 == 0.0 & d13 > -inf & d13 < inf ^ 1) {
+  ___assert_fail(1712, 1520, 32, 1552);
+ }
+ i11 = i1 + 4 | 0;
+ i12 = (HEAP8[i2 + 39 | 0] | 0) == 0 ? 0 : 8;
+ HEAP16[i11 >> 1] = i12;
+ if ((HEAP8[i2 + 38 | 0] | 0) != 0) {
+  i12 = (i12 & 65535 | 16) & 65535;
+  HEAP16[i11 >> 1] = i12;
+ }
+ if ((HEAP8[i2 + 36 | 0] | 0) != 0) {
+  i12 = (i12 & 65535 | 4) & 65535;
+  HEAP16[i11 >> 1] = i12;
+ }
+ if ((HEAP8[i2 + 37 | 0] | 0) != 0) {
+  i12 = (i12 & 65535 | 2) & 65535;
+  HEAP16[i11 >> 1] = i12;
+ }
+ if ((HEAP8[i2 + 40 | 0] | 0) != 0) {
+  HEAP16[i11 >> 1] = i12 & 65535 | 32;
+ }
+ HEAP32[i1 + 88 >> 2] = i5;
+ i11 = i9;
+ i12 = HEAP32[i11 >> 2] | 0;
+ i11 = HEAP32[i11 + 4 >> 2] | 0;
+ i9 = i1 + 12 | 0;
+ HEAP32[i9 >> 2] = i12;
+ HEAP32[i9 + 4 >> 2] = i11;
+ d13 = +HEAPF32[i7 >> 2];
+ HEAPF32[i1 + 20 >> 2] = +Math_sin(+d13);
+ HEAPF32[i1 + 24 >> 2] = +Math_cos(+d13);
+ HEAPF32[i1 + 28 >> 2] = 0.0;
+ HEAPF32[i1 + 32 >> 2] = 0.0;
+ i9 = i1 + 36 | 0;
+ HEAP32[i9 >> 2] = i12;
+ HEAP32[i9 + 4 >> 2] = i11;
+ i9 = i1 + 44 | 0;
+ HEAP32[i9 >> 2] = i12;
+ HEAP32[i9 + 4 >> 2] = i11;
+ HEAPF32[i1 + 52 >> 2] = +HEAPF32[i7 >> 2];
+ HEAPF32[i1 + 56 >> 2] = +HEAPF32[i7 >> 2];
+ HEAPF32[i1 + 60 >> 2] = 0.0;
+ HEAP32[i1 + 108 >> 2] = 0;
+ HEAP32[i1 + 112 >> 2] = 0;
+ HEAP32[i1 + 92 >> 2] = 0;
+ HEAP32[i1 + 96 >> 2] = 0;
+ i9 = i6;
+ i11 = HEAP32[i9 + 4 >> 2] | 0;
+ i12 = i1 + 64 | 0;
+ HEAP32[i12 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i12 + 4 >> 2] = i11;
+ HEAPF32[i1 + 72 >> 2] = +HEAPF32[i8 >> 2];
+ HEAPF32[i1 + 132 >> 2] = +HEAPF32[i10 >> 2];
+ HEAPF32[i1 + 136 >> 2] = +HEAPF32[i4 >> 2];
+ HEAPF32[i1 + 140 >> 2] = +HEAPF32[i2 + 48 >> 2];
+ HEAPF32[i1 + 76 >> 2] = 0.0;
+ HEAPF32[i1 + 80 >> 2] = 0.0;
+ HEAPF32[i1 + 84 >> 2] = 0.0;
+ HEAPF32[i1 + 144 >> 2] = 0.0;
+ i12 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i1 >> 2] = i12;
+ i4 = i1 + 116 | 0;
+ if ((i12 | 0) == 2) {
+  HEAPF32[i4 >> 2] = 1.0;
+  HEAPF32[i1 + 120 >> 2] = 1.0;
+  i11 = i1 + 124 | 0;
+  HEAPF32[i11 >> 2] = 0.0;
+  i11 = i1 + 128 | 0;
+  HEAPF32[i11 >> 2] = 0.0;
+  i11 = i2 + 44 | 0;
+  i11 = HEAP32[i11 >> 2] | 0;
+  i12 = i1 + 148 | 0;
+  HEAP32[i12 >> 2] = i11;
+  i12 = i1 + 100 | 0;
+  HEAP32[i12 >> 2] = 0;
+  i12 = i1 + 104 | 0;
+  HEAP32[i12 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ } else {
+  HEAPF32[i4 >> 2] = 0.0;
+  HEAPF32[i1 + 120 >> 2] = 0.0;
+  i11 = i1 + 124 | 0;
+  HEAPF32[i11 >> 2] = 0.0;
+  i11 = i1 + 128 | 0;
+  HEAPF32[i11 >> 2] = 0.0;
+  i11 = i2 + 44 | 0;
+  i11 = HEAP32[i11 >> 2] | 0;
+  i12 = i1 + 148 | 0;
+  HEAP32[i12 >> 2] = i11;
+  i12 = i1 + 100 | 0;
+  HEAP32[i12 >> 2] = 0;
+  i12 = i1 + 104 | 0;
+  HEAP32[i12 >> 2] = 0;
+  STACKTOP = i3;
+  return;
+ }
+}
+function __ZN24b2PositionSolverManifold10InitializeEP27b2ContactPositionConstraintRK11b2TransformS4_i(i2, i1, i13, i12, i15) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i13 = i13 | 0;
+ i12 = i12 | 0;
+ i15 = i15 | 0;
+ var i3 = 0, d4 = 0.0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i14 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, i19 = 0, i20 = 0;
+ i3 = STACKTOP;
+ if ((HEAP32[i1 + 84 >> 2] | 0) <= 0) {
+  ___assert_fail(6752, 6520, 617, 6776);
+ }
+ i14 = HEAP32[i1 + 72 >> 2] | 0;
+ if ((i14 | 0) == 1) {
+  i19 = i13 + 12 | 0;
+  d5 = +HEAPF32[i19 >> 2];
+  d6 = +HEAPF32[i1 + 16 >> 2];
+  i14 = i13 + 8 | 0;
+  d7 = +HEAPF32[i14 >> 2];
+  d9 = +HEAPF32[i1 + 20 >> 2];
+  d4 = d5 * d6 - d7 * d9;
+  d9 = d6 * d7 + d5 * d9;
+  d5 = +d4;
+  d7 = +d9;
+  i20 = i2;
+  HEAPF32[i20 >> 2] = d5;
+  HEAPF32[i20 + 4 >> 2] = d7;
+  d7 = +HEAPF32[i19 >> 2];
+  d5 = +HEAPF32[i1 + 24 >> 2];
+  d6 = +HEAPF32[i14 >> 2];
+  d8 = +HEAPF32[i1 + 28 >> 2];
+  d16 = +HEAPF32[i12 + 12 >> 2];
+  d18 = +HEAPF32[i1 + (i15 << 3) >> 2];
+  d17 = +HEAPF32[i12 + 8 >> 2];
+  d11 = +HEAPF32[i1 + (i15 << 3) + 4 >> 2];
+  d10 = +HEAPF32[i12 >> 2] + (d16 * d18 - d17 * d11);
+  d11 = d18 * d17 + d16 * d11 + +HEAPF32[i12 + 4 >> 2];
+  HEAPF32[i2 + 16 >> 2] = d4 * (d10 - (+HEAPF32[i13 >> 2] + (d7 * d5 - d6 * d8))) + (d11 - (d5 * d6 + d7 * d8 + +HEAPF32[i13 + 4 >> 2])) * d9 - +HEAPF32[i1 + 76 >> 2] - +HEAPF32[i1 + 80 >> 2];
+  d10 = +d10;
+  d11 = +d11;
+  i15 = i2 + 8 | 0;
+  HEAPF32[i15 >> 2] = d10;
+  HEAPF32[i15 + 4 >> 2] = d11;
+  STACKTOP = i3;
+  return;
+ } else if ((i14 | 0) == 2) {
+  i19 = i12 + 12 | 0;
+  d7 = +HEAPF32[i19 >> 2];
+  d8 = +HEAPF32[i1 + 16 >> 2];
+  i20 = i12 + 8 | 0;
+  d9 = +HEAPF32[i20 >> 2];
+  d18 = +HEAPF32[i1 + 20 >> 2];
+  d17 = d7 * d8 - d9 * d18;
+  d18 = d8 * d9 + d7 * d18;
+  d7 = +d17;
+  d9 = +d18;
+  i14 = i2;
+  HEAPF32[i14 >> 2] = d7;
+  HEAPF32[i14 + 4 >> 2] = d9;
+  d9 = +HEAPF32[i19 >> 2];
+  d7 = +HEAPF32[i1 + 24 >> 2];
+  d8 = +HEAPF32[i20 >> 2];
+  d10 = +HEAPF32[i1 + 28 >> 2];
+  d6 = +HEAPF32[i13 + 12 >> 2];
+  d4 = +HEAPF32[i1 + (i15 << 3) >> 2];
+  d5 = +HEAPF32[i13 + 8 >> 2];
+  d16 = +HEAPF32[i1 + (i15 << 3) + 4 >> 2];
+  d11 = +HEAPF32[i13 >> 2] + (d6 * d4 - d5 * d16);
+  d16 = d4 * d5 + d6 * d16 + +HEAPF32[i13 + 4 >> 2];
+  HEAPF32[i2 + 16 >> 2] = d17 * (d11 - (+HEAPF32[i12 >> 2] + (d9 * d7 - d8 * d10))) + (d16 - (d7 * d8 + d9 * d10 + +HEAPF32[i12 + 4 >> 2])) * d18 - +HEAPF32[i1 + 76 >> 2] - +HEAPF32[i1 + 80 >> 2];
+  d11 = +d11;
+  d16 = +d16;
+  i20 = i2 + 8 | 0;
+  HEAPF32[i20 >> 2] = d11;
+  HEAPF32[i20 + 4 >> 2] = d16;
+  d17 = +-d17;
+  d18 = +-d18;
+  i20 = i2;
+  HEAPF32[i20 >> 2] = d17;
+  HEAPF32[i20 + 4 >> 2] = d18;
+  STACKTOP = i3;
+  return;
+ } else if ((i14 | 0) == 0) {
+  d7 = +HEAPF32[i13 + 12 >> 2];
+  d8 = +HEAPF32[i1 + 24 >> 2];
+  d18 = +HEAPF32[i13 + 8 >> 2];
+  d6 = +HEAPF32[i1 + 28 >> 2];
+  d4 = +HEAPF32[i13 >> 2] + (d7 * d8 - d18 * d6);
+  d6 = d8 * d18 + d7 * d6 + +HEAPF32[i13 + 4 >> 2];
+  d7 = +HEAPF32[i12 + 12 >> 2];
+  d18 = +HEAPF32[i1 >> 2];
+  d8 = +HEAPF32[i12 + 8 >> 2];
+  d9 = +HEAPF32[i1 + 4 >> 2];
+  d5 = +HEAPF32[i12 >> 2] + (d7 * d18 - d8 * d9);
+  d9 = d18 * d8 + d7 * d9 + +HEAPF32[i12 + 4 >> 2];
+  d7 = d5 - d4;
+  d8 = d9 - d6;
+  d18 = +d7;
+  d10 = +d8;
+  i20 = i2;
+  HEAPF32[i20 >> 2] = d18;
+  HEAPF32[i20 + 4 >> 2] = d10;
+  d10 = +Math_sqrt(+(d7 * d7 + d8 * d8));
+  if (d10 < 1.1920928955078125e-7) {
+   d10 = d7;
+   d11 = d8;
+  } else {
+   d11 = 1.0 / d10;
+   d10 = d7 * d11;
+   HEAPF32[i2 >> 2] = d10;
+   d11 = d8 * d11;
+   HEAPF32[i2 + 4 >> 2] = d11;
+  }
+  d17 = +((d4 + d5) * .5);
+  d18 = +((d6 + d9) * .5);
+  i20 = i2 + 8 | 0;
+  HEAPF32[i20 >> 2] = d17;
+  HEAPF32[i20 + 4 >> 2] = d18;
+  HEAPF32[i2 + 16 >> 2] = d7 * d10 + d8 * d11 - +HEAPF32[i1 + 76 >> 2] - +HEAPF32[i1 + 80 >> 2];
+  STACKTOP = i3;
+  return;
+ } else {
+  STACKTOP = i3;
+  return;
+ }
+}
+function __ZNSt3__118__insertion_sort_3IRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i5, i1, i2) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i6 = i4 + 12 | 0;
+ i3 = i4;
+ i7 = i5 + 24 | 0;
+ i8 = i5 + 12 | 0;
+ i10 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i8, i5) | 0;
+ i9 = FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i7, i8) | 0;
+ do {
+  if (i10) {
+   if (i9) {
+    HEAP32[i6 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+    HEAP32[i6 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+    HEAP32[i6 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    HEAP32[i5 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i5 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+    break;
+   }
+   HEAP32[i6 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+   HEAP32[i6 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i6 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+   HEAP32[i5 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+   HEAP32[i5 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+   HEAP32[i8 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i8 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i8 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i7, i8) | 0) {
+    HEAP32[i6 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+    HEAP32[i6 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+    HEAP32[i6 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+    HEAP32[i8 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i8 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i8 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   }
+  } else {
+   if (i9) {
+    HEAP32[i6 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+    HEAP32[i6 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+    HEAP32[i6 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+    HEAP32[i8 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i8 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i8 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    HEAP32[i7 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+    HEAP32[i7 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+    HEAP32[i7 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+    if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i8, i5) | 0) {
+     HEAP32[i6 + 0 >> 2] = HEAP32[i5 + 0 >> 2];
+     HEAP32[i6 + 4 >> 2] = HEAP32[i5 + 4 >> 2];
+     HEAP32[i6 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+     HEAP32[i5 + 0 >> 2] = HEAP32[i8 + 0 >> 2];
+     HEAP32[i5 + 4 >> 2] = HEAP32[i8 + 4 >> 2];
+     HEAP32[i5 + 8 >> 2] = HEAP32[i8 + 8 >> 2];
+     HEAP32[i8 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+     HEAP32[i8 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+     HEAP32[i8 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+    }
+   }
+  }
+ } while (0);
+ i6 = i5 + 36 | 0;
+ if ((i6 | 0) == (i1 | 0)) {
+  STACKTOP = i4;
+  return;
+ }
+ while (1) {
+  if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i6, i7) | 0) {
+   HEAP32[i3 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+   HEAP32[i3 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   i8 = i6;
+   while (1) {
+    HEAP32[i8 + 0 >> 2] = HEAP32[i7 + 0 >> 2];
+    HEAP32[i8 + 4 >> 2] = HEAP32[i7 + 4 >> 2];
+    HEAP32[i8 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+    if ((i7 | 0) == (i5 | 0)) {
+     break;
+    }
+    i8 = i7 + -12 | 0;
+    if (FUNCTION_TABLE_iii[HEAP32[i2 >> 2] & 3](i3, i8) | 0) {
+     i10 = i7;
+     i7 = i8;
+     i8 = i10;
+    } else {
+     break;
+    }
+   }
+   HEAP32[i7 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+   HEAP32[i7 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+   HEAP32[i7 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+  }
+  i7 = i6 + 12 | 0;
+  if ((i7 | 0) == (i1 | 0)) {
+   break;
+  } else {
+   i10 = i6;
+   i6 = i7;
+   i7 = i10;
+  }
+ }
+ STACKTOP = i4;
+ return;
+}
+function __ZNK20b2SeparationFunction8EvaluateEiif(i10, i12, i11, d9) {
+ i10 = i10 | 0;
+ i12 = i12 | 0;
+ i11 = i11 | 0;
+ d9 = +d9;
+ var d1 = 0.0, d2 = 0.0, d3 = 0.0, d4 = 0.0, d5 = 0.0, d6 = 0.0, i7 = 0, d8 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, i17 = 0, d18 = 0.0, d19 = 0.0;
+ i7 = STACKTOP;
+ d14 = 1.0 - d9;
+ d3 = d14 * +HEAPF32[i10 + 32 >> 2] + +HEAPF32[i10 + 36 >> 2] * d9;
+ d4 = +Math_sin(+d3);
+ d3 = +Math_cos(+d3);
+ d5 = +HEAPF32[i10 + 8 >> 2];
+ d6 = +HEAPF32[i10 + 12 >> 2];
+ d2 = d14 * +HEAPF32[i10 + 16 >> 2] + +HEAPF32[i10 + 24 >> 2] * d9 - (d3 * d5 - d4 * d6);
+ d6 = d14 * +HEAPF32[i10 + 20 >> 2] + +HEAPF32[i10 + 28 >> 2] * d9 - (d4 * d5 + d3 * d6);
+ d5 = d14 * +HEAPF32[i10 + 68 >> 2] + +HEAPF32[i10 + 72 >> 2] * d9;
+ d1 = +Math_sin(+d5);
+ d5 = +Math_cos(+d5);
+ d15 = +HEAPF32[i10 + 44 >> 2];
+ d16 = +HEAPF32[i10 + 48 >> 2];
+ d8 = d14 * +HEAPF32[i10 + 52 >> 2] + +HEAPF32[i10 + 60 >> 2] * d9 - (d5 * d15 - d1 * d16);
+ d9 = d14 * +HEAPF32[i10 + 56 >> 2] + +HEAPF32[i10 + 64 >> 2] * d9 - (d1 * d15 + d5 * d16);
+ i17 = HEAP32[i10 + 80 >> 2] | 0;
+ if ((i17 | 0) == 0) {
+  d14 = +HEAPF32[i10 + 92 >> 2];
+  d13 = +HEAPF32[i10 + 96 >> 2];
+  i17 = HEAP32[i10 >> 2] | 0;
+  if (!((i12 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i17 + 20 >> 2] | 0) <= (i12 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i17 = (HEAP32[i17 + 16 >> 2] | 0) + (i12 << 3) | 0;
+  d15 = +HEAPF32[i17 >> 2];
+  d16 = +HEAPF32[i17 + 4 >> 2];
+  i10 = HEAP32[i10 + 4 >> 2] | 0;
+  if (!((i11 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i10 + 20 >> 2] | 0) <= (i11 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i17 = (HEAP32[i10 + 16 >> 2] | 0) + (i11 << 3) | 0;
+  d19 = +HEAPF32[i17 >> 2];
+  d18 = +HEAPF32[i17 + 4 >> 2];
+  d16 = d14 * (d8 + (d5 * d19 - d1 * d18) - (d2 + (d3 * d15 - d4 * d16))) + d13 * (d9 + (d1 * d19 + d5 * d18) - (d6 + (d4 * d15 + d3 * d16)));
+  STACKTOP = i7;
+  return +d16;
+ } else if ((i17 | 0) == 1) {
+  d14 = +HEAPF32[i10 + 92 >> 2];
+  d13 = +HEAPF32[i10 + 96 >> 2];
+  d16 = +HEAPF32[i10 + 84 >> 2];
+  d15 = +HEAPF32[i10 + 88 >> 2];
+  i10 = HEAP32[i10 + 4 >> 2] | 0;
+  if (!((i11 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i10 + 20 >> 2] | 0) <= (i11 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i17 = (HEAP32[i10 + 16 >> 2] | 0) + (i11 << 3) | 0;
+  d18 = +HEAPF32[i17 >> 2];
+  d19 = +HEAPF32[i17 + 4 >> 2];
+  d19 = (d3 * d14 - d4 * d13) * (d8 + (d5 * d18 - d1 * d19) - (d2 + (d3 * d16 - d4 * d15))) + (d4 * d14 + d3 * d13) * (d9 + (d1 * d18 + d5 * d19) - (d6 + (d4 * d16 + d3 * d15)));
+  STACKTOP = i7;
+  return +d19;
+ } else if ((i17 | 0) == 2) {
+  d16 = +HEAPF32[i10 + 92 >> 2];
+  d15 = +HEAPF32[i10 + 96 >> 2];
+  d14 = +HEAPF32[i10 + 84 >> 2];
+  d13 = +HEAPF32[i10 + 88 >> 2];
+  i10 = HEAP32[i10 >> 2] | 0;
+  if (!((i12 | 0) > -1)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  if ((HEAP32[i10 + 20 >> 2] | 0) <= (i12 | 0)) {
+   ___assert_fail(3640, 3672, 103, 3704);
+  }
+  i17 = (HEAP32[i10 + 16 >> 2] | 0) + (i12 << 3) | 0;
+  d18 = +HEAPF32[i17 >> 2];
+  d19 = +HEAPF32[i17 + 4 >> 2];
+  d19 = (d5 * d16 - d1 * d15) * (d2 + (d3 * d18 - d4 * d19) - (d8 + (d5 * d14 - d1 * d13))) + (d1 * d16 + d5 * d15) * (d6 + (d4 * d18 + d3 * d19) - (d9 + (d1 * d14 + d5 * d13)));
+  STACKTOP = i7;
+  return +d19;
+ } else {
+  ___assert_fail(3616, 3560, 242, 3624);
+ }
+ return 0.0;
+}
+function __ZN6b2Body13ResetMassDataEv(i2) {
+ i2 = i2 | 0;
+ var d1 = 0.0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, d14 = 0.0, d15 = 0.0, d16 = 0.0, i17 = 0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i10 = i3;
+ i8 = i2 + 116 | 0;
+ i9 = i2 + 120 | 0;
+ i4 = i2 + 124 | 0;
+ i5 = i2 + 128 | 0;
+ i6 = i2 + 28 | 0;
+ HEAPF32[i6 >> 2] = 0.0;
+ HEAPF32[i2 + 32 >> 2] = 0.0;
+ HEAP32[i8 + 0 >> 2] = 0;
+ HEAP32[i8 + 4 >> 2] = 0;
+ HEAP32[i8 + 8 >> 2] = 0;
+ HEAP32[i8 + 12 >> 2] = 0;
+ i11 = HEAP32[i2 >> 2] | 0;
+ if ((i11 | 0) == 2) {
+  i17 = 3784;
+  d16 = +HEAPF32[i17 >> 2];
+  d18 = +HEAPF32[i17 + 4 >> 2];
+  i17 = HEAP32[i2 + 100 >> 2] | 0;
+  if ((i17 | 0) != 0) {
+   i11 = i10 + 4 | 0;
+   i12 = i10 + 8 | 0;
+   i13 = i10 + 12 | 0;
+   d14 = 0.0;
+   d15 = 0.0;
+   do {
+    d19 = +HEAPF32[i17 >> 2];
+    if (!(d19 == 0.0)) {
+     i20 = HEAP32[i17 + 12 >> 2] | 0;
+     FUNCTION_TABLE_viid[HEAP32[(HEAP32[i20 >> 2] | 0) + 28 >> 2] & 3](i20, i10, d19);
+     d14 = +HEAPF32[i10 >> 2];
+     d15 = d14 + +HEAPF32[i8 >> 2];
+     HEAPF32[i8 >> 2] = d15;
+     d16 = d16 + d14 * +HEAPF32[i11 >> 2];
+     d18 = d18 + d14 * +HEAPF32[i12 >> 2];
+     d14 = +HEAPF32[i13 >> 2] + +HEAPF32[i4 >> 2];
+     HEAPF32[i4 >> 2] = d14;
+    }
+    i17 = HEAP32[i17 + 4 >> 2] | 0;
+   } while ((i17 | 0) != 0);
+   if (d15 > 0.0) {
+    d19 = 1.0 / d15;
+    HEAPF32[i9 >> 2] = d19;
+    d16 = d16 * d19;
+    d18 = d18 * d19;
+   } else {
+    i7 = 11;
+   }
+  } else {
+   d14 = 0.0;
+   i7 = 11;
+  }
+  if ((i7 | 0) == 11) {
+   HEAPF32[i8 >> 2] = 1.0;
+   HEAPF32[i9 >> 2] = 1.0;
+   d15 = 1.0;
+  }
+  do {
+   if (d14 > 0.0 ? (HEAP16[i2 + 4 >> 1] & 16) == 0 : 0) {
+    d14 = d14 - (d18 * d18 + d16 * d16) * d15;
+    HEAPF32[i4 >> 2] = d14;
+    if (d14 > 0.0) {
+     d1 = 1.0 / d14;
+     break;
+    } else {
+     ___assert_fail(1872, 1520, 319, 1856);
+    }
+   } else {
+    i7 = 17;
+   }
+  } while (0);
+  if ((i7 | 0) == 17) {
+   HEAPF32[i4 >> 2] = 0.0;
+   d1 = 0.0;
+  }
+  HEAPF32[i5 >> 2] = d1;
+  i20 = i2 + 44 | 0;
+  i17 = i20;
+  d19 = +HEAPF32[i17 >> 2];
+  d14 = +HEAPF32[i17 + 4 >> 2];
+  d21 = +d16;
+  d1 = +d18;
+  i17 = i6;
+  HEAPF32[i17 >> 2] = d21;
+  HEAPF32[i17 + 4 >> 2] = d1;
+  d1 = +HEAPF32[i2 + 24 >> 2];
+  d21 = +HEAPF32[i2 + 20 >> 2];
+  d15 = +HEAPF32[i2 + 12 >> 2] + (d1 * d16 - d21 * d18);
+  d16 = d16 * d21 + d1 * d18 + +HEAPF32[i2 + 16 >> 2];
+  d1 = +d15;
+  d18 = +d16;
+  HEAPF32[i20 >> 2] = d1;
+  HEAPF32[i20 + 4 >> 2] = d18;
+  i20 = i2 + 36 | 0;
+  HEAPF32[i20 >> 2] = d1;
+  HEAPF32[i20 + 4 >> 2] = d18;
+  d18 = +HEAPF32[i2 + 72 >> 2];
+  i20 = i2 + 64 | 0;
+  HEAPF32[i20 >> 2] = +HEAPF32[i20 >> 2] - d18 * (d16 - d14);
+  i20 = i2 + 68 | 0;
+  HEAPF32[i20 >> 2] = d18 * (d15 - d19) + +HEAPF32[i20 >> 2];
+  STACKTOP = i3;
+  return;
+ } else if ((i11 | 0) == 1 | (i11 | 0) == 0) {
+  i17 = i2 + 12 | 0;
+  i13 = HEAP32[i17 >> 2] | 0;
+  i17 = HEAP32[i17 + 4 >> 2] | 0;
+  i20 = i2 + 36 | 0;
+  HEAP32[i20 >> 2] = i13;
+  HEAP32[i20 + 4 >> 2] = i17;
+  i20 = i2 + 44 | 0;
+  HEAP32[i20 >> 2] = i13;
+  HEAP32[i20 + 4 >> 2] = i17;
+  HEAPF32[i2 + 52 >> 2] = +HEAPF32[i2 + 56 >> 2];
+  STACKTOP = i3;
+  return;
+ } else {
+  ___assert_fail(1824, 1520, 284, 1856);
+ }
+}
+function __ZN9b2Contact6UpdateEP17b2ContactListener(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i2 = i3;
+ i10 = i1 + 64 | 0;
+ i6 = i2 + 0 | 0;
+ i7 = i10 + 0 | 0;
+ i5 = i6 + 64 | 0;
+ do {
+  HEAP32[i6 >> 2] = HEAP32[i7 >> 2];
+  i6 = i6 + 4 | 0;
+  i7 = i7 + 4 | 0;
+ } while ((i6 | 0) < (i5 | 0));
+ i6 = i1 + 4 | 0;
+ i11 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i11 | 4;
+ i11 = i11 >>> 1;
+ i14 = HEAP32[i1 + 48 >> 2] | 0;
+ i15 = HEAP32[i1 + 52 >> 2] | 0;
+ i5 = (HEAP8[i15 + 38 | 0] | HEAP8[i14 + 38 | 0]) << 24 >> 24 != 0;
+ i8 = HEAP32[i14 + 8 >> 2] | 0;
+ i7 = HEAP32[i15 + 8 >> 2] | 0;
+ i12 = i8 + 12 | 0;
+ i13 = i7 + 12 | 0;
+ if (!i5) {
+  FUNCTION_TABLE_viiii[HEAP32[HEAP32[i1 >> 2] >> 2] & 15](i1, i10, i12, i13);
+  i12 = i1 + 124 | 0;
+  i10 = (HEAP32[i12 >> 2] | 0) > 0;
+  L4 : do {
+   if (i10) {
+    i19 = HEAP32[i2 + 60 >> 2] | 0;
+    if ((i19 | 0) > 0) {
+     i18 = 0;
+    } else {
+     i9 = 0;
+     while (1) {
+      HEAPF32[i1 + (i9 * 20 | 0) + 72 >> 2] = 0.0;
+      HEAPF32[i1 + (i9 * 20 | 0) + 76 >> 2] = 0.0;
+      i9 = i9 + 1 | 0;
+      if ((i9 | 0) >= (HEAP32[i12 >> 2] | 0)) {
+       break L4;
+      }
+     }
+    }
+    do {
+     i16 = i1 + (i18 * 20 | 0) + 72 | 0;
+     HEAPF32[i16 >> 2] = 0.0;
+     i15 = i1 + (i18 * 20 | 0) + 76 | 0;
+     HEAPF32[i15 >> 2] = 0.0;
+     i14 = HEAP32[i1 + (i18 * 20 | 0) + 80 >> 2] | 0;
+     i17 = 0;
+     while (1) {
+      i13 = i17 + 1 | 0;
+      if ((HEAP32[i2 + (i17 * 20 | 0) + 16 >> 2] | 0) == (i14 | 0)) {
+       i9 = 7;
+       break;
+      }
+      if ((i13 | 0) < (i19 | 0)) {
+       i17 = i13;
+      } else {
+       break;
+      }
+     }
+     if ((i9 | 0) == 7) {
+      i9 = 0;
+      HEAPF32[i16 >> 2] = +HEAPF32[i2 + (i17 * 20 | 0) + 8 >> 2];
+      HEAPF32[i15 >> 2] = +HEAPF32[i2 + (i17 * 20 | 0) + 12 >> 2];
+     }
+     i18 = i18 + 1 | 0;
+    } while ((i18 | 0) < (HEAP32[i12 >> 2] | 0));
+   }
+  } while (0);
+  i9 = i11 & 1;
+  if (i10 ^ (i9 | 0) != 0) {
+   i11 = i8 + 4 | 0;
+   i12 = HEAPU16[i11 >> 1] | 0;
+   if ((i12 & 2 | 0) == 0) {
+    HEAP16[i11 >> 1] = i12 | 2;
+    HEAPF32[i8 + 144 >> 2] = 0.0;
+   }
+   i8 = i7 + 4 | 0;
+   i11 = HEAPU16[i8 >> 1] | 0;
+   if ((i11 & 2 | 0) == 0) {
+    HEAP16[i8 >> 1] = i11 | 2;
+    HEAPF32[i7 + 144 >> 2] = 0.0;
+   }
+  }
+ } else {
+  i10 = __Z13b2TestOverlapPK7b2ShapeiS1_iRK11b2TransformS4_(HEAP32[i14 + 12 >> 2] | 0, HEAP32[i1 + 56 >> 2] | 0, HEAP32[i15 + 12 >> 2] | 0, HEAP32[i1 + 60 >> 2] | 0, i12, i13) | 0;
+  HEAP32[i1 + 124 >> 2] = 0;
+  i9 = i11 & 1;
+ }
+ i7 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i10 ? i7 | 2 : i7 & -3;
+ i8 = (i9 | 0) == 0;
+ i6 = i10 ^ 1;
+ i7 = (i4 | 0) == 0;
+ if (!(i8 ^ 1 | i6 | i7)) {
+  FUNCTION_TABLE_vii[HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] & 15](i4, i1);
+ }
+ if (!(i8 | i10 | i7)) {
+  FUNCTION_TABLE_vii[HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] & 15](i4, i1);
+ }
+ if (i5 | i6 | i7) {
+  STACKTOP = i3;
+  return;
+ }
+ FUNCTION_TABLE_viii[HEAP32[(HEAP32[i4 >> 2] | 0) + 16 >> 2] & 3](i4, i1, i2);
+ STACKTOP = i3;
+ return;
+}
+function __ZN13b2DynamicTree10RemoveLeafEi(i1, i12) {
+ i1 = i1 | 0;
+ i12 = i12 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i13 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i1 >> 2] | 0) == (i12 | 0)) {
+  HEAP32[i1 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i1 + 4 | 0;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i6 = HEAP32[i5 + (i12 * 36 | 0) + 20 >> 2] | 0;
+ i4 = i5 + (i6 * 36 | 0) + 20 | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ i13 = HEAP32[i5 + (i6 * 36 | 0) + 24 >> 2] | 0;
+ if ((i13 | 0) == (i12 | 0)) {
+  i13 = HEAP32[i5 + (i6 * 36 | 0) + 28 >> 2] | 0;
+ }
+ if ((i7 | 0) == -1) {
+  HEAP32[i1 >> 2] = i13;
+  HEAP32[i5 + (i13 * 36 | 0) + 20 >> 2] = -1;
+  if (!((i6 | 0) > -1)) {
+   ___assert_fail(3e3, 2944, 97, 3040);
+  }
+  if ((HEAP32[i1 + 12 >> 2] | 0) <= (i6 | 0)) {
+   ___assert_fail(3e3, 2944, 97, 3040);
+  }
+  i3 = i1 + 8 | 0;
+  if ((HEAP32[i3 >> 2] | 0) <= 0) {
+   ___assert_fail(3056, 2944, 98, 3040);
+  }
+  i13 = i1 + 16 | 0;
+  HEAP32[i4 >> 2] = HEAP32[i13 >> 2];
+  HEAP32[i5 + (i6 * 36 | 0) + 32 >> 2] = -1;
+  HEAP32[i13 >> 2] = i6;
+  HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + -1;
+  STACKTOP = i2;
+  return;
+ }
+ i12 = i5 + (i7 * 36 | 0) + 24 | 0;
+ if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+  HEAP32[i12 >> 2] = i13;
+ } else {
+  HEAP32[i5 + (i7 * 36 | 0) + 28 >> 2] = i13;
+ }
+ HEAP32[i5 + (i13 * 36 | 0) + 20 >> 2] = i7;
+ if (!((i6 | 0) > -1)) {
+  ___assert_fail(3e3, 2944, 97, 3040);
+ }
+ if ((HEAP32[i1 + 12 >> 2] | 0) <= (i6 | 0)) {
+  ___assert_fail(3e3, 2944, 97, 3040);
+ }
+ i12 = i1 + 8 | 0;
+ if ((HEAP32[i12 >> 2] | 0) <= 0) {
+  ___assert_fail(3056, 2944, 98, 3040);
+ }
+ i13 = i1 + 16 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i13 >> 2];
+ HEAP32[i5 + (i6 * 36 | 0) + 32 >> 2] = -1;
+ HEAP32[i13 >> 2] = i6;
+ HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + -1;
+ do {
+  i4 = __ZN13b2DynamicTree7BalanceEi(i1, i7) | 0;
+  i7 = HEAP32[i3 >> 2] | 0;
+  i6 = HEAP32[i7 + (i4 * 36 | 0) + 24 >> 2] | 0;
+  i5 = HEAP32[i7 + (i4 * 36 | 0) + 28 >> 2] | 0;
+  d10 = +HEAPF32[i7 + (i6 * 36 | 0) >> 2];
+  d11 = +HEAPF32[i7 + (i5 * 36 | 0) >> 2];
+  d9 = +HEAPF32[i7 + (i6 * 36 | 0) + 4 >> 2];
+  d8 = +HEAPF32[i7 + (i5 * 36 | 0) + 4 >> 2];
+  d10 = +(d10 < d11 ? d10 : d11);
+  d11 = +(d9 < d8 ? d9 : d8);
+  i13 = i7 + (i4 * 36 | 0) | 0;
+  HEAPF32[i13 >> 2] = d10;
+  HEAPF32[i13 + 4 >> 2] = d11;
+  d11 = +HEAPF32[i7 + (i6 * 36 | 0) + 8 >> 2];
+  d10 = +HEAPF32[i7 + (i5 * 36 | 0) + 8 >> 2];
+  d9 = +HEAPF32[i7 + (i6 * 36 | 0) + 12 >> 2];
+  d8 = +HEAPF32[i7 + (i5 * 36 | 0) + 12 >> 2];
+  d10 = +(d11 > d10 ? d11 : d10);
+  d11 = +(d9 > d8 ? d9 : d8);
+  i7 = i7 + (i4 * 36 | 0) + 8 | 0;
+  HEAPF32[i7 >> 2] = d10;
+  HEAPF32[i7 + 4 >> 2] = d11;
+  i7 = HEAP32[i3 >> 2] | 0;
+  i6 = HEAP32[i7 + (i6 * 36 | 0) + 32 >> 2] | 0;
+  i5 = HEAP32[i7 + (i5 * 36 | 0) + 32 >> 2] | 0;
+  HEAP32[i7 + (i4 * 36 | 0) + 32 >> 2] = ((i6 | 0) > (i5 | 0) ? i6 : i5) + 1;
+  i7 = HEAP32[i7 + (i4 * 36 | 0) + 20 >> 2] | 0;
+ } while (!((i7 | 0) == -1));
+ STACKTOP = i2;
+ return;
+}
+function __ZN9b2Simplex6Solve3Ev(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, d4 = 0.0, d5 = 0.0, d6 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, i22 = 0;
+ i1 = STACKTOP;
+ i2 = i7 + 16 | 0;
+ d17 = +HEAPF32[i2 >> 2];
+ d15 = +HEAPF32[i2 + 4 >> 2];
+ i2 = i7 + 36 | 0;
+ i3 = i7 + 52 | 0;
+ d14 = +HEAPF32[i3 >> 2];
+ d16 = +HEAPF32[i3 + 4 >> 2];
+ i3 = i7 + 72 | 0;
+ i22 = i7 + 88 | 0;
+ d18 = +HEAPF32[i22 >> 2];
+ d11 = +HEAPF32[i22 + 4 >> 2];
+ d20 = d14 - d17;
+ d10 = d16 - d15;
+ d9 = d17 * d20 + d15 * d10;
+ d8 = d14 * d20 + d16 * d10;
+ d4 = d18 - d17;
+ d19 = d11 - d15;
+ d6 = d17 * d4 + d15 * d19;
+ d5 = d18 * d4 + d11 * d19;
+ d21 = d18 - d14;
+ d12 = d11 - d16;
+ d13 = d14 * d21 + d16 * d12;
+ d12 = d18 * d21 + d11 * d12;
+ d4 = d20 * d19 - d10 * d4;
+ d10 = (d14 * d11 - d16 * d18) * d4;
+ d11 = (d15 * d18 - d17 * d11) * d4;
+ d4 = (d17 * d16 - d15 * d14) * d4;
+ if (!(!(d9 >= -0.0) | !(d6 >= -0.0))) {
+  HEAPF32[i7 + 24 >> 2] = 1.0;
+  HEAP32[i7 + 108 >> 2] = 1;
+  STACKTOP = i1;
+  return;
+ }
+ if (!(!(d9 < -0.0) | !(d8 > 0.0) | !(d4 <= 0.0))) {
+  d21 = 1.0 / (d8 - d9);
+  HEAPF32[i7 + 24 >> 2] = d8 * d21;
+  HEAPF32[i7 + 60 >> 2] = -(d9 * d21);
+  HEAP32[i7 + 108 >> 2] = 2;
+  STACKTOP = i1;
+  return;
+ }
+ if (!(!(d6 < -0.0) | !(d5 > 0.0) | !(d11 <= 0.0))) {
+  d21 = 1.0 / (d5 - d6);
+  HEAPF32[i7 + 24 >> 2] = d5 * d21;
+  HEAPF32[i7 + 96 >> 2] = -(d6 * d21);
+  HEAP32[i7 + 108 >> 2] = 2;
+  i7 = i2 + 0 | 0;
+  i3 = i3 + 0 | 0;
+  i2 = i7 + 36 | 0;
+  do {
+   HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+   i7 = i7 + 4 | 0;
+   i3 = i3 + 4 | 0;
+  } while ((i7 | 0) < (i2 | 0));
+  STACKTOP = i1;
+  return;
+ }
+ if (!(!(d8 <= 0.0) | !(d13 >= -0.0))) {
+  HEAPF32[i7 + 60 >> 2] = 1.0;
+  HEAP32[i7 + 108 >> 2] = 1;
+  i7 = i7 + 0 | 0;
+  i3 = i2 + 0 | 0;
+  i2 = i7 + 36 | 0;
+  do {
+   HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+   i7 = i7 + 4 | 0;
+   i3 = i3 + 4 | 0;
+  } while ((i7 | 0) < (i2 | 0));
+  STACKTOP = i1;
+  return;
+ }
+ if (!(!(d5 <= 0.0) | !(d12 <= 0.0))) {
+  HEAPF32[i7 + 96 >> 2] = 1.0;
+  HEAP32[i7 + 108 >> 2] = 1;
+  i7 = i7 + 0 | 0;
+  i3 = i3 + 0 | 0;
+  i2 = i7 + 36 | 0;
+  do {
+   HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+   i7 = i7 + 4 | 0;
+   i3 = i3 + 4 | 0;
+  } while ((i7 | 0) < (i2 | 0));
+  STACKTOP = i1;
+  return;
+ }
+ if (!(d13 < -0.0) | !(d12 > 0.0) | !(d10 <= 0.0)) {
+  d21 = 1.0 / (d4 + (d10 + d11));
+  HEAPF32[i7 + 24 >> 2] = d10 * d21;
+  HEAPF32[i7 + 60 >> 2] = d11 * d21;
+  HEAPF32[i7 + 96 >> 2] = d4 * d21;
+  HEAP32[i7 + 108 >> 2] = 3;
+  STACKTOP = i1;
+  return;
+ } else {
+  d21 = 1.0 / (d12 - d13);
+  HEAPF32[i7 + 60 >> 2] = d12 * d21;
+  HEAPF32[i7 + 96 >> 2] = -(d13 * d21);
+  HEAP32[i7 + 108 >> 2] = 2;
+  i7 = i7 + 0 | 0;
+  i3 = i3 + 0 | 0;
+  i2 = i7 + 36 | 0;
+  do {
+   HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+   i7 = i7 + 4 | 0;
+   i3 = i3 + 4 | 0;
+  } while ((i7 | 0) < (i2 | 0));
+  STACKTOP = i1;
+  return;
+ }
+}
+function __ZN16b2ContactManager7CollideEv(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i2 = STACKTOP;
+ i8 = HEAP32[i3 + 60 >> 2] | 0;
+ if ((i8 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = i3 + 12 | 0;
+ i6 = i3 + 4 | 0;
+ i5 = i3 + 72 | 0;
+ i4 = i3 + 68 | 0;
+ L4 : while (1) {
+  i12 = HEAP32[i8 + 48 >> 2] | 0;
+  i10 = HEAP32[i8 + 52 >> 2] | 0;
+  i11 = HEAP32[i8 + 56 >> 2] | 0;
+  i9 = HEAP32[i8 + 60 >> 2] | 0;
+  i15 = HEAP32[i12 + 8 >> 2] | 0;
+  i13 = HEAP32[i10 + 8 >> 2] | 0;
+  i16 = i8 + 4 | 0;
+  do {
+   if ((HEAP32[i16 >> 2] & 8 | 0) == 0) {
+    i1 = 11;
+   } else {
+    if (!(__ZNK6b2Body13ShouldCollideEPKS_(i13, i15) | 0)) {
+     i16 = HEAP32[i8 + 12 >> 2] | 0;
+     __ZN16b2ContactManager7DestroyEP9b2Contact(i3, i8);
+     i8 = i16;
+     break;
+    }
+    i14 = HEAP32[i4 >> 2] | 0;
+    if ((i14 | 0) != 0 ? !(FUNCTION_TABLE_iiii[HEAP32[(HEAP32[i14 >> 2] | 0) + 8 >> 2] & 7](i14, i12, i10) | 0) : 0) {
+     i16 = HEAP32[i8 + 12 >> 2] | 0;
+     __ZN16b2ContactManager7DestroyEP9b2Contact(i3, i8);
+     i8 = i16;
+     break;
+    }
+    HEAP32[i16 >> 2] = HEAP32[i16 >> 2] & -9;
+    i1 = 11;
+   }
+  } while (0);
+  do {
+   if ((i1 | 0) == 11) {
+    i1 = 0;
+    if ((HEAP16[i15 + 4 >> 1] & 2) == 0) {
+     i14 = 0;
+    } else {
+     i14 = (HEAP32[i15 >> 2] | 0) != 0;
+    }
+    if ((HEAP16[i13 + 4 >> 1] & 2) == 0) {
+     i13 = 0;
+    } else {
+     i13 = (HEAP32[i13 >> 2] | 0) != 0;
+    }
+    if (!(i14 | i13)) {
+     i8 = HEAP32[i8 + 12 >> 2] | 0;
+     break;
+    }
+    i11 = HEAP32[(HEAP32[i12 + 24 >> 2] | 0) + (i11 * 28 | 0) + 24 >> 2] | 0;
+    i9 = HEAP32[(HEAP32[i10 + 24 >> 2] | 0) + (i9 * 28 | 0) + 24 >> 2] | 0;
+    if (!((i11 | 0) > -1)) {
+     i1 = 19;
+     break L4;
+    }
+    i10 = HEAP32[i7 >> 2] | 0;
+    if ((i10 | 0) <= (i11 | 0)) {
+     i1 = 19;
+     break L4;
+    }
+    i12 = HEAP32[i6 >> 2] | 0;
+    if (!((i9 | 0) > -1 & (i10 | 0) > (i9 | 0))) {
+     i1 = 21;
+     break L4;
+    }
+    if (+HEAPF32[i12 + (i9 * 36 | 0) >> 2] - +HEAPF32[i12 + (i11 * 36 | 0) + 8 >> 2] > 0.0 | +HEAPF32[i12 + (i9 * 36 | 0) + 4 >> 2] - +HEAPF32[i12 + (i11 * 36 | 0) + 12 >> 2] > 0.0 | +HEAPF32[i12 + (i11 * 36 | 0) >> 2] - +HEAPF32[i12 + (i9 * 36 | 0) + 8 >> 2] > 0.0 | +HEAPF32[i12 + (i11 * 36 | 0) + 4 >> 2] - +HEAPF32[i12 + (i9 * 36 | 0) + 12 >> 2] > 0.0) {
+     i16 = HEAP32[i8 + 12 >> 2] | 0;
+     __ZN16b2ContactManager7DestroyEP9b2Contact(i3, i8);
+     i8 = i16;
+     break;
+    } else {
+     __ZN9b2Contact6UpdateEP17b2ContactListener(i8, HEAP32[i5 >> 2] | 0);
+     i8 = HEAP32[i8 + 12 >> 2] | 0;
+     break;
+    }
+   }
+  } while (0);
+  if ((i8 | 0) == 0) {
+   i1 = 25;
+   break;
+  }
+ }
+ if ((i1 | 0) == 19) {
+  ___assert_fail(1904, 1952, 159, 2008);
+ } else if ((i1 | 0) == 21) {
+  ___assert_fail(1904, 1952, 159, 2008);
+ } else if ((i1 | 0) == 25) {
+  STACKTOP = i2;
+  return;
+ }
+}
+function __ZN16b2ContactManager7AddPairEPvS0_(i1, i5, i6) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i5 + 16 >> 2] | 0;
+ i3 = HEAP32[i6 + 16 >> 2] | 0;
+ i5 = HEAP32[i5 + 20 >> 2] | 0;
+ i6 = HEAP32[i6 + 20 >> 2] | 0;
+ i8 = HEAP32[i4 + 8 >> 2] | 0;
+ i7 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((i8 | 0) == (i7 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i10 = HEAP32[i7 + 112 >> 2] | 0;
+ L4 : do {
+  if ((i10 | 0) != 0) {
+   while (1) {
+    if ((HEAP32[i10 >> 2] | 0) == (i8 | 0)) {
+     i9 = HEAP32[i10 + 4 >> 2] | 0;
+     i12 = HEAP32[i9 + 48 >> 2] | 0;
+     i13 = HEAP32[i9 + 52 >> 2] | 0;
+     i11 = HEAP32[i9 + 56 >> 2] | 0;
+     i9 = HEAP32[i9 + 60 >> 2] | 0;
+     if ((i12 | 0) == (i4 | 0) & (i13 | 0) == (i3 | 0) & (i11 | 0) == (i5 | 0) & (i9 | 0) == (i6 | 0)) {
+      i9 = 22;
+      break;
+     }
+     if ((i12 | 0) == (i3 | 0) & (i13 | 0) == (i4 | 0) & (i11 | 0) == (i6 | 0) & (i9 | 0) == (i5 | 0)) {
+      i9 = 22;
+      break;
+     }
+    }
+    i10 = HEAP32[i10 + 12 >> 2] | 0;
+    if ((i10 | 0) == 0) {
+     break L4;
+    }
+   }
+   if ((i9 | 0) == 22) {
+    STACKTOP = i2;
+    return;
+   }
+  }
+ } while (0);
+ if (!(__ZNK6b2Body13ShouldCollideEPKS_(i7, i8) | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[i1 + 68 >> 2] | 0;
+ if ((i7 | 0) != 0 ? !(FUNCTION_TABLE_iiii[HEAP32[(HEAP32[i7 >> 2] | 0) + 8 >> 2] & 7](i7, i4, i3) | 0) : 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i5 = __ZN9b2Contact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i4, i5, i3, i6, HEAP32[i1 + 76 >> 2] | 0) | 0;
+ if ((i5 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP32[(HEAP32[i5 + 48 >> 2] | 0) + 8 >> 2] | 0;
+ i3 = HEAP32[(HEAP32[i5 + 52 >> 2] | 0) + 8 >> 2] | 0;
+ HEAP32[i5 + 8 >> 2] = 0;
+ i7 = i1 + 60 | 0;
+ HEAP32[i5 + 12 >> 2] = HEAP32[i7 >> 2];
+ i6 = HEAP32[i7 >> 2] | 0;
+ if ((i6 | 0) != 0) {
+  HEAP32[i6 + 8 >> 2] = i5;
+ }
+ HEAP32[i7 >> 2] = i5;
+ i8 = i5 + 16 | 0;
+ HEAP32[i5 + 20 >> 2] = i5;
+ HEAP32[i8 >> 2] = i3;
+ HEAP32[i5 + 24 >> 2] = 0;
+ i6 = i4 + 112 | 0;
+ HEAP32[i5 + 28 >> 2] = HEAP32[i6 >> 2];
+ i7 = HEAP32[i6 >> 2] | 0;
+ if ((i7 | 0) != 0) {
+  HEAP32[i7 + 8 >> 2] = i8;
+ }
+ HEAP32[i6 >> 2] = i8;
+ i6 = i5 + 32 | 0;
+ HEAP32[i5 + 36 >> 2] = i5;
+ HEAP32[i6 >> 2] = i4;
+ HEAP32[i5 + 40 >> 2] = 0;
+ i7 = i3 + 112 | 0;
+ HEAP32[i5 + 44 >> 2] = HEAP32[i7 >> 2];
+ i5 = HEAP32[i7 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  HEAP32[i5 + 8 >> 2] = i6;
+ }
+ HEAP32[i7 >> 2] = i6;
+ i5 = i4 + 4 | 0;
+ i6 = HEAPU16[i5 >> 1] | 0;
+ if ((i6 & 2 | 0) == 0) {
+  HEAP16[i5 >> 1] = i6 | 2;
+  HEAPF32[i4 + 144 >> 2] = 0.0;
+ }
+ i4 = i3 + 4 | 0;
+ i5 = HEAPU16[i4 >> 1] | 0;
+ if ((i5 & 2 | 0) == 0) {
+  HEAP16[i4 >> 1] = i5 | 2;
+  HEAPF32[i3 + 144 >> 2] = 0.0;
+ }
+ i13 = i1 + 64 | 0;
+ HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN12b2BroadPhase11UpdatePairsI16b2ContactManagerEEvPT_(i5, i2) {
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i6 = i3;
+ i1 = i5 + 52 | 0;
+ HEAP32[i1 >> 2] = 0;
+ i4 = i5 + 40 | 0;
+ i12 = HEAP32[i4 >> 2] | 0;
+ do {
+  if ((i12 | 0) > 0) {
+   i9 = i5 + 32 | 0;
+   i11 = i5 + 56 | 0;
+   i8 = i5 + 12 | 0;
+   i10 = i5 + 4 | 0;
+   i13 = 0;
+   while (1) {
+    i14 = HEAP32[(HEAP32[i9 >> 2] | 0) + (i13 << 2) >> 2] | 0;
+    HEAP32[i11 >> 2] = i14;
+    if (!((i14 | 0) == -1)) {
+     if (!((i14 | 0) > -1)) {
+      i8 = 6;
+      break;
+     }
+     if ((HEAP32[i8 >> 2] | 0) <= (i14 | 0)) {
+      i8 = 6;
+      break;
+     }
+     __ZNK13b2DynamicTree5QueryI12b2BroadPhaseEEvPT_RK6b2AABB(i5, i5, (HEAP32[i10 >> 2] | 0) + (i14 * 36 | 0) | 0);
+     i12 = HEAP32[i4 >> 2] | 0;
+    }
+    i13 = i13 + 1 | 0;
+    if ((i13 | 0) >= (i12 | 0)) {
+     i8 = 9;
+     break;
+    }
+   }
+   if ((i8 | 0) == 6) {
+    ___assert_fail(1904, 1952, 159, 2008);
+   } else if ((i8 | 0) == 9) {
+    i7 = HEAP32[i1 >> 2] | 0;
+    break;
+   }
+  } else {
+   i7 = 0;
+  }
+ } while (0);
+ HEAP32[i4 >> 2] = 0;
+ i4 = i5 + 44 | 0;
+ i14 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i6 >> 2] = 3;
+ __ZNSt3__16__sortIRPFbRK6b2PairS3_EPS1_EEvT0_S8_T_(i14, i14 + (i7 * 12 | 0) | 0, i6);
+ if ((HEAP32[i1 >> 2] | 0) <= 0) {
+  STACKTOP = i3;
+  return;
+ }
+ i6 = i5 + 12 | 0;
+ i7 = i5 + 4 | 0;
+ i9 = 0;
+ L18 : while (1) {
+  i8 = HEAP32[i4 >> 2] | 0;
+  i5 = i8 + (i9 * 12 | 0) | 0;
+  i10 = HEAP32[i5 >> 2] | 0;
+  if (!((i10 | 0) > -1)) {
+   i8 = 14;
+   break;
+  }
+  i12 = HEAP32[i6 >> 2] | 0;
+  if ((i12 | 0) <= (i10 | 0)) {
+   i8 = 14;
+   break;
+  }
+  i11 = HEAP32[i7 >> 2] | 0;
+  i8 = i8 + (i9 * 12 | 0) + 4 | 0;
+  i13 = HEAP32[i8 >> 2] | 0;
+  if (!((i13 | 0) > -1 & (i12 | 0) > (i13 | 0))) {
+   i8 = 16;
+   break;
+  }
+  __ZN16b2ContactManager7AddPairEPvS0_(i2, HEAP32[i11 + (i10 * 36 | 0) + 16 >> 2] | 0, HEAP32[i11 + (i13 * 36 | 0) + 16 >> 2] | 0);
+  i10 = HEAP32[i1 >> 2] | 0;
+  while (1) {
+   i9 = i9 + 1 | 0;
+   if ((i9 | 0) >= (i10 | 0)) {
+    i8 = 21;
+    break L18;
+   }
+   i11 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i11 + (i9 * 12 | 0) >> 2] | 0) != (HEAP32[i5 >> 2] | 0)) {
+    continue L18;
+   }
+   if ((HEAP32[i11 + (i9 * 12 | 0) + 4 >> 2] | 0) != (HEAP32[i8 >> 2] | 0)) {
+    continue L18;
+   }
+  }
+ }
+ if ((i8 | 0) == 14) {
+  ___assert_fail(1904, 1952, 153, 1992);
+ } else if ((i8 | 0) == 16) {
+  ___assert_fail(1904, 1952, 153, 1992);
+ } else if ((i8 | 0) == 21) {
+  STACKTOP = i3;
+  return;
+ }
+}
+function __ZNK13b2DynamicTree5QueryI12b2BroadPhaseEEvPT_RK6b2AABB(i9, i4, i7) {
+ i9 = i9 | 0;
+ i4 = i4 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1040 | 0;
+ i3 = i2;
+ i1 = i3 + 4 | 0;
+ HEAP32[i3 >> 2] = i1;
+ i5 = i3 + 1028 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i6 = i3 + 1032 | 0;
+ HEAP32[i6 >> 2] = 256;
+ i14 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i14 + (HEAP32[i5 >> 2] << 2) >> 2] = HEAP32[i9 >> 2];
+ i15 = HEAP32[i5 >> 2] | 0;
+ i16 = i15 + 1 | 0;
+ HEAP32[i5 >> 2] = i16;
+ L1 : do {
+  if ((i15 | 0) > -1) {
+   i9 = i9 + 4 | 0;
+   i11 = i7 + 4 | 0;
+   i12 = i7 + 8 | 0;
+   i10 = i7 + 12 | 0;
+   while (1) {
+    i16 = i16 + -1 | 0;
+    HEAP32[i5 >> 2] = i16;
+    i13 = HEAP32[i14 + (i16 << 2) >> 2] | 0;
+    do {
+     if (!((i13 | 0) == -1) ? (i8 = HEAP32[i9 >> 2] | 0, !(+HEAPF32[i7 >> 2] - +HEAPF32[i8 + (i13 * 36 | 0) + 8 >> 2] > 0.0 | +HEAPF32[i11 >> 2] - +HEAPF32[i8 + (i13 * 36 | 0) + 12 >> 2] > 0.0 | +HEAPF32[i8 + (i13 * 36 | 0) >> 2] - +HEAPF32[i12 >> 2] > 0.0 | +HEAPF32[i8 + (i13 * 36 | 0) + 4 >> 2] - +HEAPF32[i10 >> 2] > 0.0)) : 0) {
+      i15 = i8 + (i13 * 36 | 0) + 24 | 0;
+      if ((HEAP32[i15 >> 2] | 0) == -1) {
+       if (!(__ZN12b2BroadPhase13QueryCallbackEi(i4, i13) | 0)) {
+        break L1;
+       }
+       i16 = HEAP32[i5 >> 2] | 0;
+       break;
+      }
+      if ((i16 | 0) == (HEAP32[i6 >> 2] | 0) ? (HEAP32[i6 >> 2] = i16 << 1, i16 = __Z7b2Alloci(i16 << 3) | 0, HEAP32[i3 >> 2] = i16, _memcpy(i16 | 0, i14 | 0, HEAP32[i5 >> 2] << 2 | 0) | 0, (i14 | 0) != (i1 | 0)) : 0) {
+       __Z6b2FreePv(i14);
+      }
+      i14 = HEAP32[i3 >> 2] | 0;
+      HEAP32[i14 + (HEAP32[i5 >> 2] << 2) >> 2] = HEAP32[i15 >> 2];
+      i15 = (HEAP32[i5 >> 2] | 0) + 1 | 0;
+      HEAP32[i5 >> 2] = i15;
+      i13 = i8 + (i13 * 36 | 0) + 28 | 0;
+      if ((i15 | 0) == (HEAP32[i6 >> 2] | 0) ? (HEAP32[i6 >> 2] = i15 << 1, i16 = __Z7b2Alloci(i15 << 3) | 0, HEAP32[i3 >> 2] = i16, _memcpy(i16 | 0, i14 | 0, HEAP32[i5 >> 2] << 2 | 0) | 0, (i14 | 0) != (i1 | 0)) : 0) {
+       __Z6b2FreePv(i14);
+      }
+      HEAP32[(HEAP32[i3 >> 2] | 0) + (HEAP32[i5 >> 2] << 2) >> 2] = HEAP32[i13 >> 2];
+      i16 = (HEAP32[i5 >> 2] | 0) + 1 | 0;
+      HEAP32[i5 >> 2] = i16;
+     }
+    } while (0);
+    if ((i16 | 0) <= 0) {
+     break L1;
+    }
+    i14 = HEAP32[i3 >> 2] | 0;
+   }
+  }
+ } while (0);
+ i4 = HEAP32[i3 >> 2] | 0;
+ if ((i4 | 0) == (i1 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ __Z6b2FreePv(i4);
+ HEAP32[i3 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZN15b2ContactSolver9WarmStartEv(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, d10 = 0.0, d11 = 0.0, d12 = 0.0, i13 = 0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0, d21 = 0.0, i22 = 0, d23 = 0.0, i24 = 0, d25 = 0.0, d26 = 0.0, d27 = 0.0;
+ i1 = STACKTOP;
+ i2 = i4 + 48 | 0;
+ if ((HEAP32[i2 >> 2] | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i4 + 40 | 0;
+ i5 = i4 + 28 | 0;
+ i22 = HEAP32[i5 >> 2] | 0;
+ i8 = 0;
+ do {
+  i9 = HEAP32[i3 >> 2] | 0;
+  i7 = HEAP32[i9 + (i8 * 152 | 0) + 112 >> 2] | 0;
+  i6 = HEAP32[i9 + (i8 * 152 | 0) + 116 >> 2] | 0;
+  d10 = +HEAPF32[i9 + (i8 * 152 | 0) + 120 >> 2];
+  d14 = +HEAPF32[i9 + (i8 * 152 | 0) + 128 >> 2];
+  d12 = +HEAPF32[i9 + (i8 * 152 | 0) + 124 >> 2];
+  d11 = +HEAPF32[i9 + (i8 * 152 | 0) + 132 >> 2];
+  i13 = HEAP32[i9 + (i8 * 152 | 0) + 144 >> 2] | 0;
+  i4 = i22 + (i7 * 12 | 0) | 0;
+  i24 = i4;
+  d17 = +HEAPF32[i24 >> 2];
+  d19 = +HEAPF32[i24 + 4 >> 2];
+  d20 = +HEAPF32[i22 + (i7 * 12 | 0) + 8 >> 2];
+  i24 = i22 + (i6 * 12 | 0) | 0;
+  d21 = +HEAPF32[i24 >> 2];
+  d23 = +HEAPF32[i24 + 4 >> 2];
+  d18 = +HEAPF32[i22 + (i6 * 12 | 0) + 8 >> 2];
+  i22 = i9 + (i8 * 152 | 0) + 72 | 0;
+  d15 = +HEAPF32[i22 >> 2];
+  d16 = +HEAPF32[i22 + 4 >> 2];
+  if ((i13 | 0) > 0) {
+   i22 = 0;
+   do {
+    d27 = +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 16 >> 2];
+    d25 = +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 20 >> 2];
+    d26 = d15 * d27 + d16 * d25;
+    d25 = d16 * d27 - d15 * d25;
+    d20 = d20 - d14 * (+HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) >> 2] * d25 - +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 4 >> 2] * d26);
+    d17 = d17 - d10 * d26;
+    d19 = d19 - d10 * d25;
+    d18 = d18 + d11 * (d25 * +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 8 >> 2] - d26 * +HEAPF32[i9 + (i8 * 152 | 0) + (i22 * 36 | 0) + 12 >> 2]);
+    d21 = d21 + d12 * d26;
+    d23 = d23 + d12 * d25;
+    i22 = i22 + 1 | 0;
+   } while ((i22 | 0) != (i13 | 0));
+  }
+  d27 = +d17;
+  d26 = +d19;
+  i22 = i4;
+  HEAPF32[i22 >> 2] = d27;
+  HEAPF32[i22 + 4 >> 2] = d26;
+  i22 = HEAP32[i5 >> 2] | 0;
+  HEAPF32[i22 + (i7 * 12 | 0) + 8 >> 2] = d20;
+  d26 = +d21;
+  d27 = +d23;
+  i22 = i22 + (i6 * 12 | 0) | 0;
+  HEAPF32[i22 >> 2] = d26;
+  HEAPF32[i22 + 4 >> 2] = d27;
+  i22 = HEAP32[i5 >> 2] | 0;
+  HEAPF32[i22 + (i6 * 12 | 0) + 8 >> 2] = d18;
+  i8 = i8 + 1 | 0;
+ } while ((i8 | 0) < (HEAP32[i2 >> 2] | 0));
+ STACKTOP = i1;
+ return;
+}
+function __ZNK14b2PolygonShape7RayCastEP15b2RayCastOutputRK14b2RayCastInputRK11b2Transformi(i1, i5, i8, i7, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, d3 = 0.0, i6 = 0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, i14 = 0, i15 = 0, i16 = 0, d17 = 0.0, d18 = 0.0, d19 = 0.0, d20 = 0.0;
+ i4 = STACKTOP;
+ d10 = +HEAPF32[i7 >> 2];
+ d9 = +HEAPF32[i8 >> 2] - d10;
+ d18 = +HEAPF32[i7 + 4 >> 2];
+ d11 = +HEAPF32[i8 + 4 >> 2] - d18;
+ i6 = i7 + 12 | 0;
+ d17 = +HEAPF32[i6 >> 2];
+ i7 = i7 + 8 | 0;
+ d19 = +HEAPF32[i7 >> 2];
+ d12 = d9 * d17 + d11 * d19;
+ d9 = d17 * d11 - d9 * d19;
+ d10 = +HEAPF32[i8 + 8 >> 2] - d10;
+ d18 = +HEAPF32[i8 + 12 >> 2] - d18;
+ d11 = d17 * d10 + d19 * d18 - d12;
+ d10 = d17 * d18 - d19 * d10 - d9;
+ i8 = i8 + 16 | 0;
+ i14 = HEAP32[i1 + 148 >> 2] | 0;
+ do {
+  if ((i14 | 0) > 0) {
+   i16 = 0;
+   i15 = -1;
+   d13 = 0.0;
+   d17 = +HEAPF32[i8 >> 2];
+   L3 : while (1) {
+    d20 = +HEAPF32[i1 + (i16 << 3) + 84 >> 2];
+    d19 = +HEAPF32[i1 + (i16 << 3) + 88 >> 2];
+    d18 = (+HEAPF32[i1 + (i16 << 3) + 20 >> 2] - d12) * d20 + (+HEAPF32[i1 + (i16 << 3) + 24 >> 2] - d9) * d19;
+    d19 = d11 * d20 + d10 * d19;
+    do {
+     if (d19 == 0.0) {
+      if (d18 < 0.0) {
+       i1 = 0;
+       i14 = 18;
+       break L3;
+      }
+     } else {
+      if (d19 < 0.0 ? d18 < d13 * d19 : 0) {
+       i15 = i16;
+       d13 = d18 / d19;
+       break;
+      }
+      if (d19 > 0.0 ? d18 < d17 * d19 : 0) {
+       d17 = d18 / d19;
+      }
+     }
+    } while (0);
+    i16 = i16 + 1 | 0;
+    if (d17 < d13) {
+     i1 = 0;
+     i14 = 18;
+     break;
+    }
+    if ((i16 | 0) >= (i14 | 0)) {
+     i14 = 13;
+     break;
+    }
+   }
+   if ((i14 | 0) == 13) {
+    if (d13 >= 0.0) {
+     i2 = i15;
+     d3 = d13;
+     break;
+    }
+    ___assert_fail(376, 328, 249, 424);
+   } else if ((i14 | 0) == 18) {
+    STACKTOP = i4;
+    return i1 | 0;
+   }
+  } else {
+   i2 = -1;
+   d3 = 0.0;
+  }
+ } while (0);
+ if (!(d3 <= +HEAPF32[i8 >> 2])) {
+  ___assert_fail(376, 328, 249, 424);
+ }
+ if (!((i2 | 0) > -1)) {
+  i16 = 0;
+  STACKTOP = i4;
+  return i16 | 0;
+ }
+ HEAPF32[i5 + 8 >> 2] = d3;
+ d18 = +HEAPF32[i6 >> 2];
+ d13 = +HEAPF32[i1 + (i2 << 3) + 84 >> 2];
+ d17 = +HEAPF32[i7 >> 2];
+ d20 = +HEAPF32[i1 + (i2 << 3) + 88 >> 2];
+ d19 = +(d18 * d13 - d17 * d20);
+ d20 = +(d13 * d17 + d18 * d20);
+ i16 = i5;
+ HEAPF32[i16 >> 2] = d19;
+ HEAPF32[i16 + 4 >> 2] = d20;
+ i16 = 1;
+ STACKTOP = i4;
+ return i16 | 0;
+}
+function __ZN7b2World4StepEfii(i1, d9, i11, i12) {
+ i1 = i1 | 0;
+ d9 = +d9;
+ i11 = i11 | 0;
+ i12 = i12 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i13 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i4 + 27 | 0;
+ i5 = i4;
+ i8 = i4 + 26 | 0;
+ i10 = i4 + 25 | 0;
+ i7 = i4 + 24 | 0;
+ __ZN7b2TimerC2Ev(i3);
+ i2 = i1 + 102868 | 0;
+ i13 = HEAP32[i2 >> 2] | 0;
+ if ((i13 & 1 | 0) != 0) {
+  __ZN16b2ContactManager15FindNewContactsEv(i1 + 102872 | 0);
+  i13 = HEAP32[i2 >> 2] & -2;
+  HEAP32[i2 >> 2] = i13;
+ }
+ HEAP32[i2 >> 2] = i13 | 2;
+ HEAPF32[i5 >> 2] = d9;
+ HEAP32[i5 + 12 >> 2] = i11;
+ HEAP32[i5 + 16 >> 2] = i12;
+ if (d9 > 0.0) {
+  HEAPF32[i5 + 4 >> 2] = 1.0 / d9;
+ } else {
+  HEAPF32[i5 + 4 >> 2] = 0.0;
+ }
+ i11 = i1 + 102988 | 0;
+ HEAPF32[i5 + 8 >> 2] = +HEAPF32[i11 >> 2] * d9;
+ HEAP8[i5 + 20 | 0] = HEAP8[i1 + 102992 | 0] | 0;
+ __ZN7b2TimerC2Ev(i8);
+ __ZN16b2ContactManager7CollideEv(i1 + 102872 | 0);
+ HEAPF32[i1 + 103e3 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i8);
+ if ((HEAP8[i1 + 102995 | 0] | 0) != 0 ? +HEAPF32[i5 >> 2] > 0.0 : 0) {
+  __ZN7b2TimerC2Ev(i10);
+  __ZN7b2World5SolveERK10b2TimeStep(i1, i5);
+  HEAPF32[i1 + 103004 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i10);
+ }
+ if ((HEAP8[i1 + 102993 | 0] | 0) != 0) {
+  d9 = +HEAPF32[i5 >> 2];
+  if (d9 > 0.0) {
+   __ZN7b2TimerC2Ev(i7);
+   __ZN7b2World8SolveTOIERK10b2TimeStep(i1, i5);
+   HEAPF32[i1 + 103024 >> 2] = +__ZNK7b2Timer15GetMillisecondsEv(i7);
+   i6 = 12;
+  }
+ } else {
+  i6 = 12;
+ }
+ if ((i6 | 0) == 12) {
+  d9 = +HEAPF32[i5 >> 2];
+ }
+ if (d9 > 0.0) {
+  HEAPF32[i11 >> 2] = +HEAPF32[i5 + 4 >> 2];
+ }
+ i5 = HEAP32[i2 >> 2] | 0;
+ if ((i5 & 4 | 0) == 0) {
+  i13 = i5 & -3;
+  HEAP32[i2 >> 2] = i13;
+  d9 = +__ZNK7b2Timer15GetMillisecondsEv(i3);
+  i13 = i1 + 102996 | 0;
+  HEAPF32[i13 >> 2] = d9;
+  STACKTOP = i4;
+  return;
+ }
+ i6 = HEAP32[i1 + 102952 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  i13 = i5 & -3;
+  HEAP32[i2 >> 2] = i13;
+  d9 = +__ZNK7b2Timer15GetMillisecondsEv(i3);
+  i13 = i1 + 102996 | 0;
+  HEAPF32[i13 >> 2] = d9;
+  STACKTOP = i4;
+  return;
+ }
+ do {
+  HEAPF32[i6 + 76 >> 2] = 0.0;
+  HEAPF32[i6 + 80 >> 2] = 0.0;
+  HEAPF32[i6 + 84 >> 2] = 0.0;
+  i6 = HEAP32[i6 + 96 >> 2] | 0;
+ } while ((i6 | 0) != 0);
+ i13 = i5 & -3;
+ HEAP32[i2 >> 2] = i13;
+ d9 = +__ZNK7b2Timer15GetMillisecondsEv(i3);
+ i13 = i1 + 102996 | 0;
+ HEAPF32[i13 >> 2] = d9;
+ STACKTOP = i4;
+ return;
+}
+function __ZL19b2FindMaxSeparationPiPK14b2PolygonShapeRK11b2TransformS2_S5_(i1, i5, i6, i3, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i7 = 0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i12 = 0, i13 = 0, i14 = 0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0;
+ i2 = STACKTOP;
+ i7 = HEAP32[i5 + 148 >> 2] | 0;
+ d17 = +HEAPF32[i4 + 12 >> 2];
+ d19 = +HEAPF32[i3 + 12 >> 2];
+ d18 = +HEAPF32[i4 + 8 >> 2];
+ d16 = +HEAPF32[i3 + 16 >> 2];
+ d15 = +HEAPF32[i6 + 12 >> 2];
+ d10 = +HEAPF32[i5 + 12 >> 2];
+ d8 = +HEAPF32[i6 + 8 >> 2];
+ d9 = +HEAPF32[i5 + 16 >> 2];
+ d11 = +HEAPF32[i4 >> 2] + (d17 * d19 - d18 * d16) - (+HEAPF32[i6 >> 2] + (d15 * d10 - d8 * d9));
+ d9 = d19 * d18 + d17 * d16 + +HEAPF32[i4 + 4 >> 2] - (d10 * d8 + d15 * d9 + +HEAPF32[i6 + 4 >> 2]);
+ d10 = d15 * d11 + d8 * d9;
+ d8 = d15 * d9 - d11 * d8;
+ if ((i7 | 0) > 0) {
+  i14 = 0;
+  i13 = 0;
+  d9 = -3.4028234663852886e+38;
+  while (1) {
+   d11 = d10 * +HEAPF32[i5 + (i13 << 3) + 84 >> 2] + d8 * +HEAPF32[i5 + (i13 << 3) + 88 >> 2];
+   i12 = d11 > d9;
+   i14 = i12 ? i13 : i14;
+   i13 = i13 + 1 | 0;
+   if ((i13 | 0) == (i7 | 0)) {
+    break;
+   } else {
+    d9 = i12 ? d11 : d9;
+   }
+  }
+ } else {
+  i14 = 0;
+ }
+ d9 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i14, i3, i4);
+ i12 = ((i14 | 0) > 0 ? i14 : i7) + -1 | 0;
+ d8 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i12, i3, i4);
+ i13 = i14 + 1 | 0;
+ i13 = (i13 | 0) < (i7 | 0) ? i13 : 0;
+ d10 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i13, i3, i4);
+ if (d8 > d9 & d8 > d10) {
+  while (1) {
+   i13 = ((i12 | 0) > 0 ? i12 : i7) + -1 | 0;
+   d9 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i13, i3, i4);
+   if (d9 > d8) {
+    i12 = i13;
+    d8 = d9;
+   } else {
+    break;
+   }
+  }
+  HEAP32[i1 >> 2] = i12;
+  STACKTOP = i2;
+  return +d8;
+ }
+ if (d10 > d9) {
+  i12 = i13;
+  d8 = d10;
+ } else {
+  d19 = d9;
+  HEAP32[i1 >> 2] = i14;
+  STACKTOP = i2;
+  return +d19;
+ }
+ while (1) {
+  i13 = i12 + 1 | 0;
+  i13 = (i13 | 0) < (i7 | 0) ? i13 : 0;
+  d9 = +__ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i5, i6, i13, i3, i4);
+  if (d9 > d8) {
+   i12 = i13;
+   d8 = d9;
+  } else {
+   break;
+  }
+ }
+ HEAP32[i1 >> 2] = i12;
+ STACKTOP = i2;
+ return +d8;
+}
+function __ZN9b2Fixture11SynchronizeEP12b2BroadPhaseRK11b2TransformS4_(i10, i8, i7, i2) {
+ i10 = i10 | 0;
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0, i27 = 0;
+ i9 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i5 = i9 + 24 | 0;
+ i6 = i9 + 8 | 0;
+ i3 = i9;
+ i4 = i10 + 28 | 0;
+ if ((HEAP32[i4 >> 2] | 0) <= 0) {
+  STACKTOP = i9;
+  return;
+ }
+ i1 = i10 + 24 | 0;
+ i18 = i10 + 12 | 0;
+ i19 = i5 + 4 | 0;
+ i20 = i6 + 4 | 0;
+ i13 = i5 + 8 | 0;
+ i14 = i6 + 8 | 0;
+ i15 = i5 + 12 | 0;
+ i16 = i6 + 12 | 0;
+ i11 = i2 + 4 | 0;
+ i22 = i7 + 4 | 0;
+ i12 = i3 + 4 | 0;
+ i21 = 0;
+ do {
+  i10 = HEAP32[i1 >> 2] | 0;
+  i27 = HEAP32[i18 >> 2] | 0;
+  i17 = i10 + (i21 * 28 | 0) + 20 | 0;
+  FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i27 >> 2] | 0) + 24 >> 2] & 15](i27, i5, i7, HEAP32[i17 >> 2] | 0);
+  i27 = HEAP32[i18 >> 2] | 0;
+  FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i27 >> 2] | 0) + 24 >> 2] & 15](i27, i6, i2, HEAP32[i17 >> 2] | 0);
+  i17 = i10 + (i21 * 28 | 0) | 0;
+  d25 = +HEAPF32[i5 >> 2];
+  d26 = +HEAPF32[i6 >> 2];
+  d24 = +HEAPF32[i19 >> 2];
+  d23 = +HEAPF32[i20 >> 2];
+  d25 = +(d25 < d26 ? d25 : d26);
+  d26 = +(d24 < d23 ? d24 : d23);
+  i27 = i17;
+  HEAPF32[i27 >> 2] = d25;
+  HEAPF32[i27 + 4 >> 2] = d26;
+  d25 = +HEAPF32[i13 >> 2];
+  d26 = +HEAPF32[i14 >> 2];
+  d23 = +HEAPF32[i15 >> 2];
+  d24 = +HEAPF32[i16 >> 2];
+  d25 = +(d25 > d26 ? d25 : d26);
+  d26 = +(d23 > d24 ? d23 : d24);
+  i27 = i10 + (i21 * 28 | 0) + 8 | 0;
+  HEAPF32[i27 >> 2] = d25;
+  HEAPF32[i27 + 4 >> 2] = d26;
+  d26 = +HEAPF32[i11 >> 2] - +HEAPF32[i22 >> 2];
+  HEAPF32[i3 >> 2] = +HEAPF32[i2 >> 2] - +HEAPF32[i7 >> 2];
+  HEAPF32[i12 >> 2] = d26;
+  __ZN12b2BroadPhase9MoveProxyEiRK6b2AABBRK6b2Vec2(i8, HEAP32[i10 + (i21 * 28 | 0) + 24 >> 2] | 0, i17, i3);
+  i21 = i21 + 1 | 0;
+ } while ((i21 | 0) < (HEAP32[i4 >> 2] | 0));
+ STACKTOP = i9;
+ return;
+}
+function __ZN12b2EPCollider24ComputePolygonSeparationEv(i2, i9) {
+ i2 = i2 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = 0.0, d7 = 0.0, i8 = 0, d10 = 0.0, d11 = 0.0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, d16 = 0.0, d17 = 0.0, d18 = 0.0, d19 = 0.0, i20 = 0, d21 = 0.0, d22 = 0.0, d23 = 0.0, d24 = 0.0, d25 = 0.0, d26 = 0.0;
+ i15 = STACKTOP;
+ HEAP32[i2 >> 2] = 0;
+ i3 = i2 + 4 | 0;
+ HEAP32[i3 >> 2] = -1;
+ i4 = i2 + 8 | 0;
+ HEAPF32[i4 >> 2] = -3.4028234663852886e+38;
+ d7 = +HEAPF32[i9 + 216 >> 2];
+ d6 = +HEAPF32[i9 + 212 >> 2];
+ i5 = HEAP32[i9 + 128 >> 2] | 0;
+ if ((i5 | 0) <= 0) {
+  STACKTOP = i15;
+  return;
+ }
+ d17 = +HEAPF32[i9 + 164 >> 2];
+ d18 = +HEAPF32[i9 + 168 >> 2];
+ d11 = +HEAPF32[i9 + 172 >> 2];
+ d10 = +HEAPF32[i9 + 176 >> 2];
+ d16 = +HEAPF32[i9 + 244 >> 2];
+ i12 = i9 + 228 | 0;
+ i13 = i9 + 232 | 0;
+ i14 = i9 + 236 | 0;
+ i1 = i9 + 240 | 0;
+ d19 = -3.4028234663852886e+38;
+ i20 = 0;
+ while (1) {
+  d23 = +HEAPF32[i9 + (i20 << 3) + 64 >> 2];
+  d21 = -d23;
+  d22 = -+HEAPF32[i9 + (i20 << 3) + 68 >> 2];
+  d26 = +HEAPF32[i9 + (i20 << 3) >> 2];
+  d25 = +HEAPF32[i9 + (i20 << 3) + 4 >> 2];
+  d24 = (d26 - d17) * d21 + (d25 - d18) * d22;
+  d25 = (d26 - d11) * d21 + (d25 - d10) * d22;
+  d24 = d24 < d25 ? d24 : d25;
+  if (d24 > d16) {
+   break;
+  }
+  if (!(d7 * d23 + d6 * d22 >= 0.0)) {
+   if (!((d21 - +HEAPF32[i12 >> 2]) * d6 + (d22 - +HEAPF32[i13 >> 2]) * d7 < -.03490658849477768) & d24 > d19) {
+    i8 = 8;
+   }
+  } else {
+   if (!((d21 - +HEAPF32[i14 >> 2]) * d6 + (d22 - +HEAPF32[i1 >> 2]) * d7 < -.03490658849477768) & d24 > d19) {
+    i8 = 8;
+   }
+  }
+  if ((i8 | 0) == 8) {
+   i8 = 0;
+   HEAP32[i2 >> 2] = 2;
+   HEAP32[i3 >> 2] = i20;
+   HEAPF32[i4 >> 2] = d24;
+   d19 = d24;
+  }
+  i20 = i20 + 1 | 0;
+  if ((i20 | 0) >= (i5 | 0)) {
+   i8 = 10;
+   break;
+  }
+ }
+ if ((i8 | 0) == 10) {
+  STACKTOP = i15;
+  return;
+ }
+ HEAP32[i2 >> 2] = 2;
+ HEAP32[i3 >> 2] = i20;
+ HEAPF32[i4 >> 2] = d24;
+ STACKTOP = i15;
+ return;
+}
+function __ZNK11b2EdgeShape7RayCastEP15b2RayCastOutputRK14b2RayCastInputRK11b2Transformi(i17, i1, i2, i18, i3) {
+ i17 = i17 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i18 = i18 | 0;
+ i3 = i3 | 0;
+ var d4 = 0.0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0;
+ i3 = STACKTOP;
+ d6 = +HEAPF32[i18 >> 2];
+ d7 = +HEAPF32[i2 >> 2] - d6;
+ d9 = +HEAPF32[i18 + 4 >> 2];
+ d4 = +HEAPF32[i2 + 4 >> 2] - d9;
+ d11 = +HEAPF32[i18 + 12 >> 2];
+ d5 = +HEAPF32[i18 + 8 >> 2];
+ d8 = d7 * d11 + d4 * d5;
+ d7 = d11 * d4 - d7 * d5;
+ d6 = +HEAPF32[i2 + 8 >> 2] - d6;
+ d9 = +HEAPF32[i2 + 12 >> 2] - d9;
+ d4 = d11 * d6 + d5 * d9 - d8;
+ d6 = d11 * d9 - d5 * d6 - d7;
+ i18 = i17 + 12 | 0;
+ d5 = +HEAPF32[i18 >> 2];
+ d9 = +HEAPF32[i18 + 4 >> 2];
+ i18 = i17 + 20 | 0;
+ d11 = +HEAPF32[i18 >> 2];
+ d11 = d11 - d5;
+ d12 = +HEAPF32[i18 + 4 >> 2] - d9;
+ d15 = -d11;
+ d10 = d11 * d11 + d12 * d12;
+ d13 = +Math_sqrt(+d10);
+ if (d13 < 1.1920928955078125e-7) {
+  d13 = d12;
+ } else {
+  d16 = 1.0 / d13;
+  d13 = d12 * d16;
+  d15 = d16 * d15;
+ }
+ d14 = (d9 - d7) * d15 + (d5 - d8) * d13;
+ d16 = d6 * d15 + d4 * d13;
+ if (d16 == 0.0) {
+  i18 = 0;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ d16 = d14 / d16;
+ if (d16 < 0.0) {
+  i18 = 0;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ if (+HEAPF32[i2 + 16 >> 2] < d16 | d10 == 0.0) {
+  i18 = 0;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ d12 = (d11 * (d8 + d4 * d16 - d5) + d12 * (d7 + d6 * d16 - d9)) / d10;
+ if (d12 < 0.0 | d12 > 1.0) {
+  i18 = 0;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ HEAPF32[i1 + 8 >> 2] = d16;
+ if (d14 > 0.0) {
+  d14 = +-d13;
+  d16 = +-d15;
+  i18 = i1;
+  HEAPF32[i18 >> 2] = d14;
+  HEAPF32[i18 + 4 >> 2] = d16;
+  i18 = 1;
+  STACKTOP = i3;
+  return i18 | 0;
+ } else {
+  d14 = +d13;
+  d16 = +d15;
+  i18 = i1;
+  HEAPF32[i18 >> 2] = d14;
+  HEAPF32[i18 + 4 >> 2] = d16;
+  i18 = 1;
+  STACKTOP = i3;
+  return i18 | 0;
+ }
+ return 0;
+}
+function ___dynamic_cast(i7, i6, i11, i5) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i11 = i11 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i2 = i1;
+ i3 = HEAP32[i7 >> 2] | 0;
+ i4 = i7 + (HEAP32[i3 + -8 >> 2] | 0) | 0;
+ i3 = HEAP32[i3 + -4 >> 2] | 0;
+ HEAP32[i2 >> 2] = i11;
+ HEAP32[i2 + 4 >> 2] = i7;
+ HEAP32[i2 + 8 >> 2] = i6;
+ HEAP32[i2 + 12 >> 2] = i5;
+ i9 = i2 + 16 | 0;
+ i10 = i2 + 20 | 0;
+ i6 = i2 + 24 | 0;
+ i8 = i2 + 28 | 0;
+ i5 = i2 + 32 | 0;
+ i7 = i2 + 40 | 0;
+ i12 = (i3 | 0) == (i11 | 0);
+ i13 = i9 + 0 | 0;
+ i11 = i13 + 36 | 0;
+ do {
+  HEAP32[i13 >> 2] = 0;
+  i13 = i13 + 4 | 0;
+ } while ((i13 | 0) < (i11 | 0));
+ HEAP16[i9 + 36 >> 1] = 0;
+ HEAP8[i9 + 38 | 0] = 0;
+ if (i12) {
+  HEAP32[i2 + 48 >> 2] = 1;
+  FUNCTION_TABLE_viiiiii[HEAP32[(HEAP32[i3 >> 2] | 0) + 20 >> 2] & 3](i3, i2, i4, i4, 1, 0);
+  i13 = (HEAP32[i6 >> 2] | 0) == 1 ? i4 : 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ FUNCTION_TABLE_viiiii[HEAP32[(HEAP32[i3 >> 2] | 0) + 24 >> 2] & 3](i3, i2, i4, 1, 0);
+ i2 = HEAP32[i2 + 36 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  if ((HEAP32[i7 >> 2] | 0) != 1) {
+   i13 = 0;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+  if ((HEAP32[i8 >> 2] | 0) != 1) {
+   i13 = 0;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+  i13 = (HEAP32[i5 >> 2] | 0) == 1 ? HEAP32[i10 >> 2] | 0 : 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else if ((i2 | 0) == 1) {
+  if ((HEAP32[i6 >> 2] | 0) != 1) {
+   if ((HEAP32[i7 >> 2] | 0) != 0) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+   if ((HEAP32[i8 >> 2] | 0) != 1) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+   if ((HEAP32[i5 >> 2] | 0) != 1) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+  i13 = HEAP32[i9 >> 2] | 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else {
+  i13 = 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ return 0;
+}
+function __ZNK14b2PolygonShape11ComputeMassEP10b2MassDataf(i4, i1, d2) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ d2 = +d2;
+ var i3 = 0, i5 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i12 = 0, d13 = 0.0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, d18 = 0.0, i19 = 0, d20 = 0.0, d21 = 0.0, d22 = 0.0, d23 = 0.0;
+ i3 = STACKTOP;
+ i5 = HEAP32[i4 + 148 >> 2] | 0;
+ if ((i5 | 0) > 2) {
+  d7 = 0.0;
+  d6 = 0.0;
+  i12 = 0;
+ } else {
+  ___assert_fail(432, 328, 306, 456);
+ }
+ do {
+  d6 = d6 + +HEAPF32[i4 + (i12 << 3) + 20 >> 2];
+  d7 = d7 + +HEAPF32[i4 + (i12 << 3) + 24 >> 2];
+  i12 = i12 + 1 | 0;
+ } while ((i12 | 0) < (i5 | 0));
+ d11 = 1.0 / +(i5 | 0);
+ d6 = d6 * d11;
+ d11 = d7 * d11;
+ i16 = i4 + 20 | 0;
+ i19 = i4 + 24 | 0;
+ d9 = 0.0;
+ d10 = 0.0;
+ d7 = 0.0;
+ d8 = 0.0;
+ i17 = 0;
+ do {
+  d18 = +HEAPF32[i4 + (i17 << 3) + 20 >> 2] - d6;
+  d13 = +HEAPF32[i4 + (i17 << 3) + 24 >> 2] - d11;
+  i17 = i17 + 1 | 0;
+  i12 = (i17 | 0) < (i5 | 0);
+  if (i12) {
+   i14 = i4 + (i17 << 3) + 20 | 0;
+   i15 = i4 + (i17 << 3) + 24 | 0;
+  } else {
+   i14 = i16;
+   i15 = i19;
+  }
+  d21 = +HEAPF32[i14 >> 2] - d6;
+  d20 = +HEAPF32[i15 >> 2] - d11;
+  d22 = d18 * d20 - d13 * d21;
+  d23 = d22 * .5;
+  d8 = d8 + d23;
+  d23 = d23 * .3333333432674408;
+  d9 = d9 + (d18 + d21) * d23;
+  d10 = d10 + (d13 + d20) * d23;
+  d7 = d7 + d22 * .0833333358168602 * (d21 * d21 + (d18 * d18 + d18 * d21) + (d20 * d20 + (d13 * d13 + d13 * d20)));
+ } while (i12);
+ d13 = d8 * d2;
+ HEAPF32[i1 >> 2] = d13;
+ if (d8 > 1.1920928955078125e-7) {
+  d23 = 1.0 / d8;
+  d22 = d9 * d23;
+  d23 = d10 * d23;
+  d20 = d6 + d22;
+  d21 = d11 + d23;
+  d11 = +d20;
+  d18 = +d21;
+  i19 = i1 + 4 | 0;
+  HEAPF32[i19 >> 2] = d11;
+  HEAPF32[i19 + 4 >> 2] = d18;
+  HEAPF32[i1 + 12 >> 2] = d7 * d2 + d13 * (d20 * d20 + d21 * d21 - (d22 * d22 + d23 * d23));
+  STACKTOP = i3;
+  return;
+ } else {
+  ___assert_fail(472, 328, 352, 456);
+ }
+}
+function __ZN16b2ContactManager7DestroyEP9b2Contact(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ i5 = HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 8 >> 2] | 0;
+ i4 = HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 8 >> 2] | 0;
+ i6 = HEAP32[i1 + 72 >> 2] | 0;
+ if ((i6 | 0) != 0 ? (HEAP32[i2 + 4 >> 2] & 2 | 0) != 0 : 0) {
+  FUNCTION_TABLE_vii[HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] & 15](i6, i2);
+ }
+ i7 = i2 + 8 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ i6 = i2 + 12 | 0;
+ if ((i8 | 0) != 0) {
+  HEAP32[i8 + 12 >> 2] = HEAP32[i6 >> 2];
+ }
+ i8 = HEAP32[i6 >> 2] | 0;
+ if ((i8 | 0) != 0) {
+  HEAP32[i8 + 8 >> 2] = HEAP32[i7 >> 2];
+ }
+ i7 = i1 + 60 | 0;
+ if ((HEAP32[i7 >> 2] | 0) == (i2 | 0)) {
+  HEAP32[i7 >> 2] = HEAP32[i6 >> 2];
+ }
+ i7 = i2 + 24 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ i6 = i2 + 28 | 0;
+ if ((i8 | 0) != 0) {
+  HEAP32[i8 + 12 >> 2] = HEAP32[i6 >> 2];
+ }
+ i8 = HEAP32[i6 >> 2] | 0;
+ if ((i8 | 0) != 0) {
+  HEAP32[i8 + 8 >> 2] = HEAP32[i7 >> 2];
+ }
+ i5 = i5 + 112 | 0;
+ if ((i2 + 16 | 0) == (HEAP32[i5 >> 2] | 0)) {
+  HEAP32[i5 >> 2] = HEAP32[i6 >> 2];
+ }
+ i6 = i2 + 40 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ i5 = i2 + 44 | 0;
+ if ((i7 | 0) != 0) {
+  HEAP32[i7 + 12 >> 2] = HEAP32[i5 >> 2];
+ }
+ i7 = HEAP32[i5 >> 2] | 0;
+ if ((i7 | 0) != 0) {
+  HEAP32[i7 + 8 >> 2] = HEAP32[i6 >> 2];
+ }
+ i4 = i4 + 112 | 0;
+ if ((i2 + 32 | 0) != (HEAP32[i4 >> 2] | 0)) {
+  i8 = i1 + 76 | 0;
+  i8 = HEAP32[i8 >> 2] | 0;
+  __ZN9b2Contact7DestroyEPS_P16b2BlockAllocator(i2, i8);
+  i8 = i1 + 64 | 0;
+  i7 = HEAP32[i8 >> 2] | 0;
+  i7 = i7 + -1 | 0;
+  HEAP32[i8 >> 2] = i7;
+  STACKTOP = i3;
+  return;
+ }
+ HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+ i8 = i1 + 76 | 0;
+ i8 = HEAP32[i8 >> 2] | 0;
+ __ZN9b2Contact7DestroyEPS_P16b2BlockAllocator(i2, i8);
+ i8 = i1 + 64 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ i7 = i7 + -1 | 0;
+ HEAP32[i8 >> 2] = i7;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK10__cxxabiv120__si_class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib(i6, i3, i4, i8, i7) {
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ if ((i6 | 0) == (HEAP32[i3 + 8 >> 2] | 0)) {
+  if ((HEAP32[i3 + 4 >> 2] | 0) != (i4 | 0)) {
+   STACKTOP = i1;
+   return;
+  }
+  i2 = i3 + 28 | 0;
+  if ((HEAP32[i2 >> 2] | 0) == 1) {
+   STACKTOP = i1;
+   return;
+  }
+  HEAP32[i2 >> 2] = i8;
+  STACKTOP = i1;
+  return;
+ }
+ if ((i6 | 0) != (HEAP32[i3 >> 2] | 0)) {
+  i9 = HEAP32[i6 + 8 >> 2] | 0;
+  FUNCTION_TABLE_viiiii[HEAP32[(HEAP32[i9 >> 2] | 0) + 24 >> 2] & 3](i9, i3, i4, i8, i7);
+  STACKTOP = i1;
+  return;
+ }
+ if ((HEAP32[i3 + 16 >> 2] | 0) != (i4 | 0) ? (i5 = i3 + 20 | 0, (HEAP32[i5 >> 2] | 0) != (i4 | 0)) : 0) {
+  HEAP32[i3 + 32 >> 2] = i8;
+  i8 = i3 + 44 | 0;
+  if ((HEAP32[i8 >> 2] | 0) == 4) {
+   STACKTOP = i1;
+   return;
+  }
+  i9 = i3 + 52 | 0;
+  HEAP8[i9] = 0;
+  i10 = i3 + 53 | 0;
+  HEAP8[i10] = 0;
+  i6 = HEAP32[i6 + 8 >> 2] | 0;
+  FUNCTION_TABLE_viiiiii[HEAP32[(HEAP32[i6 >> 2] | 0) + 20 >> 2] & 3](i6, i3, i4, i4, 1, i7);
+  if ((HEAP8[i10] | 0) != 0) {
+   if ((HEAP8[i9] | 0) == 0) {
+    i6 = 1;
+    i2 = 13;
+   }
+  } else {
+   i6 = 0;
+   i2 = 13;
+  }
+  do {
+   if ((i2 | 0) == 13) {
+    HEAP32[i5 >> 2] = i4;
+    i10 = i3 + 40 | 0;
+    HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + 1;
+    if ((HEAP32[i3 + 36 >> 2] | 0) == 1 ? (HEAP32[i3 + 24 >> 2] | 0) == 2 : 0) {
+     HEAP8[i3 + 54 | 0] = 1;
+     if (i6) {
+      break;
+     }
+    } else {
+     i2 = 16;
+    }
+    if ((i2 | 0) == 16 ? i6 : 0) {
+     break;
+    }
+    HEAP32[i8 >> 2] = 4;
+    STACKTOP = i1;
+    return;
+   }
+  } while (0);
+  HEAP32[i8 >> 2] = 3;
+  STACKTOP = i1;
+  return;
+ }
+ if ((i8 | 0) != 1) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i3 + 32 >> 2] = 1;
+ STACKTOP = i1;
+ return;
+}
+function __ZN16b2BlockAllocator8AllocateEi(i4, i2) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ if ((i2 | 0) == 0) {
+  i9 = 0;
+  STACKTOP = i1;
+  return i9 | 0;
+ }
+ if ((i2 | 0) <= 0) {
+  ___assert_fail(1376, 1312, 104, 1392);
+ }
+ if ((i2 | 0) > 640) {
+  i9 = __Z7b2Alloci(i2) | 0;
+  STACKTOP = i1;
+  return i9 | 0;
+ }
+ i9 = HEAP8[632 + i2 | 0] | 0;
+ i5 = i9 & 255;
+ if (!((i9 & 255) < 14)) {
+  ___assert_fail(1408, 1312, 112, 1392);
+ }
+ i2 = i4 + (i5 << 2) + 12 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  HEAP32[i2 >> 2] = HEAP32[i3 >> 2];
+  i9 = i3;
+  STACKTOP = i1;
+  return i9 | 0;
+ }
+ i3 = i4 + 4 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i7 = i4 + 8 | 0;
+ if ((i6 | 0) == (HEAP32[i7 >> 2] | 0)) {
+  i9 = HEAP32[i4 >> 2] | 0;
+  i6 = i6 + 128 | 0;
+  HEAP32[i7 >> 2] = i6;
+  i6 = __Z7b2Alloci(i6 << 3) | 0;
+  HEAP32[i4 >> 2] = i6;
+  _memcpy(i6 | 0, i9 | 0, HEAP32[i3 >> 2] << 3 | 0) | 0;
+  _memset((HEAP32[i4 >> 2] | 0) + (HEAP32[i3 >> 2] << 3) | 0, 0, 1024) | 0;
+  __Z6b2FreePv(i9);
+  i6 = HEAP32[i3 >> 2] | 0;
+ }
+ i9 = HEAP32[i4 >> 2] | 0;
+ i7 = __Z7b2Alloci(16384) | 0;
+ i4 = i9 + (i6 << 3) + 4 | 0;
+ HEAP32[i4 >> 2] = i7;
+ i5 = HEAP32[576 + (i5 << 2) >> 2] | 0;
+ HEAP32[i9 + (i6 << 3) >> 2] = i5;
+ i6 = 16384 / (i5 | 0) | 0;
+ if ((Math_imul(i6, i5) | 0) >= 16385) {
+  ___assert_fail(1448, 1312, 140, 1392);
+ }
+ i6 = i6 + -1 | 0;
+ if ((i6 | 0) > 0) {
+  i9 = 0;
+  while (1) {
+   i8 = i9 + 1 | 0;
+   HEAP32[i7 + (Math_imul(i9, i5) | 0) >> 2] = i7 + (Math_imul(i8, i5) | 0);
+   i7 = HEAP32[i4 >> 2] | 0;
+   if ((i8 | 0) == (i6 | 0)) {
+    break;
+   } else {
+    i9 = i8;
+   }
+  }
+ }
+ HEAP32[i7 + (Math_imul(i6, i5) | 0) >> 2] = 0;
+ HEAP32[i2 >> 2] = HEAP32[HEAP32[i4 >> 2] >> 2];
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 1;
+ i9 = HEAP32[i4 >> 2] | 0;
+ STACKTOP = i1;
+ return i9 | 0;
+}
+function __ZN9b2Contact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i4, i5, i1, i3, i6) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ if ((HEAP8[4200] | 0) == 0) {
+  HEAP32[1002] = 3;
+  HEAP32[4012 >> 2] = 3;
+  HEAP8[4016 | 0] = 1;
+  HEAP32[4104 >> 2] = 4;
+  HEAP32[4108 >> 2] = 4;
+  HEAP8[4112 | 0] = 1;
+  HEAP32[4032 >> 2] = 4;
+  HEAP32[4036 >> 2] = 4;
+  HEAP8[4040 | 0] = 0;
+  HEAP32[4128 >> 2] = 5;
+  HEAP32[4132 >> 2] = 5;
+  HEAP8[4136 | 0] = 1;
+  HEAP32[4056 >> 2] = 6;
+  HEAP32[4060 >> 2] = 6;
+  HEAP8[4064 | 0] = 1;
+  HEAP32[4020 >> 2] = 6;
+  HEAP32[4024 >> 2] = 6;
+  HEAP8[4028 | 0] = 0;
+  HEAP32[4080 >> 2] = 7;
+  HEAP32[4084 >> 2] = 7;
+  HEAP8[4088 | 0] = 1;
+  HEAP32[4116 >> 2] = 7;
+  HEAP32[4120 >> 2] = 7;
+  HEAP8[4124 | 0] = 0;
+  HEAP32[4152 >> 2] = 8;
+  HEAP32[4156 >> 2] = 8;
+  HEAP8[4160 | 0] = 1;
+  HEAP32[4044 >> 2] = 8;
+  HEAP32[4048 >> 2] = 8;
+  HEAP8[4052 | 0] = 0;
+  HEAP32[4176 >> 2] = 9;
+  HEAP32[4180 >> 2] = 9;
+  HEAP8[4184 | 0] = 1;
+  HEAP32[4140 >> 2] = 9;
+  HEAP32[4144 >> 2] = 9;
+  HEAP8[4148 | 0] = 0;
+  HEAP8[4200] = 1;
+ }
+ i7 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 4 >> 2] | 0;
+ i8 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 4 >> 2] | 0;
+ if (!(i7 >>> 0 < 4)) {
+  ___assert_fail(4208, 4256, 80, 4344);
+ }
+ if (!(i8 >>> 0 < 4)) {
+  ___assert_fail(4296, 4256, 81, 4344);
+ }
+ i9 = HEAP32[4008 + (i7 * 48 | 0) + (i8 * 12 | 0) >> 2] | 0;
+ if ((i9 | 0) == 0) {
+  i9 = 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ if ((HEAP8[4008 + (i7 * 48 | 0) + (i8 * 12 | 0) + 8 | 0] | 0) == 0) {
+  i9 = FUNCTION_TABLE_iiiiii[i9 & 15](i1, i3, i4, i5, i6) | 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ } else {
+  i9 = FUNCTION_TABLE_iiiiii[i9 & 15](i4, i5, i1, i3, i6) | 0;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ return 0;
+}
+function __ZN13b2DynamicTree9MoveProxyEiRK6b2AABBRK6b2Vec2(i1, i2, i13, i9) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i13 = i13 | 0;
+ i9 = i9 | 0;
+ var i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d10 = 0.0, d11 = 0.0, i12 = 0;
+ i4 = STACKTOP;
+ if (!((i2 | 0) > -1)) {
+  ___assert_fail(3072, 2944, 135, 3152);
+ }
+ if ((HEAP32[i1 + 12 >> 2] | 0) <= (i2 | 0)) {
+  ___assert_fail(3072, 2944, 135, 3152);
+ }
+ i3 = i1 + 4 | 0;
+ i12 = HEAP32[i3 >> 2] | 0;
+ if (!((HEAP32[i12 + (i2 * 36 | 0) + 24 >> 2] | 0) == -1)) {
+  ___assert_fail(3120, 2944, 137, 3152);
+ }
+ if (((+HEAPF32[i12 + (i2 * 36 | 0) >> 2] <= +HEAPF32[i13 >> 2] ? +HEAPF32[i12 + (i2 * 36 | 0) + 4 >> 2] <= +HEAPF32[i13 + 4 >> 2] : 0) ? +HEAPF32[i13 + 8 >> 2] <= +HEAPF32[i12 + (i2 * 36 | 0) + 8 >> 2] : 0) ? +HEAPF32[i13 + 12 >> 2] <= +HEAPF32[i12 + (i2 * 36 | 0) + 12 >> 2] : 0) {
+  i13 = 0;
+  STACKTOP = i4;
+  return i13 | 0;
+ }
+ __ZN13b2DynamicTree10RemoveLeafEi(i1, i2);
+ i12 = i13;
+ d6 = +HEAPF32[i12 >> 2];
+ d8 = +HEAPF32[i12 + 4 >> 2];
+ i13 = i13 + 8 | 0;
+ d10 = +HEAPF32[i13 >> 2];
+ d6 = d6 + -.10000000149011612;
+ d8 = d8 + -.10000000149011612;
+ d10 = d10 + .10000000149011612;
+ d5 = +HEAPF32[i13 + 4 >> 2] + .10000000149011612;
+ d11 = +HEAPF32[i9 >> 2] * 2.0;
+ d7 = +HEAPF32[i9 + 4 >> 2] * 2.0;
+ if (d11 < 0.0) {
+  d6 = d6 + d11;
+ } else {
+  d10 = d11 + d10;
+ }
+ if (d7 < 0.0) {
+  d8 = d8 + d7;
+ } else {
+  d5 = d7 + d5;
+ }
+ i13 = HEAP32[i3 >> 2] | 0;
+ d7 = +d6;
+ d11 = +d8;
+ i12 = i13 + (i2 * 36 | 0) | 0;
+ HEAPF32[i12 >> 2] = d7;
+ HEAPF32[i12 + 4 >> 2] = d11;
+ d10 = +d10;
+ d11 = +d5;
+ i13 = i13 + (i2 * 36 | 0) + 8 | 0;
+ HEAPF32[i13 >> 2] = d10;
+ HEAPF32[i13 + 4 >> 2] = d11;
+ __ZN13b2DynamicTree10InsertLeafEi(i1, i2);
+ i13 = 1;
+ STACKTOP = i4;
+ return i13 | 0;
+}
+function __ZNK9b2Simplex16GetWitnessPointsEP6b2Vec2S1_(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, i9 = 0, i10 = 0, d11 = 0.0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 108 >> 2] | 0;
+ if ((i3 | 0) == 2) {
+  i9 = i1 + 24 | 0;
+  d7 = +HEAPF32[i9 >> 2];
+  i3 = i1 + 60 | 0;
+  d8 = +HEAPF32[i3 >> 2];
+  d6 = +(d7 * +HEAPF32[i1 >> 2] + d8 * +HEAPF32[i1 + 36 >> 2]);
+  d8 = +(d7 * +HEAPF32[i1 + 4 >> 2] + d8 * +HEAPF32[i1 + 40 >> 2]);
+  HEAPF32[i4 >> 2] = d6;
+  HEAPF32[i4 + 4 >> 2] = d8;
+  d8 = +HEAPF32[i9 >> 2];
+  d6 = +HEAPF32[i3 >> 2];
+  d7 = +(d8 * +HEAPF32[i1 + 8 >> 2] + d6 * +HEAPF32[i1 + 44 >> 2]);
+  d6 = +(d8 * +HEAPF32[i1 + 12 >> 2] + d6 * +HEAPF32[i1 + 48 >> 2]);
+  HEAPF32[i5 >> 2] = d7;
+  HEAPF32[i5 + 4 >> 2] = d6;
+  STACKTOP = i2;
+  return;
+ } else if ((i3 | 0) == 1) {
+  i10 = i1;
+  i9 = HEAP32[i10 + 4 >> 2] | 0;
+  i3 = i4;
+  HEAP32[i3 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i3 + 4 >> 2] = i9;
+  i3 = i1 + 8 | 0;
+  i4 = HEAP32[i3 + 4 >> 2] | 0;
+  i9 = i5;
+  HEAP32[i9 >> 2] = HEAP32[i3 >> 2];
+  HEAP32[i9 + 4 >> 2] = i4;
+  STACKTOP = i2;
+  return;
+ } else if ((i3 | 0) == 0) {
+  ___assert_fail(2712, 2672, 217, 2752);
+ } else if ((i3 | 0) == 3) {
+  d11 = +HEAPF32[i1 + 24 >> 2];
+  d6 = +HEAPF32[i1 + 60 >> 2];
+  d8 = +HEAPF32[i1 + 96 >> 2];
+  d7 = +(d11 * +HEAPF32[i1 >> 2] + d6 * +HEAPF32[i1 + 36 >> 2] + d8 * +HEAPF32[i1 + 72 >> 2]);
+  d8 = +(d11 * +HEAPF32[i1 + 4 >> 2] + d6 * +HEAPF32[i1 + 40 >> 2] + d8 * +HEAPF32[i1 + 76 >> 2]);
+  i10 = i4;
+  HEAPF32[i10 >> 2] = d7;
+  HEAPF32[i10 + 4 >> 2] = d8;
+  i10 = i5;
+  HEAPF32[i10 >> 2] = d7;
+  HEAPF32[i10 + 4 >> 2] = d8;
+  STACKTOP = i2;
+  return;
+ } else {
+  ___assert_fail(2712, 2672, 236, 2752);
+ }
+}
+function __ZNK12b2ChainShape12GetChildEdgeEP11b2EdgeShapei(i4, i3, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ if (!((i1 | 0) > -1)) {
+  ___assert_fail(6832, 6792, 89, 6872);
+ }
+ i5 = i4 + 16 | 0;
+ if (((HEAP32[i5 >> 2] | 0) + -1 | 0) <= (i1 | 0)) {
+  ___assert_fail(6832, 6792, 89, 6872);
+ }
+ HEAP32[i3 + 4 >> 2] = 1;
+ HEAPF32[i3 + 8 >> 2] = +HEAPF32[i4 + 8 >> 2];
+ i6 = i4 + 12 | 0;
+ i7 = (HEAP32[i6 >> 2] | 0) + (i1 << 3) | 0;
+ i8 = HEAP32[i7 + 4 >> 2] | 0;
+ i9 = i3 + 12 | 0;
+ HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i9 + 4 >> 2] = i8;
+ i9 = (HEAP32[i6 >> 2] | 0) + (i1 + 1 << 3) | 0;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i3 + 20 | 0;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ i7 = i3 + 28 | 0;
+ if ((i1 | 0) > 0) {
+  i10 = (HEAP32[i6 >> 2] | 0) + (i1 + -1 << 3) | 0;
+  i8 = HEAP32[i10 + 4 >> 2] | 0;
+  i9 = i7;
+  HEAP32[i9 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i9 + 4 >> 2] = i8;
+  HEAP8[i3 + 44 | 0] = 1;
+ } else {
+  i8 = i4 + 20 | 0;
+  i9 = HEAP32[i8 + 4 >> 2] | 0;
+  i10 = i7;
+  HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i10 + 4 >> 2] = i9;
+  HEAP8[i3 + 44 | 0] = HEAP8[i4 + 36 | 0] | 0;
+ }
+ i7 = i3 + 36 | 0;
+ if (((HEAP32[i5 >> 2] | 0) + -2 | 0) > (i1 | 0)) {
+  i8 = (HEAP32[i6 >> 2] | 0) + (i1 + 2 << 3) | 0;
+  i9 = HEAP32[i8 + 4 >> 2] | 0;
+  i10 = i7;
+  HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i10 + 4 >> 2] = i9;
+  HEAP8[i3 + 45 | 0] = 1;
+  STACKTOP = i2;
+  return;
+ } else {
+  i8 = i4 + 28 | 0;
+  i9 = HEAP32[i8 + 4 >> 2] | 0;
+  i10 = i7;
+  HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i10 + 4 >> 2] = i9;
+  HEAP8[i3 + 45 | 0] = HEAP8[i4 + 37 | 0] | 0;
+  STACKTOP = i2;
+  return;
+ }
+}
+function __ZN15b2DistanceProxy3SetEPK7b2Shapei(i3, i1, i5) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 4 >> 2] | 0;
+ if ((i4 | 0) == 1) {
+  HEAP32[i3 + 16 >> 2] = i1 + 12;
+  HEAP32[i3 + 20 >> 2] = 2;
+  HEAPF32[i3 + 24 >> 2] = +HEAPF32[i1 + 8 >> 2];
+  STACKTOP = i2;
+  return;
+ } else if ((i4 | 0) == 3) {
+  if (!((i5 | 0) > -1)) {
+   ___assert_fail(2632, 2672, 53, 2704);
+  }
+  i4 = i1 + 16 | 0;
+  if ((HEAP32[i4 >> 2] | 0) <= (i5 | 0)) {
+   ___assert_fail(2632, 2672, 53, 2704);
+  }
+  i7 = i1 + 12 | 0;
+  i9 = (HEAP32[i7 >> 2] | 0) + (i5 << 3) | 0;
+  i8 = HEAP32[i9 + 4 >> 2] | 0;
+  i6 = i3;
+  HEAP32[i6 >> 2] = HEAP32[i9 >> 2];
+  HEAP32[i6 + 4 >> 2] = i8;
+  i6 = i5 + 1 | 0;
+  i5 = i3 + 8 | 0;
+  i7 = HEAP32[i7 >> 2] | 0;
+  if ((i6 | 0) < (HEAP32[i4 >> 2] | 0)) {
+   i7 = i7 + (i6 << 3) | 0;
+   i8 = HEAP32[i7 + 4 >> 2] | 0;
+   i9 = i5;
+   HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i9 + 4 >> 2] = i8;
+  } else {
+   i8 = HEAP32[i7 + 4 >> 2] | 0;
+   i9 = i5;
+   HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i9 + 4 >> 2] = i8;
+  }
+  HEAP32[i3 + 16 >> 2] = i3;
+  HEAP32[i3 + 20 >> 2] = 2;
+  HEAPF32[i3 + 24 >> 2] = +HEAPF32[i1 + 8 >> 2];
+  STACKTOP = i2;
+  return;
+ } else if ((i4 | 0) == 2) {
+  HEAP32[i3 + 16 >> 2] = i1 + 20;
+  HEAP32[i3 + 20 >> 2] = HEAP32[i1 + 148 >> 2];
+  HEAPF32[i3 + 24 >> 2] = +HEAPF32[i1 + 8 >> 2];
+  STACKTOP = i2;
+  return;
+ } else if ((i4 | 0) == 0) {
+  HEAP32[i3 + 16 >> 2] = i1 + 12;
+  HEAP32[i3 + 20 >> 2] = 1;
+  HEAPF32[i3 + 24 >> 2] = +HEAPF32[i1 + 8 >> 2];
+  STACKTOP = i2;
+  return;
+ } else {
+  ___assert_fail(2712, 2672, 81, 2704);
+ }
+}
+function __ZL16b2EdgeSeparationPK14b2PolygonShapeRK11b2TransformiS1_S4_(i2, i7, i4, i5, i6) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var d1 = 0.0, d3 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, i12 = 0, i13 = 0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, i18 = 0, i19 = 0, i20 = 0;
+ i12 = STACKTOP;
+ i13 = HEAP32[i5 + 148 >> 2] | 0;
+ if (!((i4 | 0) > -1)) {
+  ___assert_fail(5640, 5688, 32, 5752);
+ }
+ if ((HEAP32[i2 + 148 >> 2] | 0) <= (i4 | 0)) {
+  ___assert_fail(5640, 5688, 32, 5752);
+ }
+ d11 = +HEAPF32[i7 + 12 >> 2];
+ d9 = +HEAPF32[i2 + (i4 << 3) + 84 >> 2];
+ d1 = +HEAPF32[i7 + 8 >> 2];
+ d3 = +HEAPF32[i2 + (i4 << 3) + 88 >> 2];
+ d8 = d11 * d9 - d1 * d3;
+ d3 = d9 * d1 + d11 * d3;
+ d9 = +HEAPF32[i6 + 12 >> 2];
+ d10 = +HEAPF32[i6 + 8 >> 2];
+ d16 = d9 * d8 + d10 * d3;
+ d14 = d9 * d3 - d8 * d10;
+ if ((i13 | 0) > 0) {
+  i19 = 0;
+  i20 = 0;
+  d15 = 3.4028234663852886e+38;
+  while (1) {
+   d17 = d16 * +HEAPF32[i5 + (i19 << 3) + 20 >> 2] + d14 * +HEAPF32[i5 + (i19 << 3) + 24 >> 2];
+   i18 = d17 < d15;
+   i20 = i18 ? i19 : i20;
+   i19 = i19 + 1 | 0;
+   if ((i19 | 0) == (i13 | 0)) {
+    break;
+   } else {
+    d15 = i18 ? d17 : d15;
+   }
+  }
+ } else {
+  i20 = 0;
+ }
+ d16 = +HEAPF32[i2 + (i4 << 3) + 20 >> 2];
+ d17 = +HEAPF32[i2 + (i4 << 3) + 24 >> 2];
+ d14 = +HEAPF32[i5 + (i20 << 3) + 20 >> 2];
+ d15 = +HEAPF32[i5 + (i20 << 3) + 24 >> 2];
+ STACKTOP = i12;
+ return +(d8 * (+HEAPF32[i6 >> 2] + (d9 * d14 - d10 * d15) - (+HEAPF32[i7 >> 2] + (d11 * d16 - d1 * d17))) + d3 * (d14 * d10 + d9 * d15 + +HEAPF32[i6 + 4 >> 2] - (d16 * d1 + d11 * d17 + +HEAPF32[i7 + 4 >> 2])));
+}
+function __Z4iterv() {
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0, d7 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i2 = i1;
+ i3 = i1 + 32 | 0;
+ i4 = HEAP32[16] | 0;
+ if ((i4 | 0) >= (HEAP32[4] | 0)) {
+  HEAP32[16] = i4 + 1;
+  __Z7measurePl(i3, HEAP32[8] | 0);
+  d7 = +HEAPF32[i3 + 4 >> 2];
+  d6 = +(HEAP32[10] | 0) / 1.0e6 * 1.0e3;
+  d5 = +(HEAP32[12] | 0) / 1.0e6 * 1.0e3;
+  HEAPF64[tempDoublePtr >> 3] = +HEAPF32[i3 >> 2];
+  HEAP32[i2 >> 2] = HEAP32[tempDoublePtr >> 2];
+  HEAP32[i2 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+  i4 = i2 + 8 | 0;
+  HEAPF64[tempDoublePtr >> 3] = d7;
+  HEAP32[i4 >> 2] = HEAP32[tempDoublePtr >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+  i4 = i2 + 16 | 0;
+  HEAPF64[tempDoublePtr >> 3] = d6;
+  HEAP32[i4 >> 2] = HEAP32[tempDoublePtr >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+  i4 = i2 + 24 | 0;
+  HEAPF64[tempDoublePtr >> 3] = d5;
+  HEAP32[i4 >> 2] = HEAP32[tempDoublePtr >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+  _printf(96, i2 | 0) | 0;
+  _emscripten_run_script(152);
+  if ((HEAP32[18] | 0) == 0) {
+   STACKTOP = i1;
+   return;
+  }
+  _emscripten_cancel_main_loop();
+  STACKTOP = i1;
+  return;
+ }
+ i3 = _clock() | 0;
+ __ZN7b2World4StepEfii(HEAP32[6] | 0, .01666666753590107, 3, 3);
+ i3 = (_clock() | 0) - i3 | 0;
+ i2 = HEAP32[16] | 0;
+ HEAP32[(HEAP32[8] | 0) + (i2 << 2) >> 2] = i3;
+ if ((i3 | 0) < (HEAP32[10] | 0)) {
+  HEAP32[10] = i3;
+ }
+ if ((i3 | 0) > (HEAP32[12] | 0)) {
+  HEAP32[12] = i3;
+ }
+ HEAP32[16] = i2 + 1;
+ STACKTOP = i1;
+ return;
+}
+function __ZN13b2DynamicTree12AllocateNodeEv(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i2 = i5 + 16 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ if ((i3 | 0) == -1) {
+  i4 = i5 + 8 | 0;
+  i6 = HEAP32[i4 >> 2] | 0;
+  i3 = i5 + 12 | 0;
+  if ((i6 | 0) != (HEAP32[i3 >> 2] | 0)) {
+   ___assert_fail(2912, 2944, 61, 2984);
+  }
+  i5 = i5 + 4 | 0;
+  i7 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i3 >> 2] = i6 << 1;
+  i6 = __Z7b2Alloci(i6 * 72 | 0) | 0;
+  HEAP32[i5 >> 2] = i6;
+  _memcpy(i6 | 0, i7 | 0, (HEAP32[i4 >> 2] | 0) * 36 | 0) | 0;
+  __Z6b2FreePv(i7);
+  i6 = HEAP32[i4 >> 2] | 0;
+  i7 = (HEAP32[i3 >> 2] | 0) + -1 | 0;
+  i5 = HEAP32[i5 >> 2] | 0;
+  if ((i6 | 0) < (i7 | 0)) {
+   i7 = i6;
+   while (1) {
+    i6 = i7 + 1 | 0;
+    HEAP32[i5 + (i7 * 36 | 0) + 20 >> 2] = i6;
+    HEAP32[i5 + (i7 * 36 | 0) + 32 >> 2] = -1;
+    i7 = (HEAP32[i3 >> 2] | 0) + -1 | 0;
+    if ((i6 | 0) < (i7 | 0)) {
+     i7 = i6;
+    } else {
+     break;
+    }
+   }
+  }
+  HEAP32[i5 + (i7 * 36 | 0) + 20 >> 2] = -1;
+  HEAP32[i5 + (((HEAP32[i3 >> 2] | 0) + -1 | 0) * 36 | 0) + 32 >> 2] = -1;
+  i3 = HEAP32[i4 >> 2] | 0;
+  HEAP32[i2 >> 2] = i3;
+ } else {
+  i4 = i5 + 8 | 0;
+  i5 = HEAP32[i5 + 4 >> 2] | 0;
+ }
+ i7 = i5 + (i3 * 36 | 0) + 20 | 0;
+ HEAP32[i2 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i7 >> 2] = -1;
+ HEAP32[i5 + (i3 * 36 | 0) + 24 >> 2] = -1;
+ HEAP32[i5 + (i3 * 36 | 0) + 28 >> 2] = -1;
+ HEAP32[i5 + (i3 * 36 | 0) + 32 >> 2] = 0;
+ HEAP32[i5 + (i3 * 36 | 0) + 16 >> 2] = 0;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 1;
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function __ZN9b2Fixture6CreateEP16b2BlockAllocatorP6b2BodyPK12b2FixtureDef(i1, i5, i4, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i6 = 0, i7 = 0, d8 = 0.0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 40 >> 2] = HEAP32[i3 + 4 >> 2];
+ HEAPF32[i1 + 16 >> 2] = +HEAPF32[i3 + 8 >> 2];
+ HEAPF32[i1 + 20 >> 2] = +HEAPF32[i3 + 12 >> 2];
+ HEAP32[i1 + 8 >> 2] = i4;
+ HEAP32[i1 + 4 >> 2] = 0;
+ i4 = i1 + 32 | 0;
+ i6 = i3 + 22 | 0;
+ HEAP16[i4 + 0 >> 1] = HEAP16[i6 + 0 >> 1] | 0;
+ HEAP16[i4 + 2 >> 1] = HEAP16[i6 + 2 >> 1] | 0;
+ HEAP16[i4 + 4 >> 1] = HEAP16[i6 + 4 >> 1] | 0;
+ HEAP8[i1 + 38 | 0] = HEAP8[i3 + 20 | 0] | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ i4 = FUNCTION_TABLE_iii[HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] & 3](i4, i5) | 0;
+ HEAP32[i1 + 12 >> 2] = i4;
+ i4 = FUNCTION_TABLE_ii[HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] & 3](i4) | 0;
+ i6 = __ZN16b2BlockAllocator8AllocateEi(i5, i4 * 28 | 0) | 0;
+ i5 = i1 + 24 | 0;
+ HEAP32[i5 >> 2] = i6;
+ if ((i4 | 0) > 0) {
+  i7 = 0;
+ } else {
+  i7 = i1 + 28 | 0;
+  HEAP32[i7 >> 2] = 0;
+  i7 = i3 + 16 | 0;
+  d8 = +HEAPF32[i7 >> 2];
+  HEAPF32[i1 >> 2] = d8;
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  HEAP32[i6 + (i7 * 28 | 0) + 16 >> 2] = 0;
+  i6 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i6 + (i7 * 28 | 0) + 24 >> 2] = -1;
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != (i4 | 0));
+ i7 = i1 + 28 | 0;
+ HEAP32[i7 >> 2] = 0;
+ i7 = i3 + 16 | 0;
+ d8 = +HEAPF32[i7 >> 2];
+ HEAPF32[i1 >> 2] = d8;
+ STACKTOP = i2;
+ return;
+}
+function __Z19b2ClipSegmentToLineP12b2ClipVertexPKS_RK6b2Vec2fi(i4, i1, i5, d9, i2) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ d9 = +d9;
+ i2 = i2 | 0;
+ var i3 = 0, i6 = 0, d7 = 0.0, i8 = 0, i10 = 0, d11 = 0.0, d12 = 0.0, i13 = 0;
+ i3 = STACKTOP;
+ d12 = +HEAPF32[i5 >> 2];
+ d11 = +HEAPF32[i5 + 4 >> 2];
+ i5 = i1 + 4 | 0;
+ d7 = d12 * +HEAPF32[i1 >> 2] + d11 * +HEAPF32[i5 >> 2] - d9;
+ i6 = i1 + 12 | 0;
+ i8 = i1 + 16 | 0;
+ d9 = d12 * +HEAPF32[i6 >> 2] + d11 * +HEAPF32[i8 >> 2] - d9;
+ if (!(d7 <= 0.0)) {
+  i10 = 0;
+ } else {
+  HEAP32[i4 + 0 >> 2] = HEAP32[i1 + 0 >> 2];
+  HEAP32[i4 + 4 >> 2] = HEAP32[i1 + 4 >> 2];
+  HEAP32[i4 + 8 >> 2] = HEAP32[i1 + 8 >> 2];
+  i10 = 1;
+ }
+ if (d9 <= 0.0) {
+  i13 = i10 + 1 | 0;
+  i10 = i4 + (i10 * 12 | 0) | 0;
+  HEAP32[i10 + 0 >> 2] = HEAP32[i6 + 0 >> 2];
+  HEAP32[i10 + 4 >> 2] = HEAP32[i6 + 4 >> 2];
+  HEAP32[i10 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+  i10 = i13;
+ }
+ if (!(d7 * d9 < 0.0)) {
+  i13 = i10;
+  STACKTOP = i3;
+  return i13 | 0;
+ }
+ d9 = d7 / (d7 - d9);
+ d11 = +HEAPF32[i1 >> 2];
+ d12 = +HEAPF32[i5 >> 2];
+ d11 = +(d11 + d9 * (+HEAPF32[i6 >> 2] - d11));
+ d12 = +(d12 + d9 * (+HEAPF32[i8 >> 2] - d12));
+ i13 = i4 + (i10 * 12 | 0) | 0;
+ HEAPF32[i13 >> 2] = d11;
+ HEAPF32[i13 + 4 >> 2] = d12;
+ i13 = i4 + (i10 * 12 | 0) + 8 | 0;
+ HEAP8[i13] = i2;
+ HEAP8[i13 + 1 | 0] = HEAP8[i1 + 9 | 0] | 0;
+ HEAP8[i13 + 2 | 0] = 0;
+ HEAP8[i13 + 3 | 0] = 1;
+ i13 = i10 + 1 | 0;
+ STACKTOP = i3;
+ return i13 | 0;
+}
+function __Z16b2CollideCirclesP10b2ManifoldPK13b2CircleShapeRK11b2TransformS3_S6_(i1, i7, i8, i6, i9) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ i6 = i6 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, d10 = 0.0, d11 = 0.0, d12 = 0.0, d13 = 0.0, d14 = 0.0, d15 = 0.0, d16 = 0.0, d17 = 0.0, d18 = 0.0;
+ i2 = STACKTOP;
+ i4 = i1 + 60 | 0;
+ HEAP32[i4 >> 2] = 0;
+ i3 = i7 + 12 | 0;
+ d10 = +HEAPF32[i8 + 12 >> 2];
+ d14 = +HEAPF32[i3 >> 2];
+ d13 = +HEAPF32[i8 + 8 >> 2];
+ d11 = +HEAPF32[i7 + 16 >> 2];
+ i5 = i6 + 12 | 0;
+ d16 = +HEAPF32[i9 + 12 >> 2];
+ d18 = +HEAPF32[i5 >> 2];
+ d17 = +HEAPF32[i9 + 8 >> 2];
+ d15 = +HEAPF32[i6 + 16 >> 2];
+ d12 = +HEAPF32[i9 >> 2] + (d16 * d18 - d17 * d15) - (+HEAPF32[i8 >> 2] + (d10 * d14 - d13 * d11));
+ d11 = d18 * d17 + d16 * d15 + +HEAPF32[i9 + 4 >> 2] - (d14 * d13 + d10 * d11 + +HEAPF32[i8 + 4 >> 2]);
+ d10 = +HEAPF32[i7 + 8 >> 2] + +HEAPF32[i6 + 8 >> 2];
+ if (d12 * d12 + d11 * d11 > d10 * d10) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i1 + 56 >> 2] = 0;
+ i9 = i3;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i1 + 48 | 0;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ HEAPF32[i1 + 40 >> 2] = 0.0;
+ HEAPF32[i1 + 44 >> 2] = 0.0;
+ HEAP32[i4 >> 2] = 1;
+ i7 = i5;
+ i8 = HEAP32[i7 + 4 >> 2] | 0;
+ i9 = i1;
+ HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i9 + 4 >> 2] = i8;
+ HEAP32[i1 + 16 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZNK14b2PolygonShape11ComputeAABBEP6b2AABBRK11b2Transformi(i1, i2, i7, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i3 = i3 | 0;
+ var d4 = 0.0, d5 = 0.0, d6 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0, d11 = 0.0, d12 = 0.0, i13 = 0, d14 = 0.0, d15 = 0.0, d16 = 0.0;
+ i3 = STACKTOP;
+ d4 = +HEAPF32[i7 + 12 >> 2];
+ d15 = +HEAPF32[i1 + 20 >> 2];
+ d5 = +HEAPF32[i7 + 8 >> 2];
+ d12 = +HEAPF32[i1 + 24 >> 2];
+ d6 = +HEAPF32[i7 >> 2];
+ d9 = d6 + (d4 * d15 - d5 * d12);
+ d8 = +HEAPF32[i7 + 4 >> 2];
+ d12 = d15 * d5 + d4 * d12 + d8;
+ i7 = HEAP32[i1 + 148 >> 2] | 0;
+ if ((i7 | 0) > 1) {
+  d10 = d9;
+  d11 = d12;
+  i13 = 1;
+  do {
+   d16 = +HEAPF32[i1 + (i13 << 3) + 20 >> 2];
+   d14 = +HEAPF32[i1 + (i13 << 3) + 24 >> 2];
+   d15 = d6 + (d4 * d16 - d5 * d14);
+   d14 = d16 * d5 + d4 * d14 + d8;
+   d10 = d10 < d15 ? d10 : d15;
+   d11 = d11 < d14 ? d11 : d14;
+   d9 = d9 > d15 ? d9 : d15;
+   d12 = d12 > d14 ? d12 : d14;
+   i13 = i13 + 1 | 0;
+  } while ((i13 | 0) < (i7 | 0));
+ } else {
+  d11 = d12;
+  d10 = d9;
+ }
+ d16 = +HEAPF32[i1 + 8 >> 2];
+ d14 = +(d10 - d16);
+ d15 = +(d11 - d16);
+ i13 = i2;
+ HEAPF32[i13 >> 2] = d14;
+ HEAPF32[i13 + 4 >> 2] = d15;
+ d15 = +(d9 + d16);
+ d16 = +(d12 + d16);
+ i13 = i2 + 8 | 0;
+ HEAPF32[i13 >> 2] = d15;
+ HEAPF32[i13 + 4 >> 2] = d16;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK10__cxxabiv120__si_class_type_info16search_above_dstEPNS_19__dynamic_cast_infoEPKvS4_ib(i5, i1, i4, i6, i3, i7) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i5 | 0) != (HEAP32[i1 + 8 >> 2] | 0)) {
+  i5 = HEAP32[i5 + 8 >> 2] | 0;
+  FUNCTION_TABLE_viiiiii[HEAP32[(HEAP32[i5 >> 2] | 0) + 20 >> 2] & 3](i5, i1, i4, i6, i3, i7);
+  STACKTOP = i2;
+  return;
+ }
+ HEAP8[i1 + 53 | 0] = 1;
+ if ((HEAP32[i1 + 4 >> 2] | 0) != (i6 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP8[i1 + 52 | 0] = 1;
+ i5 = i1 + 16 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i5 >> 2] = i4;
+  HEAP32[i1 + 24 >> 2] = i3;
+  HEAP32[i1 + 36 >> 2] = 1;
+  if (!((HEAP32[i1 + 48 >> 2] | 0) == 1 & (i3 | 0) == 1)) {
+   STACKTOP = i2;
+   return;
+  }
+  HEAP8[i1 + 54 | 0] = 1;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i6 | 0) != (i4 | 0)) {
+  i7 = i1 + 36 | 0;
+  HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + 1;
+  HEAP8[i1 + 54 | 0] = 1;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i1 + 24 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) == 2) {
+  HEAP32[i4 >> 2] = i3;
+ } else {
+  i3 = i5;
+ }
+ if (!((HEAP32[i1 + 48 >> 2] | 0) == 1 & (i3 | 0) == 1)) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP8[i1 + 54 | 0] = 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN6b2Body13CreateFixtureEPK12b2FixtureDef(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i2 = i1 + 88 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((HEAP32[i4 + 102868 >> 2] & 2 | 0) != 0) {
+  ___assert_fail(1776, 1520, 153, 1808);
+ }
+ i6 = __ZN16b2BlockAllocator8AllocateEi(i4, 44) | 0;
+ if ((i6 | 0) == 0) {
+  i6 = 0;
+ } else {
+  __ZN9b2FixtureC2Ev(i6);
+ }
+ __ZN9b2Fixture6CreateEP16b2BlockAllocatorP6b2BodyPK12b2FixtureDef(i6, i4, i1, i5);
+ if (!((HEAP16[i1 + 4 >> 1] & 32) == 0)) {
+  __ZN9b2Fixture13CreateProxiesEP12b2BroadPhaseRK11b2Transform(i6, (HEAP32[i2 >> 2] | 0) + 102872 | 0, i1 + 12 | 0);
+ }
+ i5 = i1 + 100 | 0;
+ HEAP32[i6 + 4 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i5 >> 2] = i6;
+ i5 = i1 + 104 | 0;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+ HEAP32[i6 + 8 >> 2] = i1;
+ if (!(+HEAPF32[i6 >> 2] > 0.0)) {
+  i5 = HEAP32[i2 >> 2] | 0;
+  i5 = i5 + 102868 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i4 = i4 | 1;
+  HEAP32[i5 >> 2] = i4;
+  STACKTOP = i3;
+  return i6 | 0;
+ }
+ __ZN6b2Body13ResetMassDataEv(i1);
+ i5 = HEAP32[i2 >> 2] | 0;
+ i5 = i5 + 102868 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ i4 = i4 | 1;
+ HEAP32[i5 >> 2] = i4;
+ STACKTOP = i3;
+ return i6 | 0;
+}
+function __Z13b2TestOverlapPK7b2ShapeiS1_iRK11b2TransformS4_(i6, i5, i4, i3, i2, i1) {
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i8 = STACKTOP;
+ STACKTOP = STACKTOP + 128 | 0;
+ i9 = i8 + 36 | 0;
+ i10 = i8 + 24 | 0;
+ i7 = i8;
+ HEAP32[i9 + 16 >> 2] = 0;
+ HEAP32[i9 + 20 >> 2] = 0;
+ HEAPF32[i9 + 24 >> 2] = 0.0;
+ HEAP32[i9 + 44 >> 2] = 0;
+ HEAP32[i9 + 48 >> 2] = 0;
+ HEAPF32[i9 + 52 >> 2] = 0.0;
+ __ZN15b2DistanceProxy3SetEPK7b2Shapei(i9, i6, i5);
+ __ZN15b2DistanceProxy3SetEPK7b2Shapei(i9 + 28 | 0, i4, i3);
+ i6 = i9 + 56 | 0;
+ HEAP32[i6 + 0 >> 2] = HEAP32[i2 + 0 >> 2];
+ HEAP32[i6 + 4 >> 2] = HEAP32[i2 + 4 >> 2];
+ HEAP32[i6 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+ HEAP32[i6 + 12 >> 2] = HEAP32[i2 + 12 >> 2];
+ i6 = i9 + 72 | 0;
+ HEAP32[i6 + 0 >> 2] = HEAP32[i1 + 0 >> 2];
+ HEAP32[i6 + 4 >> 2] = HEAP32[i1 + 4 >> 2];
+ HEAP32[i6 + 8 >> 2] = HEAP32[i1 + 8 >> 2];
+ HEAP32[i6 + 12 >> 2] = HEAP32[i1 + 12 >> 2];
+ HEAP8[i9 + 88 | 0] = 1;
+ HEAP16[i10 + 4 >> 1] = 0;
+ __Z10b2DistanceP16b2DistanceOutputP14b2SimplexCachePK15b2DistanceInput(i7, i10, i9);
+ STACKTOP = i8;
+ return +HEAPF32[i7 + 16 >> 2] < 11920928955078125.0e-22 | 0;
+}
+function __ZNK10__cxxabiv117__class_type_info16search_above_dstEPNS_19__dynamic_cast_infoEPKvS4_ib(i6, i1, i4, i5, i2, i3) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i3 = STACKTOP;
+ if ((HEAP32[i1 + 8 >> 2] | 0) != (i6 | 0)) {
+  STACKTOP = i3;
+  return;
+ }
+ HEAP8[i1 + 53 | 0] = 1;
+ if ((HEAP32[i1 + 4 >> 2] | 0) != (i5 | 0)) {
+  STACKTOP = i3;
+  return;
+ }
+ HEAP8[i1 + 52 | 0] = 1;
+ i5 = i1 + 16 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i5 >> 2] = i4;
+  HEAP32[i1 + 24 >> 2] = i2;
+  HEAP32[i1 + 36 >> 2] = 1;
+  if (!((HEAP32[i1 + 48 >> 2] | 0) == 1 & (i2 | 0) == 1)) {
+   STACKTOP = i3;
+   return;
+  }
+  HEAP8[i1 + 54 | 0] = 1;
+  STACKTOP = i3;
+  return;
+ }
+ if ((i6 | 0) != (i4 | 0)) {
+  i6 = i1 + 36 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+  HEAP8[i1 + 54 | 0] = 1;
+  STACKTOP = i3;
+  return;
+ }
+ i4 = i1 + 24 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) == 2) {
+  HEAP32[i4 >> 2] = i2;
+ } else {
+  i2 = i5;
+ }
+ if (!((HEAP32[i1 + 48 >> 2] | 0) == 1 & (i2 | 0) == 1)) {
+  STACKTOP = i3;
+  return;
+ }
+ HEAP8[i1 + 54 | 0] = 1;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK11b2EdgeShape5CloneEP16b2BlockAllocator(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 48) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+ } else {
+  HEAP32[i3 >> 2] = 240;
+  HEAP32[i3 + 4 >> 2] = 1;
+  HEAPF32[i3 + 8 >> 2] = .009999999776482582;
+  i4 = i3 + 28 | 0;
+  HEAP32[i4 + 0 >> 2] = 0;
+  HEAP32[i4 + 4 >> 2] = 0;
+  HEAP32[i4 + 8 >> 2] = 0;
+  HEAP32[i4 + 12 >> 2] = 0;
+  HEAP16[i4 + 16 >> 1] = 0;
+ }
+ i6 = i1 + 4 | 0;
+ i5 = HEAP32[i6 + 4 >> 2] | 0;
+ i4 = i3 + 4 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i4 + 4 >> 2] = i5;
+ i4 = i3 + 12 | 0;
+ i1 = i1 + 12 | 0;
+ HEAP32[i4 + 0 >> 2] = HEAP32[i1 + 0 >> 2];
+ HEAP32[i4 + 4 >> 2] = HEAP32[i1 + 4 >> 2];
+ HEAP32[i4 + 8 >> 2] = HEAP32[i1 + 8 >> 2];
+ HEAP32[i4 + 12 >> 2] = HEAP32[i1 + 12 >> 2];
+ HEAP32[i4 + 16 >> 2] = HEAP32[i1 + 16 >> 2];
+ HEAP32[i4 + 20 >> 2] = HEAP32[i1 + 20 >> 2];
+ HEAP32[i4 + 24 >> 2] = HEAP32[i1 + 24 >> 2];
+ HEAP32[i4 + 28 >> 2] = HEAP32[i1 + 28 >> 2];
+ HEAP16[i4 + 32 >> 1] = HEAP16[i1 + 32 >> 1] | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function __ZN7b2WorldC2ERK6b2Vec2(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ __ZN16b2BlockAllocatorC2Ev(i1);
+ __ZN16b2StackAllocatorC2Ev(i1 + 68 | 0);
+ __ZN16b2ContactManagerC2Ev(i1 + 102872 | 0);
+ i6 = i1 + 102968 | 0;
+ HEAP32[i1 + 102980 >> 2] = 0;
+ HEAP32[i1 + 102984 >> 2] = 0;
+ i4 = i1 + 102952 | 0;
+ i5 = i1 + 102992 | 0;
+ HEAP32[i4 + 0 >> 2] = 0;
+ HEAP32[i4 + 4 >> 2] = 0;
+ HEAP32[i4 + 8 >> 2] = 0;
+ HEAP32[i4 + 12 >> 2] = 0;
+ HEAP8[i5] = 1;
+ HEAP8[i1 + 102993 | 0] = 1;
+ HEAP8[i1 + 102994 | 0] = 0;
+ HEAP8[i1 + 102995 | 0] = 1;
+ HEAP8[i1 + 102976 | 0] = 1;
+ i5 = i2;
+ i4 = HEAP32[i5 + 4 >> 2] | 0;
+ i2 = i6;
+ HEAP32[i2 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i2 + 4 >> 2] = i4;
+ HEAP32[i1 + 102868 >> 2] = 4;
+ HEAPF32[i1 + 102988 >> 2] = 0.0;
+ HEAP32[i1 + 102948 >> 2] = i1;
+ i2 = i1 + 102996 | 0;
+ HEAP32[i2 + 0 >> 2] = 0;
+ HEAP32[i2 + 4 >> 2] = 0;
+ HEAP32[i2 + 8 >> 2] = 0;
+ HEAP32[i2 + 12 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 24 >> 2] = 0;
+ HEAP32[i2 + 28 >> 2] = 0;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK10__cxxabiv117__class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib(i6, i3, i4, i1, i2) {
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i5 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i3 + 8 >> 2] | 0) == (i6 | 0)) {
+  if ((HEAP32[i3 + 4 >> 2] | 0) != (i4 | 0)) {
+   STACKTOP = i2;
+   return;
+  }
+  i3 = i3 + 28 | 0;
+  if ((HEAP32[i3 >> 2] | 0) == 1) {
+   STACKTOP = i2;
+   return;
+  }
+  HEAP32[i3 >> 2] = i1;
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[i3 >> 2] | 0) != (i6 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[i3 + 16 >> 2] | 0) != (i4 | 0) ? (i5 = i3 + 20 | 0, (HEAP32[i5 >> 2] | 0) != (i4 | 0)) : 0) {
+  HEAP32[i3 + 32 >> 2] = i1;
+  HEAP32[i5 >> 2] = i4;
+  i6 = i3 + 40 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+  if ((HEAP32[i3 + 36 >> 2] | 0) == 1 ? (HEAP32[i3 + 24 >> 2] | 0) == 2 : 0) {
+   HEAP8[i3 + 54 | 0] = 1;
+  }
+  HEAP32[i3 + 44 >> 2] = 4;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i1 | 0) != 1) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i3 + 32 >> 2] = 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN9b2Contact7DestroyEPS_P16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ if ((HEAP8[4200] | 0) == 0) {
+  ___assert_fail(4352, 4256, 103, 4376);
+ }
+ i4 = HEAP32[i1 + 48 >> 2] | 0;
+ if ((HEAP32[i1 + 124 >> 2] | 0) > 0) {
+  i7 = HEAP32[i4 + 8 >> 2] | 0;
+  i6 = i7 + 4 | 0;
+  i5 = HEAPU16[i6 >> 1] | 0;
+  if ((i5 & 2 | 0) == 0) {
+   HEAP16[i6 >> 1] = i5 | 2;
+   HEAPF32[i7 + 144 >> 2] = 0.0;
+  }
+  i7 = HEAP32[i1 + 52 >> 2] | 0;
+  i6 = HEAP32[i7 + 8 >> 2] | 0;
+  i5 = i6 + 4 | 0;
+  i8 = HEAPU16[i5 >> 1] | 0;
+  if ((i8 & 2 | 0) == 0) {
+   HEAP16[i5 >> 1] = i8 | 2;
+   HEAPF32[i6 + 144 >> 2] = 0.0;
+  }
+ } else {
+  i7 = HEAP32[i1 + 52 >> 2] | 0;
+ }
+ i4 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 4 >> 2] | 0;
+ i5 = HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 4 >> 2] | 0;
+ if ((i4 | 0) > -1 & (i5 | 0) < 4) {
+  FUNCTION_TABLE_vii[HEAP32[4008 + (i4 * 48 | 0) + (i5 * 12 | 0) + 4 >> 2] & 15](i1, i2);
+  STACKTOP = i3;
+  return;
+ } else {
+  ___assert_fail(4384, 4256, 114, 4376);
+ }
+}
+function __ZN9b2Fixture13CreateProxiesEP12b2BroadPhaseRK11b2Transform(i5, i4, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ i3 = i5 + 28 | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 0) {
+  ___assert_fail(2088, 2112, 124, 2144);
+ }
+ i6 = i5 + 12 | 0;
+ i8 = HEAP32[i6 >> 2] | 0;
+ i8 = FUNCTION_TABLE_ii[HEAP32[(HEAP32[i8 >> 2] | 0) + 12 >> 2] & 3](i8) | 0;
+ HEAP32[i3 >> 2] = i8;
+ if ((i8 | 0) <= 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = i5 + 24 | 0;
+ i8 = 0;
+ do {
+  i9 = HEAP32[i7 >> 2] | 0;
+  i10 = i9 + (i8 * 28 | 0) | 0;
+  i11 = HEAP32[i6 >> 2] | 0;
+  FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i11 >> 2] | 0) + 24 >> 2] & 15](i11, i10, i1, i8);
+  HEAP32[i9 + (i8 * 28 | 0) + 24 >> 2] = __ZN12b2BroadPhase11CreateProxyERK6b2AABBPv(i4, i10, i10) | 0;
+  HEAP32[i9 + (i8 * 28 | 0) + 16 >> 2] = i5;
+  HEAP32[i9 + (i8 * 28 | 0) + 20 >> 2] = i8;
+  i8 = i8 + 1 | 0;
+ } while ((i8 | 0) < (HEAP32[i3 >> 2] | 0));
+ STACKTOP = i2;
+ return;
+}
+function __ZNK10__cxxabiv117__class_type_info9can_catchEPKNS_16__shim_type_infoERPv(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i3 = i2;
+ if ((i1 | 0) == (i5 | 0)) {
+  i7 = 1;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ if ((i5 | 0) == 0) {
+  i7 = 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i5 = ___dynamic_cast(i5, 6952, 7008, 0) | 0;
+ if ((i5 | 0) == 0) {
+  i7 = 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i7 = i3 + 0 | 0;
+ i6 = i7 + 56 | 0;
+ do {
+  HEAP32[i7 >> 2] = 0;
+  i7 = i7 + 4 | 0;
+ } while ((i7 | 0) < (i6 | 0));
+ HEAP32[i3 >> 2] = i5;
+ HEAP32[i3 + 8 >> 2] = i1;
+ HEAP32[i3 + 12 >> 2] = -1;
+ HEAP32[i3 + 48 >> 2] = 1;
+ FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i5 >> 2] | 0) + 28 >> 2] & 15](i5, i3, HEAP32[i4 >> 2] | 0, 1);
+ if ((HEAP32[i3 + 24 >> 2] | 0) != 1) {
+  i7 = 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ HEAP32[i4 >> 2] = HEAP32[i3 + 16 >> 2];
+ i7 = 1;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function __ZN8b2IslandC2EiiiP16b2StackAllocatorP17b2ContactListener(i1, i4, i3, i2, i5, i6) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i7 = 0, i8 = 0;
+ i7 = STACKTOP;
+ i8 = i1 + 40 | 0;
+ HEAP32[i8 >> 2] = i4;
+ HEAP32[i1 + 44 >> 2] = i3;
+ HEAP32[i1 + 48 >> 2] = i2;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 36 >> 2] = 0;
+ HEAP32[i1 + 32 >> 2] = 0;
+ HEAP32[i1 >> 2] = i5;
+ HEAP32[i1 + 4 >> 2] = i6;
+ HEAP32[i1 + 8 >> 2] = __ZN16b2StackAllocator8AllocateEi(i5, i4 << 2) | 0;
+ HEAP32[i1 + 12 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i1 >> 2] | 0, i3 << 2) | 0;
+ HEAP32[i1 + 16 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i1 >> 2] | 0, i2 << 2) | 0;
+ HEAP32[i1 + 24 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i1 >> 2] | 0, (HEAP32[i8 >> 2] | 0) * 12 | 0) | 0;
+ HEAP32[i1 + 20 >> 2] = __ZN16b2StackAllocator8AllocateEi(HEAP32[i1 >> 2] | 0, (HEAP32[i8 >> 2] | 0) * 12 | 0) | 0;
+ STACKTOP = i7;
+ return;
+}
+function __ZNK11b2EdgeShape11ComputeAABBEP6b2AABBRK11b2Transformi(i8, i1, i10, i2) {
+ i8 = i8 | 0;
+ i1 = i1 | 0;
+ i10 = i10 | 0;
+ i2 = i2 | 0;
+ var d3 = 0.0, d4 = 0.0, d5 = 0.0, d6 = 0.0, d7 = 0.0, d9 = 0.0, d11 = 0.0, d12 = 0.0;
+ i2 = STACKTOP;
+ d7 = +HEAPF32[i10 + 12 >> 2];
+ d9 = +HEAPF32[i8 + 12 >> 2];
+ d11 = +HEAPF32[i10 + 8 >> 2];
+ d3 = +HEAPF32[i8 + 16 >> 2];
+ d6 = +HEAPF32[i10 >> 2];
+ d5 = d6 + (d7 * d9 - d11 * d3);
+ d12 = +HEAPF32[i10 + 4 >> 2];
+ d3 = d9 * d11 + d7 * d3 + d12;
+ d9 = +HEAPF32[i8 + 20 >> 2];
+ d4 = +HEAPF32[i8 + 24 >> 2];
+ d6 = d6 + (d7 * d9 - d11 * d4);
+ d4 = d12 + (d11 * d9 + d7 * d4);
+ d7 = +HEAPF32[i8 + 8 >> 2];
+ d9 = +((d5 < d6 ? d5 : d6) - d7);
+ d12 = +((d3 < d4 ? d3 : d4) - d7);
+ i10 = i1;
+ HEAPF32[i10 >> 2] = d9;
+ HEAPF32[i10 + 4 >> 2] = d12;
+ d5 = +(d7 + (d5 > d6 ? d5 : d6));
+ d12 = +(d7 + (d3 > d4 ? d3 : d4));
+ i10 = i1 + 8 | 0;
+ HEAPF32[i10 >> 2] = d5;
+ HEAPF32[i10 + 4 >> 2] = d12;
+ STACKTOP = i2;
+ return;
+}
+function __ZNK14b2PolygonShape9TestPointERK11b2TransformRK6b2Vec2(i2, i3, i6) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, d4 = 0.0, d5 = 0.0, i7 = 0, d8 = 0.0, d9 = 0.0, d10 = 0.0;
+ i1 = STACKTOP;
+ d8 = +HEAPF32[i6 >> 2] - +HEAPF32[i3 >> 2];
+ d9 = +HEAPF32[i6 + 4 >> 2] - +HEAPF32[i3 + 4 >> 2];
+ d10 = +HEAPF32[i3 + 12 >> 2];
+ d5 = +HEAPF32[i3 + 8 >> 2];
+ d4 = d8 * d10 + d9 * d5;
+ d5 = d10 * d9 - d8 * d5;
+ i3 = HEAP32[i2 + 148 >> 2] | 0;
+ if ((i3 | 0) > 0) {
+  i6 = 0;
+ } else {
+  i7 = 1;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ while (1) {
+  i7 = i6 + 1 | 0;
+  if ((d4 - +HEAPF32[i2 + (i6 << 3) + 20 >> 2]) * +HEAPF32[i2 + (i6 << 3) + 84 >> 2] + (d5 - +HEAPF32[i2 + (i6 << 3) + 24 >> 2]) * +HEAPF32[i2 + (i6 << 3) + 88 >> 2] > 0.0) {
+   i3 = 0;
+   i2 = 4;
+   break;
+  }
+  if ((i7 | 0) < (i3 | 0)) {
+   i6 = i7;
+  } else {
+   i3 = 1;
+   i2 = 4;
+   break;
+  }
+ }
+ if ((i2 | 0) == 4) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ return 0;
+}
+function __ZN16b2StackAllocator8AllocateEi(i4, i5) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i3 = i4 + 102796 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ if ((i6 | 0) >= 32) {
+  ___assert_fail(3896, 3808, 38, 3936);
+ }
+ i1 = i4 + (i6 * 12 | 0) + 102412 | 0;
+ HEAP32[i4 + (i6 * 12 | 0) + 102416 >> 2] = i5;
+ i7 = i4 + 102400 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 + i5 | 0) > 102400) {
+  HEAP32[i1 >> 2] = __Z7b2Alloci(i5) | 0;
+  HEAP8[i4 + (i6 * 12 | 0) + 102420 | 0] = 1;
+ } else {
+  HEAP32[i1 >> 2] = i4 + i8;
+  HEAP8[i4 + (i6 * 12 | 0) + 102420 | 0] = 0;
+  HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + i5;
+ }
+ i6 = i4 + 102404 | 0;
+ i5 = (HEAP32[i6 >> 2] | 0) + i5 | 0;
+ HEAP32[i6 >> 2] = i5;
+ i4 = i4 + 102408 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = (i6 | 0) > (i5 | 0) ? i6 : i5;
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return HEAP32[i1 >> 2] | 0;
+}
+function __ZN12b2BroadPhase13QueryCallbackEi(i5, i1) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i4 = i5 + 56 | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ if ((i7 | 0) == (i1 | 0)) {
+  STACKTOP = i2;
+  return 1;
+ }
+ i3 = i5 + 52 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i8 = i5 + 48 | 0;
+ i5 = i5 + 44 | 0;
+ if ((i6 | 0) == (HEAP32[i8 >> 2] | 0)) {
+  i7 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 << 1;
+  i6 = __Z7b2Alloci(i6 * 24 | 0) | 0;
+  HEAP32[i5 >> 2] = i6;
+  _memcpy(i6 | 0, i7 | 0, (HEAP32[i3 >> 2] | 0) * 12 | 0) | 0;
+  __Z6b2FreePv(i7);
+  i7 = HEAP32[i4 >> 2] | 0;
+  i6 = HEAP32[i3 >> 2] | 0;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 + (i6 * 12 | 0) >> 2] = (i7 | 0) > (i1 | 0) ? i1 : i7;
+ i4 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i5 + ((HEAP32[i3 >> 2] | 0) * 12 | 0) + 4 >> 2] = (i4 | 0) < (i1 | 0) ? i1 : i4;
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return 1;
+}
+function __ZNK10__cxxabiv120__si_class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi(i5, i4, i3, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i6 = 0;
+ i2 = STACKTOP;
+ if ((i5 | 0) != (HEAP32[i4 + 8 >> 2] | 0)) {
+  i6 = HEAP32[i5 + 8 >> 2] | 0;
+  FUNCTION_TABLE_viiii[HEAP32[(HEAP32[i6 >> 2] | 0) + 28 >> 2] & 15](i6, i4, i3, i1);
+  STACKTOP = i2;
+  return;
+ }
+ i5 = i4 + 16 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i5 >> 2] = i3;
+  HEAP32[i4 + 24 >> 2] = i1;
+  HEAP32[i4 + 36 >> 2] = 1;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i6 | 0) != (i3 | 0)) {
+  i6 = i4 + 36 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+  HEAP32[i4 + 24 >> 2] = 2;
+  HEAP8[i4 + 54 | 0] = 1;
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i4 + 24 | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 2) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i3 >> 2] = i1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN6b2Body19SynchronizeFixturesEv(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, d6 = 0.0, d7 = 0.0, d8 = 0.0, d9 = 0.0, d10 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ d8 = +HEAPF32[i5 + 52 >> 2];
+ d9 = +Math_sin(+d8);
+ HEAPF32[i3 + 8 >> 2] = d9;
+ d8 = +Math_cos(+d8);
+ HEAPF32[i3 + 12 >> 2] = d8;
+ d10 = +HEAPF32[i5 + 28 >> 2];
+ d6 = +HEAPF32[i5 + 32 >> 2];
+ d7 = +(+HEAPF32[i5 + 36 >> 2] - (d8 * d10 - d9 * d6));
+ d6 = +(+HEAPF32[i5 + 40 >> 2] - (d10 * d9 + d8 * d6));
+ i2 = i3;
+ HEAPF32[i2 >> 2] = d7;
+ HEAPF32[i2 + 4 >> 2] = d6;
+ i2 = (HEAP32[i5 + 88 >> 2] | 0) + 102872 | 0;
+ i4 = HEAP32[i5 + 100 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i5 + 12 | 0;
+ do {
+  __ZN9b2Fixture11SynchronizeEP12b2BroadPhaseRK11b2TransformS4_(i4, i2, i3, i5);
+  i4 = HEAP32[i4 + 4 >> 2] | 0;
+ } while ((i4 | 0) != 0);
+ STACKTOP = i1;
+ return;
+}
+function __ZN13b2DynamicTreeC2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i4 = STACKTOP;
+ HEAP32[i1 >> 2] = -1;
+ i3 = i1 + 12 | 0;
+ HEAP32[i3 >> 2] = 16;
+ HEAP32[i1 + 8 >> 2] = 0;
+ i6 = __Z7b2Alloci(576) | 0;
+ i2 = i1 + 4 | 0;
+ HEAP32[i2 >> 2] = i6;
+ _memset(i6 | 0, 0, (HEAP32[i3 >> 2] | 0) * 36 | 0) | 0;
+ i6 = (HEAP32[i3 >> 2] | 0) + -1 | 0;
+ i2 = HEAP32[i2 >> 2] | 0;
+ if ((i6 | 0) > 0) {
+  i6 = 0;
+  while (1) {
+   i5 = i6 + 1 | 0;
+   HEAP32[i2 + (i6 * 36 | 0) + 20 >> 2] = i5;
+   HEAP32[i2 + (i6 * 36 | 0) + 32 >> 2] = -1;
+   i6 = (HEAP32[i3 >> 2] | 0) + -1 | 0;
+   if ((i5 | 0) < (i6 | 0)) {
+    i6 = i5;
+   } else {
+    break;
+   }
+  }
+ }
+ HEAP32[i2 + (i6 * 36 | 0) + 20 >> 2] = -1;
+ HEAP32[i2 + (((HEAP32[i3 >> 2] | 0) + -1 | 0) * 36 | 0) + 32 >> 2] = -1;
+ HEAP32[i1 + 16 >> 2] = 0;
+ HEAP32[i1 + 20 >> 2] = 0;
+ HEAP32[i1 + 24 >> 2] = 0;
+ STACKTOP = i4;
+ return;
+}
+function __Z7measurePl(i1, i9) {
+ i1 = i1 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0, i7 = 0, d8 = 0.0, i10 = 0, d11 = 0.0;
+ i2 = STACKTOP;
+ i3 = HEAP32[4] | 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + ((4 * i3 | 0) + 15 & -16) | 0;
+ i7 = (i3 | 0) > 0;
+ if (i7) {
+  i10 = 0;
+  d6 = 0.0;
+  do {
+   d8 = +(HEAP32[i9 + (i10 << 2) >> 2] | 0) / 1.0e6 * 1.0e3;
+   HEAPF32[i4 + (i10 << 2) >> 2] = d8;
+   d6 = d6 + d8;
+   i10 = i10 + 1 | 0;
+  } while ((i10 | 0) < (i3 | 0));
+  d5 = +(i3 | 0);
+  d6 = d6 / d5;
+  HEAPF32[i1 >> 2] = d6;
+  if (i7) {
+   i7 = 0;
+   d8 = 0.0;
+   do {
+    d11 = +HEAPF32[i4 + (i7 << 2) >> 2] - d6;
+    d8 = d8 + d11 * d11;
+    i7 = i7 + 1 | 0;
+   } while ((i7 | 0) < (i3 | 0));
+  } else {
+   d8 = 0.0;
+  }
+ } else {
+  d5 = +(i3 | 0);
+  HEAPF32[i1 >> 2] = 0.0 / d5;
+  d8 = 0.0;
+ }
+ HEAPF32[i1 + 4 >> 2] = +Math_sqrt(+(d8 / d5));
+ STACKTOP = i2;
+ return;
+}
+function __ZN13b2DynamicTree11CreateProxyERK6b2AABBPv(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i4 = 0, i5 = 0, i6 = 0, d7 = 0.0, d8 = 0.0, i9 = 0;
+ i5 = STACKTOP;
+ i4 = __ZN13b2DynamicTree12AllocateNodeEv(i1) | 0;
+ i6 = i1 + 4 | 0;
+ d7 = +(+HEAPF32[i3 >> 2] + -.10000000149011612);
+ d8 = +(+HEAPF32[i3 + 4 >> 2] + -.10000000149011612);
+ i9 = (HEAP32[i6 >> 2] | 0) + (i4 * 36 | 0) | 0;
+ HEAPF32[i9 >> 2] = d7;
+ HEAPF32[i9 + 4 >> 2] = d8;
+ d8 = +(+HEAPF32[i3 + 8 >> 2] + .10000000149011612);
+ d7 = +(+HEAPF32[i3 + 12 >> 2] + .10000000149011612);
+ i3 = (HEAP32[i6 >> 2] | 0) + (i4 * 36 | 0) + 8 | 0;
+ HEAPF32[i3 >> 2] = d8;
+ HEAPF32[i3 + 4 >> 2] = d7;
+ HEAP32[(HEAP32[i6 >> 2] | 0) + (i4 * 36 | 0) + 16 >> 2] = i2;
+ HEAP32[(HEAP32[i6 >> 2] | 0) + (i4 * 36 | 0) + 32 >> 2] = 0;
+ __ZN13b2DynamicTree10InsertLeafEi(i1, i4);
+ STACKTOP = i5;
+ return i4 | 0;
+}
+function __ZN16b2BlockAllocatorC2Ev(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i4 = i3 + 8 | 0;
+ HEAP32[i4 >> 2] = 128;
+ HEAP32[i3 + 4 >> 2] = 0;
+ i5 = __Z7b2Alloci(1024) | 0;
+ HEAP32[i3 >> 2] = i5;
+ _memset(i5 | 0, 0, HEAP32[i4 >> 2] << 3 | 0) | 0;
+ i4 = i3 + 12 | 0;
+ i3 = i4 + 56 | 0;
+ do {
+  HEAP32[i4 >> 2] = 0;
+  i4 = i4 + 4 | 0;
+ } while ((i4 | 0) < (i3 | 0));
+ if ((HEAP8[1280] | 0) == 0) {
+  i3 = 1;
+  i4 = 0;
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  if ((i4 | 0) >= 14) {
+   i1 = 3;
+   break;
+  }
+  if ((i3 | 0) > (HEAP32[576 + (i4 << 2) >> 2] | 0)) {
+   i4 = i4 + 1 | 0;
+   HEAP8[632 + i3 | 0] = i4;
+  } else {
+   HEAP8[632 + i3 | 0] = i4;
+  }
+  i3 = i3 + 1 | 0;
+ } while ((i3 | 0) < 641);
+ if ((i1 | 0) == 3) {
+  ___assert_fail(1288, 1312, 73, 1352);
+ }
+ HEAP8[1280] = 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN24b2ChainAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i6 = i5;
+ i7 = HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0;
+ HEAP32[i6 >> 2] = 240;
+ HEAP32[i6 + 4 >> 2] = 1;
+ HEAPF32[i6 + 8 >> 2] = .009999999776482582;
+ i8 = i6 + 28 | 0;
+ HEAP32[i8 + 0 >> 2] = 0;
+ HEAP32[i8 + 4 >> 2] = 0;
+ HEAP32[i8 + 8 >> 2] = 0;
+ HEAP32[i8 + 12 >> 2] = 0;
+ HEAP16[i8 + 16 >> 1] = 0;
+ __ZNK12b2ChainShape12GetChildEdgeEP11b2EdgeShapei(i7, i6, HEAP32[i2 + 56 >> 2] | 0);
+ __Z23b2CollideEdgeAndPolygonP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS6_(i4, i6, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN23b2ChainAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i6 = i5;
+ i7 = HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0;
+ HEAP32[i6 >> 2] = 240;
+ HEAP32[i6 + 4 >> 2] = 1;
+ HEAPF32[i6 + 8 >> 2] = .009999999776482582;
+ i8 = i6 + 28 | 0;
+ HEAP32[i8 + 0 >> 2] = 0;
+ HEAP32[i8 + 4 >> 2] = 0;
+ HEAP32[i8 + 8 >> 2] = 0;
+ HEAP32[i8 + 12 >> 2] = 0;
+ HEAP16[i8 + 16 >> 1] = 0;
+ __ZNK12b2ChainShape12GetChildEdgeEP11b2EdgeShapei(i7, i6, HEAP32[i2 + 56 >> 2] | 0);
+ __Z22b2CollideEdgeAndCircleP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK13b2CircleShapeS6_(i4, i6, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN15b2ContactSolver13StoreImpulsesEv(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i4 + 48 >> 2] | 0;
+ if ((i2 | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = HEAP32[i4 + 40 >> 2] | 0;
+ i4 = HEAP32[i4 + 44 >> 2] | 0;
+ i5 = 0;
+ do {
+  i6 = HEAP32[i4 + (HEAP32[i3 + (i5 * 152 | 0) + 148 >> 2] << 2) >> 2] | 0;
+  i7 = HEAP32[i3 + (i5 * 152 | 0) + 144 >> 2] | 0;
+  if ((i7 | 0) > 0) {
+   i8 = 0;
+   do {
+    HEAPF32[i6 + (i8 * 20 | 0) + 72 >> 2] = +HEAPF32[i3 + (i5 * 152 | 0) + (i8 * 36 | 0) + 16 >> 2];
+    HEAPF32[i6 + (i8 * 20 | 0) + 76 >> 2] = +HEAPF32[i3 + (i5 * 152 | 0) + (i8 * 36 | 0) + 20 >> 2];
+    i8 = i8 + 1 | 0;
+   } while ((i8 | 0) < (i7 | 0));
+  }
+  i5 = i5 + 1 | 0;
+ } while ((i5 | 0) < (i2 | 0));
+ STACKTOP = i1;
+ return;
+}
+function __ZN16b2StackAllocator4FreeEPv(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i2 = i1 + 102796 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((i4 | 0) <= 0) {
+  ___assert_fail(3952, 3808, 63, 3976);
+ }
+ i6 = i4 + -1 | 0;
+ if ((HEAP32[i1 + (i6 * 12 | 0) + 102412 >> 2] | 0) != (i5 | 0)) {
+  ___assert_fail(3984, 3808, 65, 3976);
+ }
+ if ((HEAP8[i1 + (i6 * 12 | 0) + 102420 | 0] | 0) == 0) {
+  i5 = i1 + (i6 * 12 | 0) + 102416 | 0;
+  i6 = i1 + 102400 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) - (HEAP32[i5 >> 2] | 0);
+ } else {
+  __Z6b2FreePv(i5);
+  i5 = i1 + (i6 * 12 | 0) + 102416 | 0;
+  i4 = HEAP32[i2 >> 2] | 0;
+ }
+ i6 = i1 + 102404 | 0;
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) - (HEAP32[i5 >> 2] | 0);
+ HEAP32[i2 >> 2] = i4 + -1;
+ STACKTOP = i3;
+ return;
+}
+function __ZNK10__cxxabiv117__class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi(i5, i4, i3, i2) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i6 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i4 + 8 >> 2] | 0) != (i5 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i4 + 16 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i5 >> 2] = i3;
+  HEAP32[i4 + 24 >> 2] = i2;
+  HEAP32[i4 + 36 >> 2] = 1;
+  STACKTOP = i1;
+  return;
+ }
+ if ((i6 | 0) != (i3 | 0)) {
+  i6 = i4 + 36 | 0;
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+  HEAP32[i4 + 24 >> 2] = 2;
+  HEAP8[i4 + 54 | 0] = 1;
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i4 + 24 | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 2) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i3 >> 2] = i2;
+ STACKTOP = i1;
+ return;
+}
+function __ZN12b2BroadPhase11CreateProxyERK6b2AABBPv(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i3 = __ZN13b2DynamicTree11CreateProxyERK6b2AABBPv(i2, i4, i3) | 0;
+ i4 = i2 + 28 | 0;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 1;
+ i4 = i2 + 40 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ i6 = i2 + 36 | 0;
+ i2 = i2 + 32 | 0;
+ if ((i5 | 0) == (HEAP32[i6 >> 2] | 0)) {
+  i7 = HEAP32[i2 >> 2] | 0;
+  HEAP32[i6 >> 2] = i5 << 1;
+  i5 = __Z7b2Alloci(i5 << 3) | 0;
+  HEAP32[i2 >> 2] = i5;
+  _memcpy(i5 | 0, i7 | 0, HEAP32[i4 >> 2] << 2 | 0) | 0;
+  __Z6b2FreePv(i7);
+  i5 = HEAP32[i4 >> 2] | 0;
+ }
+ HEAP32[(HEAP32[i2 >> 2] | 0) + (i5 << 2) >> 2] = i3;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 1;
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function __ZN9b2ContactC2EP9b2FixtureiS1_i(i1, i4, i6, i3, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i7 = 0, d8 = 0.0, d9 = 0.0;
+ i2 = STACKTOP;
+ HEAP32[i1 >> 2] = 4440;
+ HEAP32[i1 + 4 >> 2] = 4;
+ HEAP32[i1 + 48 >> 2] = i4;
+ HEAP32[i1 + 52 >> 2] = i3;
+ HEAP32[i1 + 56 >> 2] = i6;
+ HEAP32[i1 + 60 >> 2] = i5;
+ HEAP32[i1 + 124 >> 2] = 0;
+ HEAP32[i1 + 128 >> 2] = 0;
+ i5 = i4 + 16 | 0;
+ i6 = i1 + 8 | 0;
+ i7 = i6 + 40 | 0;
+ do {
+  HEAP32[i6 >> 2] = 0;
+  i6 = i6 + 4 | 0;
+ } while ((i6 | 0) < (i7 | 0));
+ HEAPF32[i1 + 136 >> 2] = +Math_sqrt(+(+HEAPF32[i5 >> 2] * +HEAPF32[i3 + 16 >> 2]));
+ d8 = +HEAPF32[i4 + 20 >> 2];
+ d9 = +HEAPF32[i3 + 20 >> 2];
+ HEAPF32[i1 + 140 >> 2] = d8 > d9 ? d8 : d9;
+ STACKTOP = i2;
+ return;
+}
+function __ZN12b2BroadPhase9MoveProxyEiRK6b2AABBRK6b2Vec2(i3, i1, i5, i4) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ if (!(__ZN13b2DynamicTree9MoveProxyEiRK6b2AABBRK6b2Vec2(i3, i1, i5, i4) | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i3 + 40 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ i6 = i3 + 36 | 0;
+ i3 = i3 + 32 | 0;
+ if ((i5 | 0) == (HEAP32[i6 >> 2] | 0)) {
+  i7 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i6 >> 2] = i5 << 1;
+  i5 = __Z7b2Alloci(i5 << 3) | 0;
+  HEAP32[i3 >> 2] = i5;
+  _memcpy(i5 | 0, i7 | 0, HEAP32[i4 >> 2] << 2 | 0) | 0;
+  __Z6b2FreePv(i7);
+  i5 = HEAP32[i4 >> 2] | 0;
+ }
+ HEAP32[(HEAP32[i3 >> 2] | 0) + (i5 << 2) >> 2] = i1;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN24b2ChainAndPolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i3, i4, i5, i6) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i6 = __ZN16b2BlockAllocator8AllocateEi(i6, 144) | 0;
+ if ((i6 | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i6, i1, i3, i4, i5);
+ HEAP32[i6 >> 2] = 6032;
+ if ((HEAP32[(HEAP32[(HEAP32[i6 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 3) {
+  ___assert_fail(6048, 6096, 43, 6152);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i6 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 2) {
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  ___assert_fail(6184, 6096, 44, 6152);
+ }
+ return 0;
+}
+function __ZN23b2ChainAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i3, i4, i5, i6) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i6 = __ZN16b2BlockAllocator8AllocateEi(i6, 144) | 0;
+ if ((i6 | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i6, i1, i3, i4, i5);
+ HEAP32[i6 >> 2] = 5784;
+ if ((HEAP32[(HEAP32[(HEAP32[i6 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 3) {
+  ___assert_fail(5800, 5848, 43, 5904);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i6 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  ___assert_fail(5928, 5848, 44, 5904);
+ }
+ return 0;
+}
+function __ZN25b2PolygonAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 4984;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 2) {
+  ___assert_fail(5e3, 5048, 41, 5104);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(5136, 5048, 42, 5104);
+ }
+ return 0;
+}
+function __ZN23b2EdgeAndPolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 4736;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 1) {
+  ___assert_fail(4752, 4800, 41, 4856);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 2) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(4880, 4800, 42, 4856);
+ }
+ return 0;
+}
+function __ZN22b2EdgeAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 4488;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 1) {
+  ___assert_fail(4504, 4552, 41, 4608);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(4632, 4552, 42, 4608);
+ }
+ return 0;
+}
+function __ZN14b2PolygonShape8SetAsBoxEff(i1, d3, d2) {
+ i1 = i1 | 0;
+ d3 = +d3;
+ d2 = +d2;
+ var d4 = 0.0, d5 = 0.0;
+ HEAP32[i1 + 148 >> 2] = 4;
+ d4 = -d3;
+ d5 = -d2;
+ HEAPF32[i1 + 20 >> 2] = d4;
+ HEAPF32[i1 + 24 >> 2] = d5;
+ HEAPF32[i1 + 28 >> 2] = d3;
+ HEAPF32[i1 + 32 >> 2] = d5;
+ HEAPF32[i1 + 36 >> 2] = d3;
+ HEAPF32[i1 + 40 >> 2] = d2;
+ HEAPF32[i1 + 44 >> 2] = d4;
+ HEAPF32[i1 + 48 >> 2] = d2;
+ HEAPF32[i1 + 84 >> 2] = 0.0;
+ HEAPF32[i1 + 88 >> 2] = -1.0;
+ HEAPF32[i1 + 92 >> 2] = 1.0;
+ HEAPF32[i1 + 96 >> 2] = 0.0;
+ HEAPF32[i1 + 100 >> 2] = 0.0;
+ HEAPF32[i1 + 104 >> 2] = 1.0;
+ HEAPF32[i1 + 108 >> 2] = -1.0;
+ HEAPF32[i1 + 112 >> 2] = 0.0;
+ HEAPF32[i1 + 12 >> 2] = 0.0;
+ HEAPF32[i1 + 16 >> 2] = 0.0;
+ return;
+}
+function __ZN16b2PolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 5240;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 2) {
+  ___assert_fail(5256, 5304, 44, 5352);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 2) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(5376, 5304, 45, 5352);
+ }
+ return 0;
+}
+function __ZN15b2CircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator(i1, i4, i2, i5, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 144) | 0;
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i4;
+  return i5 | 0;
+ }
+ __ZN9b2ContactC2EP9b2FixtureiS1_i(i3, i1, 0, i2, 0);
+ HEAP32[i3 >> 2] = 6288;
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) != 0) {
+  ___assert_fail(6304, 6352, 44, 6400);
+ }
+ if ((HEAP32[(HEAP32[(HEAP32[i3 + 52 >> 2] | 0) + 12 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+  i5 = i3;
+  STACKTOP = i4;
+  return i5 | 0;
+ } else {
+  ___assert_fail(6416, 6352, 45, 6400);
+ }
+ return 0;
+}
+function __ZN7b2World10CreateBodyEPK9b2BodyDef(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i1 + 102868 >> 2] & 2 | 0) != 0) {
+  ___assert_fail(2160, 2184, 109, 2216);
+ }
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i1, 152) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+ } else {
+  __ZN6b2BodyC2EPK9b2BodyDefP7b2World(i3, i4, i1);
+ }
+ HEAP32[i3 + 92 >> 2] = 0;
+ i4 = i1 + 102952 | 0;
+ HEAP32[i3 + 96 >> 2] = HEAP32[i4 >> 2];
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  HEAP32[i5 + 92 >> 2] = i3;
+ }
+ HEAP32[i4 >> 2] = i3;
+ i5 = i1 + 102960 | 0;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function __ZNK6b2Body13ShouldCollideEPKS_(i4, i2) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i4 >> 2] | 0) != 2 ? (HEAP32[i2 >> 2] | 0) != 2 : 0) {
+  i2 = 0;
+ } else {
+  i3 = 3;
+ }
+ L3 : do {
+  if ((i3 | 0) == 3) {
+   i3 = HEAP32[i4 + 108 >> 2] | 0;
+   if ((i3 | 0) == 0) {
+    i2 = 1;
+   } else {
+    while (1) {
+     if ((HEAP32[i3 >> 2] | 0) == (i2 | 0) ? (HEAP8[(HEAP32[i3 + 4 >> 2] | 0) + 61 | 0] | 0) == 0 : 0) {
+      i2 = 0;
+      break L3;
+     }
+     i3 = HEAP32[i3 + 12 >> 2] | 0;
+     if ((i3 | 0) == 0) {
+      i2 = 1;
+      break;
+     }
+    }
+   }
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function __ZNK14b2PolygonShape5CloneEP16b2BlockAllocator(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i3 = __ZN16b2BlockAllocator8AllocateEi(i3, 152) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+ } else {
+  HEAP32[i3 >> 2] = 504;
+  HEAP32[i3 + 4 >> 2] = 2;
+  HEAPF32[i3 + 8 >> 2] = .009999999776482582;
+  HEAP32[i3 + 148 >> 2] = 0;
+  HEAPF32[i3 + 12 >> 2] = 0.0;
+  HEAPF32[i3 + 16 >> 2] = 0.0;
+ }
+ i6 = i1 + 4 | 0;
+ i5 = HEAP32[i6 + 4 >> 2] | 0;
+ i4 = i3 + 4 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i4 + 4 >> 2] = i5;
+ _memcpy(i3 + 12 | 0, i1 + 12 | 0, 140) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function __ZN7b2World16SetAllowSleepingEb(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = i2 + 102976 | 0;
+ if ((i4 & 1 | 0) == (HEAPU8[i3] | 0 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP8[i3] = i4 & 1;
+ if (i4) {
+  STACKTOP = i1;
+  return;
+ }
+ i2 = HEAP32[i2 + 102952 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  i3 = i2 + 4 | 0;
+  i4 = HEAPU16[i3 >> 1] | 0;
+  if ((i4 & 2 | 0) == 0) {
+   HEAP16[i3 >> 1] = i4 | 2;
+   HEAPF32[i2 + 144 >> 2] = 0.0;
+  }
+  i2 = HEAP32[i2 + 96 >> 2] | 0;
+ } while ((i2 | 0) != 0);
+ STACKTOP = i1;
+ return;
+}
+function __ZN16b2BlockAllocator4FreeEPvi(i3, i1, i4) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i4 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((i4 | 0) <= 0) {
+  ___assert_fail(1376, 1312, 164, 1488);
+ }
+ if ((i4 | 0) > 640) {
+  __Z6b2FreePv(i1);
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP8[632 + i4 | 0] | 0;
+ if (!((i4 & 255) < 14)) {
+  ___assert_fail(1408, 1312, 173, 1488);
+ }
+ i4 = i3 + ((i4 & 255) << 2) + 12 | 0;
+ HEAP32[i1 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i4 >> 2] = i1;
+ STACKTOP = i2;
+ return;
+}
+function __ZN15b2ContactFilter13ShouldCollideEP9b2FixtureS1_(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ i3 = STACKTOP;
+ i4 = HEAP16[i2 + 36 >> 1] | 0;
+ if (!(i4 << 16 >> 16 != (HEAP16[i1 + 36 >> 1] | 0) | i4 << 16 >> 16 == 0)) {
+  i4 = i4 << 16 >> 16 > 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ if ((HEAP16[i1 + 32 >> 1] & HEAP16[i2 + 34 >> 1]) << 16 >> 16 == 0) {
+  i4 = 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ i4 = (HEAP16[i1 + 34 >> 1] & HEAP16[i2 + 32 >> 1]) << 16 >> 16 != 0;
+ STACKTOP = i3;
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function __ZN6b2Body13CreateFixtureEPK7b2Shapef(i1, i3, d2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ d2 = +d2;
+ var i4 = 0, i5 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i5 = i4;
+ HEAP16[i5 + 22 >> 1] = 1;
+ HEAP16[i5 + 24 >> 1] = -1;
+ HEAP16[i5 + 26 >> 1] = 0;
+ HEAP32[i5 + 4 >> 2] = 0;
+ HEAPF32[i5 + 8 >> 2] = .20000000298023224;
+ HEAPF32[i5 + 12 >> 2] = 0.0;
+ HEAP8[i5 + 20 | 0] = 0;
+ HEAP32[i5 >> 2] = i3;
+ HEAPF32[i5 + 16 >> 2] = d2;
+ i3 = __ZN6b2Body13CreateFixtureEPK12b2FixtureDef(i1, i5) | 0;
+ STACKTOP = i4;
+ return i3 | 0;
+}
+function __Znwj(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i2 = (i2 | 0) == 0 ? 1 : i2;
+ while (1) {
+  i3 = _malloc(i2) | 0;
+  if ((i3 | 0) != 0) {
+   i2 = 6;
+   break;
+  }
+  i3 = HEAP32[1914] | 0;
+  HEAP32[1914] = i3 + 0;
+  if ((i3 | 0) == 0) {
+   i2 = 5;
+   break;
+  }
+  FUNCTION_TABLE_v[i3 & 3]();
+ }
+ if ((i2 | 0) == 5) {
+  i3 = ___cxa_allocate_exception(4) | 0;
+  HEAP32[i3 >> 2] = 7672;
+  ___cxa_throw(i3 | 0, 7720, 30);
+ } else if ((i2 | 0) == 6) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ return 0;
+}
+function __ZN8b2IslandD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 20 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 24 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 16 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 12 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i1 >> 2] | 0, HEAP32[i1 + 8 >> 2] | 0);
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2BlockAllocatorD2Ev(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i3 = i2 + 4 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((HEAP32[i3 >> 2] | 0) > 0) {
+  i5 = 0;
+ } else {
+  i5 = i4;
+  __Z6b2FreePv(i5);
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  __Z6b2FreePv(HEAP32[i4 + (i5 << 3) + 4 >> 2] | 0);
+  i5 = i5 + 1 | 0;
+  i4 = HEAP32[i2 >> 2] | 0;
+ } while ((i5 | 0) < (HEAP32[i3 >> 2] | 0));
+ __Z6b2FreePv(i4);
+ STACKTOP = i1;
+ return;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function __ZNK11b2EdgeShape11ComputeMassEP10b2MassDataf(i2, i1, d3) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ d3 = +d3;
+ var i4 = 0, d5 = 0.0;
+ i4 = STACKTOP;
+ HEAPF32[i1 >> 2] = 0.0;
+ d5 = +((+HEAPF32[i2 + 12 >> 2] + +HEAPF32[i2 + 20 >> 2]) * .5);
+ d3 = +((+HEAPF32[i2 + 16 >> 2] + +HEAPF32[i2 + 24 >> 2]) * .5);
+ i2 = i1 + 4 | 0;
+ HEAPF32[i2 >> 2] = d5;
+ HEAPF32[i2 + 4 >> 2] = d3;
+ HEAPF32[i1 + 12 >> 2] = 0.0;
+ STACKTOP = i4;
+ return;
+}
+function __ZN11b2EdgeShape3SetERK6b2Vec2S2_(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i4 = 0, i5 = 0;
+ i5 = i3;
+ i3 = HEAP32[i5 + 4 >> 2] | 0;
+ i4 = i1 + 12 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i4 + 4 >> 2] = i3;
+ i4 = i2;
+ i2 = HEAP32[i4 + 4 >> 2] | 0;
+ i3 = i1 + 20 | 0;
+ HEAP32[i3 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i3 + 4 >> 2] = i2;
+ HEAP8[i1 + 44 | 0] = 0;
+ HEAP8[i1 + 45 | 0] = 0;
+ return;
+}
+function __ZN25b2PolygonAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z25b2CollidePolygonAndCircleP10b2ManifoldPK14b2PolygonShapeRK11b2TransformPK13b2CircleShapeS6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z23b2CollideEdgeAndPolygonP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN22b2EdgeAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z22b2CollideEdgeAndCircleP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK13b2CircleShapeS6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __Z23b2CollideEdgeAndPolygonP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS6_(i5, i4, i3, i2, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i6 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 256 | 0;
+ __ZN12b2EPCollider7CollideEP10b2ManifoldPK11b2EdgeShapeRK11b2TransformPK14b2PolygonShapeS7_(i6, i5, i4, i3, i2, i1);
+ STACKTOP = i6;
+ return;
+}
+function __ZN16b2PolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z17b2CollidePolygonsP10b2ManifoldPK14b2PolygonShapeRK11b2TransformS3_S6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __ZN15b2CircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_(i2, i4, i3, i1) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ __Z16b2CollideCirclesP10b2ManifoldPK13b2CircleShapeRK11b2TransformS3_S6_(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 12 >> 2] | 0, i3, HEAP32[(HEAP32[i2 + 52 >> 2] | 0) + 12 >> 2] | 0, i1);
+ STACKTOP = i5;
+ return;
+}
+function __Z14b2PairLessThanRK6b2PairS1_(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i2 >> 2] | 0;
+ i3 = HEAP32[i5 >> 2] | 0;
+ if ((i4 | 0) >= (i3 | 0)) {
+  if ((i4 | 0) == (i3 | 0)) {
+   i2 = (HEAP32[i2 + 4 >> 2] | 0) < (HEAP32[i5 + 4 >> 2] | 0);
+  } else {
+   i2 = 0;
+  }
+ } else {
+  i2 = 1;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function __ZN9b2FixtureC2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ HEAP16[i1 + 32 >> 1] = 1;
+ HEAP16[i1 + 34 >> 1] = -1;
+ HEAP16[i1 + 36 >> 1] = 0;
+ HEAP32[i1 + 40 >> 2] = 0;
+ HEAP32[i1 + 24 >> 2] = 0;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 0 >> 2] = 0;
+ HEAP32[i1 + 4 >> 2] = 0;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP32[i1 + 12 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZN12b2BroadPhaseC2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZN13b2DynamicTreeC2Ev(i1);
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 48 >> 2] = 16;
+ HEAP32[i1 + 52 >> 2] = 0;
+ HEAP32[i1 + 44 >> 2] = __Z7b2Alloci(192) | 0;
+ HEAP32[i1 + 36 >> 2] = 16;
+ HEAP32[i1 + 40 >> 2] = 0;
+ HEAP32[i1 + 32 >> 2] = __Z7b2Alloci(64) | 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2StackAllocatorD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i1 + 102400 >> 2] | 0) != 0) {
+  ___assert_fail(3792, 3808, 32, 3848);
+ }
+ if ((HEAP32[i1 + 102796 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ } else {
+  ___assert_fail(3872, 3808, 33, 3848);
+ }
+}
+function __ZN15b2ContactSolverD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 32 | 0;
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i3 >> 2] | 0, HEAP32[i1 + 40 >> 2] | 0);
+ __ZN16b2StackAllocator4FreeEPv(HEAP32[i3 >> 2] | 0, HEAP32[i1 + 36 >> 2] | 0);
+ STACKTOP = i2;
+ return;
+}
+function __ZN25b2PolygonAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN24b2ChainAndPolygonContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN23b2EdgeAndPolygonContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN23b2ChainAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN22b2EdgeAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN16b2ContactManagerC2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZN12b2BroadPhaseC2Ev(i1);
+ HEAP32[i1 + 60 >> 2] = 0;
+ HEAP32[i1 + 64 >> 2] = 0;
+ HEAP32[i1 + 68 >> 2] = 1888;
+ HEAP32[i1 + 72 >> 2] = 1896;
+ HEAP32[i1 + 76 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2PolygonContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function __ZN15b2CircleContact7DestroyEP9b2ContactP16b2BlockAllocator(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ FUNCTION_TABLE_vi[HEAP32[(HEAP32[i1 >> 2] | 0) + 4 >> 2] & 31](i1);
+ __ZN16b2BlockAllocator4FreeEPvi(i2, i1, 144);
+ STACKTOP = i3;
+ return;
+}
+function dynCall_viiiiii(i7, i6, i5, i4, i3, i2, i1) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_viiiiii[i7 & 3](i6 | 0, i5 | 0, i4 | 0, i3 | 0, i2 | 0, i1 | 0);
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function dynCall_iiiiii(i6, i5, i4, i3, i2, i1) {
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiiiii[i6 & 15](i5 | 0, i4 | 0, i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function dynCall_viiiii(i6, i5, i4, i3, i2, i1) {
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_viiiii[i6 & 3](i5 | 0, i4 | 0, i3 | 0, i2 | 0, i1 | 0);
+}
+function __ZN16b2ContactManager15FindNewContactsEv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZN12b2BroadPhase11UpdatePairsI16b2ContactManagerEEvPT_(i1, i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2StackAllocatorC2Ev(i1) {
+ i1 = i1 | 0;
+ HEAP32[i1 + 102400 >> 2] = 0;
+ HEAP32[i1 + 102404 >> 2] = 0;
+ HEAP32[i1 + 102408 >> 2] = 0;
+ HEAP32[i1 + 102796 >> 2] = 0;
+ return;
+}
+function dynCall_viiii(i5, i4, i3, i2, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_viiii[i5 & 15](i4 | 0, i3 | 0, i2 | 0, i1 | 0);
+}
+function dynCall_iiii(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiii[i4 & 7](i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function dynCall_viii(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_viii[i4 & 3](i3 | 0, i2 | 0, i1 | 0);
+}
+function __ZNSt9bad_allocD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZNSt9exceptionD2Ev(i1 | 0);
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function __ZN13b2DynamicTreeD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __Z6b2FreePv(HEAP32[i1 + 4 >> 2] | 0);
+ STACKTOP = i2;
+ return;
+}
+function dynCall_viid(i4, i3, i2, d1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ d1 = +d1;
+ FUNCTION_TABLE_viid[i4 & 3](i3 | 0, i2 | 0, +d1);
+}
+function __ZN17b2ContactListener9PostSolveEP9b2ContactPK16b2ContactImpulse(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ return;
+}
+function __ZN10__cxxabiv120__si_class_type_infoD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN10__cxxabiv117__class_type_infoD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZNSt9bad_allocD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZNSt9exceptionD2Ev(i1 | 0);
+ STACKTOP = i2;
+ return;
+}
+function dynCall_iii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iii[i3 & 3](i2 | 0, i1 | 0) | 0;
+}
+function b8(i1, i2, i3, i4, i5, i6) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ abort(8);
+}
+function __ZN25b2PolygonAndCircleContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN17b2ContactListener8PreSolveEP9b2ContactPK10b2Manifold(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ return;
+}
+function __ZN24b2ChainAndPolygonContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN23b2EdgeAndPolygonContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN23b2ChainAndCircleContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZNK11b2EdgeShape9TestPointERK11b2TransformRK6b2Vec2(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ return 0;
+}
+function __ZN22b2EdgeAndCircleContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZdlPv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i1 | 0) != 0) {
+  _free(i1);
+ }
+ STACKTOP = i2;
+ return;
+}
+function b10(i1, i2, i3, i4, i5) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ abort(10);
+ return 0;
+}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function __Z7b2Alloci(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _malloc(i1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function __ZN17b2ContactListenerD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN16b2PolygonContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function dynCall_vii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vii[i3 & 15](i2 | 0, i1 | 0);
+}
+function __ZN15b2ContactFilterD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN15b2CircleContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN14b2PolygonShapeD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __Znaj(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = __Znwj(i1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function __ZN11b2EdgeShapeD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function __ZN9b2ContactD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function b1(i1, i2, i3, i4, i5) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ abort(1);
+}
+function __Z6b2FreePv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _free(i1);
+ STACKTOP = i2;
+ return;
+}
+function ___clang_call_terminate(i1) {
+ i1 = i1 | 0;
+ ___cxa_begin_catch(i1 | 0) | 0;
+ __ZSt9terminatev();
+}
+function __ZN17b2ContactListener12BeginContactEP9b2Contact(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ return;
+}
+function dynCall_ii(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_ii[i2 & 3](i1 | 0) | 0;
+}
+function __ZN17b2ContactListener10EndContactEP9b2Contact(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ return;
+}
+function b11(i1, i2, i3, i4) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ abort(11);
+}
+function dynCall_vi(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vi[i2 & 31](i1 | 0);
+}
+function b0(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ abort(0);
+ return 0;
+}
+function __ZNK10__cxxabiv116__shim_type_info5noop2Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZNK10__cxxabiv116__shim_type_info5noop1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b5(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ abort(5);
+}
+function __ZNK14b2PolygonShape13GetChildCountEv(i1) {
+ i1 = i1 | 0;
+ return 1;
+}
+function __ZN10__cxxabiv116__shim_type_infoD2Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b7(i1, i2, d3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ d3 = +d3;
+ abort(7);
+}
+function __ZNK11b2EdgeShape13GetChildCountEv(i1) {
+ i1 = i1 | 0;
+ return 1;
+}
+function __ZNK7b2Timer15GetMillisecondsEv(i1) {
+ i1 = i1 | 0;
+ return 0.0;
+}
+function __ZN25b2PolygonAndCircleContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN24b2ChainAndPolygonContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b9(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(9);
+ return 0;
+}
+function __ZN23b2EdgeAndPolygonContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN23b2ChainAndCircleContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN22b2EdgeAndCircleContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function dynCall_v(i1) {
+ i1 = i1 | 0;
+ FUNCTION_TABLE_v[i1 & 3]();
+}
+function __ZNKSt9bad_alloc4whatEv(i1) {
+ i1 = i1 | 0;
+ return 7688;
+}
+function ___cxa_pure_virtual__wrapper() {
+ ___cxa_pure_virtual();
+}
+function __ZN17b2ContactListenerD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN16b2PolygonContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN15b2ContactFilterD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN15b2CircleContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN14b2PolygonShapeD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b3(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(3);
+}
+function runPostSets() {
+ HEAP32[1932] = __ZTISt9exception;
+}
+function __ZN11b2EdgeShapeD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZNSt9type_infoD2Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN7b2Timer5ResetEv(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function __ZN9b2ContactD1Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function __ZN7b2TimerC2Ev(i1) {
+ i1 = i1 | 0;
+ return;
+}
+function b4(i1) {
+ i1 = i1 | 0;
+ abort(4);
+ return 0;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+function b2(i1) {
+ i1 = i1 | 0;
+ abort(2);
+}
+function b6() {
+ abort(6);
+}
+
+// EMSCRIPTEN_END_FUNCS
+  var FUNCTION_TABLE_iiii = [b0,__ZNK11b2EdgeShape9TestPointERK11b2TransformRK6b2Vec2,__ZNK14b2PolygonShape9TestPointERK11b2TransformRK6b2Vec2,__ZN15b2ContactFilter13ShouldCollideEP9b2FixtureS1_,__ZNK10__cxxabiv117__class_type_info9can_catchEPKNS_16__shim_type_infoERPv,b0,b0,b0];
+  var FUNCTION_TABLE_viiiii = [b1,__ZNK10__cxxabiv117__class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib,__ZNK10__cxxabiv120__si_class_type_info16search_below_dstEPNS_19__dynamic_cast_infoEPKvib,b1];
+  var FUNCTION_TABLE_vi = [b2,__ZN11b2EdgeShapeD1Ev,__ZN11b2EdgeShapeD0Ev,__ZN14b2PolygonShapeD1Ev,__ZN14b2PolygonShapeD0Ev,__ZN17b2ContactListenerD1Ev,__ZN17b2ContactListenerD0Ev,__ZN15b2ContactFilterD1Ev,__ZN15b2ContactFilterD0Ev,__ZN9b2ContactD1Ev,__ZN9b2ContactD0Ev,__ZN22b2EdgeAndCircleContactD1Ev,__ZN22b2EdgeAndCircleContactD0Ev,__ZN23b2EdgeAndPolygonContactD1Ev,__ZN23b2EdgeAndPolygonContactD0Ev,__ZN25b2PolygonAndCircleContactD1Ev,__ZN25b2PolygonAndCircleContactD0Ev,__ZN16b2PolygonContactD1Ev,__ZN16b2PolygonContactD0Ev,__ZN23b2ChainAndCircleContactD1Ev,__ZN23b2ChainAndCircleContactD0Ev,__ZN24b2ChainAndPolygonContactD1Ev,__ZN24b2ChainAndPolygonContactD0Ev,__ZN15b2CircleContactD1Ev,__ZN15b2CircleContactD0Ev,__ZN10__cxxabiv116__shim_type_infoD2Ev,__ZN10__cxxabiv117__class_type_infoD0Ev,__ZNK10__cxxabiv116__shim_type_info5noop1Ev,__ZNK10__cxxabiv116__shim_type_info5noop2Ev
+  ,__ZN10__cxxabiv120__si_class_type_infoD0Ev,__ZNSt9bad_allocD2Ev,__ZNSt9bad_allocD0Ev];
+  var FUNCTION_TABLE_vii = [b3,__ZN17b2ContactListener12BeginContactEP9b2Contact,__ZN17b2ContactListener10EndContactEP9b2Contact,__ZN15b2CircleContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN25b2PolygonAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN16b2PolygonContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN22b2EdgeAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN23b2EdgeAndPolygonContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN23b2ChainAndCircleContact7DestroyEP9b2ContactP16b2BlockAllocator,__ZN24b2ChainAndPolygonContact7DestroyEP9b2ContactP16b2BlockAllocator,b3,b3,b3,b3,b3,b3];
+  var FUNCTION_TABLE_ii = [b4,__ZNK11b2EdgeShape13GetChildCountEv,__ZNK14b2PolygonShape13GetChildCountEv,__ZNKSt9bad_alloc4whatEv];
+  var FUNCTION_TABLE_viii = [b5,__ZN17b2ContactListener8PreSolveEP9b2ContactPK10b2Manifold,__ZN17b2ContactListener9PostSolveEP9b2ContactPK16b2ContactImpulse,b5];
+  var FUNCTION_TABLE_v = [b6,___cxa_pure_virtual__wrapper,__Z4iterv,b6];
+  var FUNCTION_TABLE_viid = [b7,__ZNK11b2EdgeShape11ComputeMassEP10b2MassDataf,__ZNK14b2PolygonShape11ComputeMassEP10b2MassDataf,b7];
+  var FUNCTION_TABLE_viiiiii = [b8,__ZNK10__cxxabiv117__class_type_info16search_above_dstEPNS_19__dynamic_cast_infoEPKvS4_ib,__ZNK10__cxxabiv120__si_class_type_info16search_above_dstEPNS_19__dynamic_cast_infoEPKvS4_ib,b8];
+  var FUNCTION_TABLE_iii = [b9,__ZNK11b2EdgeShape5CloneEP16b2BlockAllocator,__ZNK14b2PolygonShape5CloneEP16b2BlockAllocator,__Z14b2PairLessThanRK6b2PairS1_];
+  var FUNCTION_TABLE_iiiiii = [b10,__ZNK11b2EdgeShape7RayCastEP15b2RayCastOutputRK14b2RayCastInputRK11b2Transformi,__ZNK14b2PolygonShape7RayCastEP15b2RayCastOutputRK14b2RayCastInputRK11b2Transformi,__ZN15b2CircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN25b2PolygonAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN16b2PolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN22b2EdgeAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN23b2EdgeAndPolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN23b2ChainAndCircleContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,__ZN24b2ChainAndPolygonContact6CreateEP9b2FixtureiS1_iP16b2BlockAllocator,b10,b10,b10,b10,b10,b10];
+  var FUNCTION_TABLE_viiii = [b11,__ZNK11b2EdgeShape11ComputeAABBEP6b2AABBRK11b2Transformi,__ZNK14b2PolygonShape11ComputeAABBEP6b2AABBRK11b2Transformi,__ZN22b2EdgeAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN25b2PolygonAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN16b2PolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN23b2ChainAndCircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN24b2ChainAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZN15b2CircleContact8EvaluateEP10b2ManifoldRK11b2TransformS4_,__ZNK10__cxxabiv117__class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi,__ZNK10__cxxabiv120__si_class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi,b11,b11,b11,b11];
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_iiii: dynCall_iiii, dynCall_viiiii: dynCall_viiiii, dynCall_vi: dynCall_vi, dynCall_vii: dynCall_vii, dynCall_ii: dynCall_ii, dynCall_viii: dynCall_viii, dynCall_v: dynCall_v, dynCall_viid: dynCall_viid, dynCall_viiiiii: dynCall_viiiiii, dynCall_iii: dynCall_iii, dynCall_iiiiii: dynCall_iiiiii, dynCall_viiii: dynCall_viiii };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_iiii": invoke_iiii, "invoke_viiiii": invoke_viiiii, "invoke_vi": invoke_vi, "invoke_vii": invoke_vii, "invoke_ii": invoke_ii, "invoke_viii": invoke_viii, "invoke_v": invoke_v, "invoke_viid": invoke_viid, "invoke_viiiiii": invoke_viiiiii, "invoke_iii": invoke_iii, "invoke_iiiiii": invoke_iiiiii, "invoke_viiii": invoke_viiii, "___cxa_throw": ___cxa_throw, "_emscripten_run_script": _emscripten_run_script, "_cosf": _cosf, "_send": _send, "__ZSt9terminatev": __ZSt9terminatev, "__reallyNegative": __reallyNegative, "___cxa_is_number_type": ___cxa_is_number_type, "___assert_fail": ___assert_fail, "___cxa_allocate_exception": ___cxa_allocate_exception, "___cxa_find_matching_catch": ___cxa_find_matching_catch, "_fflush": _fflush, "_pwrite": _pwrite, "___setErrNo": ___setErrNo, "_sbrk": _sbrk, "___cxa_begin_catch": ___cxa_begin_catch, "_sinf": _sinf, "_fileno": _fileno, "___resumeException": ___resumeException, "__ZSt18uncaught_exceptionv": __ZSt18uncaught_exceptionv, "_sysconf": _sysconf, "_clock": _clock, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_puts": _puts, "_mkport": _mkport, "_floorf": _floorf, "_sqrtf": _sqrtf, "_write": _write, "_emscripten_set_main_loop": _emscripten_set_main_loop, "___errno_location": ___errno_location, "__ZNSt9exceptionD2Ev": __ZNSt9exceptionD2Ev, "_printf": _printf, "___cxa_does_inherit": ___cxa_does_inherit, "__exit": __exit, "_fputc": _fputc, "_abort": _abort, "_fwrite": _fwrite, "_time": _time, "_fprintf": _fprintf, "_emscripten_cancel_main_loop": _emscripten_cancel_main_loop, "__formatString": __formatString, "_fputs": _fputs, "_exit": _exit, "___cxa_pure_virtual": ___cxa_pure_virtual, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity, "__ZTISt9exception": __ZTISt9exception }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var dynCall_iiii = Module["dynCall_iiii"] = asm["dynCall_iiii"];
+var dynCall_viiiii = Module["dynCall_viiiii"] = asm["dynCall_viiiii"];
+var dynCall_vi = Module["dynCall_vi"] = asm["dynCall_vi"];
+var dynCall_vii = Module["dynCall_vii"] = asm["dynCall_vii"];
+var dynCall_ii = Module["dynCall_ii"] = asm["dynCall_ii"];
+var dynCall_viii = Module["dynCall_viii"] = asm["dynCall_viii"];
+var dynCall_v = Module["dynCall_v"] = asm["dynCall_v"];
+var dynCall_viid = Module["dynCall_viid"] = asm["dynCall_viid"];
+var dynCall_viiiiii = Module["dynCall_viiiiii"] = asm["dynCall_viiiiii"];
+var dynCall_iii = Module["dynCall_iii"] = asm["dynCall_iii"];
+var dynCall_iiiiii = Module["dynCall_iiiiii"] = asm["dynCall_iiiiii"];
+var dynCall_viiii = Module["dynCall_viiii"] = asm["dynCall_viiii"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/copy.js b/test/mjsunit/asm/embenchen/copy.js
new file mode 100644
index 0000000..bf8d177
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/copy.js
@@ -0,0 +1,5976 @@
+var EXPECTED_OUTPUT = 'sum:8930\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(27);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,115,117,109,58,37,100,10,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+    Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+    Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+    // just add the mouse delta to the current absolut mouse position
+    // FIXME: ideally this should be clamped against the canvas size and zero
+    Browser.mouseX += Browser.mouseMovementX;
+    Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+
+
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  Module["_memset"] = _memset;
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+  function _free() {
+  }
+  Module["_free"] = _free;
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _free=env._free;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _printf=env._printf;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var __reallyNegative=env.__reallyNegative;
+  var _fwrite=env._fwrite;
+  var _malloc=env._malloc;
+  var _mkport=env._mkport;
+  var _fprintf=env._fprintf;
+  var ___setErrNo=env.___setErrNo;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _fflush=env._fflush;
+  var _write=env._write;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 625;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 6250;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 12500;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 75;
+     break L1;
+    }
+   case 48:
+    {
+     i12 = 0;
+     STACKTOP = i1;
+     return i12 | 0;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i3 + -48;
+     _printf(8, i2 | 0) | 0;
+     i12 = -1;
+     STACKTOP = i1;
+     return i12 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 1250;
+ }
+ i4 = 0;
+ i12 = 0;
+ do {
+  i9 = (i4 | 0) % 10 | 0;
+  i5 = i9 + i4 | 0;
+  i6 = (i4 | 0) % 255 | 0;
+  i8 = (i4 | 0) % 15 | 0;
+  i10 = ((i4 | 0) % 120 | 0 | 0) % 1024 | 0;
+  i11 = ((i4 | 0) % 1024 | 0) + i4 | 0;
+  i5 = ((i5 | 0) % 1024 | 0) + i5 | 0;
+  i8 = ((i8 | 0) % 1024 | 0) + i8 | 0;
+  i6 = (((i6 | 0) % 1024 | 0) + i6 + i10 | 0) % 1024 | 0;
+  i7 = 0;
+  do {
+   i17 = i7 << 1;
+   i14 = (i7 | 0) % 120 | 0;
+   i18 = (i17 | 0) % 1024 | 0;
+   i19 = (i9 + i7 | 0) % 1024 | 0;
+   i16 = ((i7 | 0) % 255 | 0 | 0) % 1024 | 0;
+   i15 = (i7 | 0) % 1024 | 0;
+   i13 = ((i7 | 0) % 15 | 0 | 0) % 1024 | 0;
+   i12 = (((i19 + i18 + i16 + i10 + i15 + i13 + ((i11 + i19 | 0) % 1024 | 0) + ((i5 + i18 | 0) % 1024 | 0) + ((i18 + i17 + i16 | 0) % 1024 | 0) + i6 + ((i8 + i15 | 0) % 1024 | 0) + ((((i14 | 0) % 1024 | 0) + i14 + i13 | 0) % 1024 | 0) | 0) % 100 | 0) + i12 | 0) % 10240 | 0;
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) != 5e4);
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) < (i3 | 0));
+ HEAP32[i2 >> 2] = i12;
+ _printf(24, i2 | 0) | 0;
+ i19 = 0;
+ STACKTOP = i1;
+ return i19 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _memcpy: _memcpy, _main: _main, _memset: _memset, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_free": _free, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_printf": _printf, "_send": _send, "_pwrite": _pwrite, "__reallyNegative": __reallyNegative, "_fwrite": _fwrite, "_malloc": _malloc, "_mkport": _mkport, "_fprintf": _fprintf, "___setErrNo": ___setErrNo, "__formatString": __formatString, "_fileno": _fileno, "_fflush": _fflush, "_write": _write, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/corrections.js b/test/mjsunit/asm/embenchen/corrections.js
new file mode 100644
index 0000000..05cdc4c
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/corrections.js
@@ -0,0 +1,5983 @@
+var EXPECTED_OUTPUT = 'final: 40006013:58243.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(35);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,102,105,110,97,108,58,32,37,100,58,37,100,46,10,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+
+
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  Module["_memset"] = _memset;
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+  function _free() {
+  }
+  Module["_free"] = _free;
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _free=env._free;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _printf=env._printf;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var __reallyNegative=env.__reallyNegative;
+  var _fwrite=env._fwrite;
+  var _malloc=env._malloc;
+  var _mkport=env._mkport;
+  var _fprintf=env._fprintf;
+  var ___setErrNo=env.___setErrNo;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _fflush=env._fflush;
+  var _write=env._write;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 3500;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 35e3;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 7e4;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 550;
+     break L1;
+    }
+   case 48:
+    {
+     i11 = 0;
+     STACKTOP = i1;
+     return i11 | 0;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i3 + -48;
+     _printf(8, i2 | 0) | 0;
+     i11 = -1;
+     STACKTOP = i1;
+     return i11 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 7e3;
+ }
+ i11 = 0;
+ i8 = 0;
+ i5 = 0;
+ while (1) {
+  i6 = ((i5 | 0) % 5 | 0) + 1 | 0;
+  i4 = ((i5 | 0) % 3 | 0) + 1 | 0;
+  i7 = 0;
+  while (1) {
+   i11 = ((i7 | 0) / (i6 | 0) | 0) + i11 | 0;
+   if (i11 >>> 0 > 1e3) {
+    i11 = (i11 >>> 0) / (i4 >>> 0) | 0;
+   }
+   if ((i7 & 3 | 0) == 0) {
+    i11 = i11 + (Math_imul((i7 & 7 | 0) == 0 ? 1 : -1, i7) | 0) | 0;
+   }
+   i10 = i11 << 16 >> 16;
+   i10 = (Math_imul(i10, i10) | 0) & 255;
+   i9 = i10 + (i8 & 65535) | 0;
+   i7 = i7 + 1 | 0;
+   if ((i7 | 0) == 2e4) {
+    break;
+   } else {
+    i8 = i9;
+   }
+  }
+  i5 = i5 + 1 | 0;
+  if ((i5 | 0) < (i3 | 0)) {
+   i8 = i9;
+  } else {
+   break;
+  }
+ }
+ HEAP32[i2 >> 2] = i11;
+ HEAP32[i2 + 4 >> 2] = i8 + i10 & 65535;
+ _printf(24, i2 | 0) | 0;
+ i11 = 0;
+ STACKTOP = i1;
+ return i11 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _memcpy: _memcpy, _main: _main, _memset: _memset, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_free": _free, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_printf": _printf, "_send": _send, "_pwrite": _pwrite, "__reallyNegative": __reallyNegative, "_fwrite": _fwrite, "_malloc": _malloc, "_mkport": _mkport, "_fprintf": _fprintf, "___setErrNo": ___setErrNo, "__formatString": __formatString, "_fileno": _fileno, "_fflush": _fflush, "_write": _write, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/fannkuch.js b/test/mjsunit/asm/embenchen/fannkuch.js
new file mode 100644
index 0000000..64bd491
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/fannkuch.js
@@ -0,0 +1,8435 @@
+var EXPECTED_OUTPUT =
+  '123456789\n' +
+  '213456789\n' +
+  '231456789\n' +
+  '321456789\n' +
+  '312456789\n' +
+  '132456789\n' +
+  '234156789\n' +
+  '324156789\n' +
+  '342156789\n' +
+  '432156789\n' +
+  '423156789\n' +
+  '243156789\n' +
+  '341256789\n' +
+  '431256789\n' +
+  '413256789\n' +
+  '143256789\n' +
+  '134256789\n' +
+  '314256789\n' +
+  '412356789\n' +
+  '142356789\n' +
+  '124356789\n' +
+  '214356789\n' +
+  '241356789\n' +
+  '421356789\n' +
+  '234516789\n' +
+  '324516789\n' +
+  '342516789\n' +
+  '432516789\n' +
+  '423516789\n' +
+  '243516789\n' +
+  'Pfannkuchen(9) = 30.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(547);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,10,0,0,0,0,0,0,80,102,97,110,110,107,117,99,104,101,110,40,37,100,41,32,61,32,37,100,46,10,0,0,37,100,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,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,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,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], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }function _putchar(c) {
+      // int putchar(int c);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/putchar.html
+      return _fputc(c, HEAP32[((_stdout)>>2)]);
+    }
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  Module["_memset"] = _memset;
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+  function _abort() {
+      Module['abort']();
+    }
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _fflush=env._fflush;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _putchar=env._putchar;
+  var _fputc=env._fputc;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var _abort=env._abort;
+  var __reallyNegative=env.__reallyNegative;
+  var _fwrite=env._fwrite;
+  var _sbrk=env._sbrk;
+  var _mkport=env._mkport;
+  var _fprintf=env._fprintf;
+  var ___setErrNo=env.___setErrNo;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _printf=env._printf;
+  var _time=env._time;
+  var _sysconf=env._sysconf;
+  var _write=env._write;
+  var ___errno_location=env.___errno_location;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[14] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 96 + (i5 << 2) | 0;
+    i5 = 96 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[14] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[64 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 96 + (i7 << 2) | 0;
+     i7 = 96 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[14] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[64 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[76 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 96 + (i9 << 2) | 0;
+      i7 = HEAP32[14] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 96 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[14] = i7 | i8;
+       i28 = 96 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[64 >> 2] = i4;
+     HEAP32[76 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[60 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[360 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[72 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 360 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[64 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[76 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 96 + (i9 << 2) | 0;
+       i7 = HEAP32[14] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 96 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[14] = i7 | i8;
+        i25 = 96 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[64 >> 2] = i2;
+      HEAP32[76 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[60 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[360 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[360 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[64 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[72 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 360 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 96 + (i6 << 2) | 0;
+         i5 = HEAP32[14] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 96 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[14] = i5 | i4;
+          i21 = 96 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 360 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[60 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[60 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[72 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[64 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[76 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[76 >> 2] = i2 + i12;
+   HEAP32[64 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[64 >> 2] = 0;
+   HEAP32[76 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[68 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[68 >> 2] = i31;
+  i32 = HEAP32[80 >> 2] | 0;
+  HEAP32[80 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[132] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[536 >> 2] = i18;
+    HEAP32[532 >> 2] = i18;
+    HEAP32[540 >> 2] = -1;
+    HEAP32[544 >> 2] = -1;
+    HEAP32[548 >> 2] = 0;
+    HEAP32[500 >> 2] = 0;
+    HEAP32[132] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[536 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[496 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[488 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[500 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[80 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 504 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[68 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[532 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[488 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[496 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[536 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[500 >> 2] = HEAP32[500 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[488 >> 2] | 0) + i14 | 0;
+  HEAP32[488 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[492 >> 2] | 0) >>> 0) {
+   HEAP32[492 >> 2] = i15;
+  }
+  i15 = HEAP32[80 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 504 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[68 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[80 >> 2] = i15 + i3;
+     HEAP32[68 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[84 >> 2] = HEAP32[544 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+     HEAP32[72 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 504 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[80 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[76 >> 2] | 0)) {
+        i32 = (HEAP32[64 >> 2] | 0) + i10 | 0;
+        HEAP32[64 >> 2] = i32;
+        HEAP32[76 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 360 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 96 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[14] = HEAP32[14] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 96 + (i10 << 2) | 0;
+        i9 = HEAP32[14] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 96 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[14] = i9 | i5;
+         i3 = 96 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 360 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[60 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[60 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[72 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[68 >> 2] | 0) + i10 | 0;
+       HEAP32[68 >> 2] = i32;
+       HEAP32[80 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 504 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[80 >> 2] = i17 + i4;
+    HEAP32[68 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[84 >> 2] = HEAP32[544 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[504 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[508 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[512 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[516 >> 2];
+    HEAP32[504 >> 2] = i17;
+    HEAP32[508 >> 2] = i14;
+    HEAP32[516 >> 2] = 0;
+    HEAP32[512 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 96 + (i4 << 2) | 0;
+      i5 = HEAP32[14] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 96 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[14] = i5 | i3;
+       i7 = 96 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 360 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[60 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[60 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[72 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[72 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[72 >> 2] = i17;
+    }
+    HEAP32[504 >> 2] = i17;
+    HEAP32[508 >> 2] = i14;
+    HEAP32[516 >> 2] = 0;
+    HEAP32[92 >> 2] = HEAP32[132];
+    HEAP32[88 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 96 + (i32 << 2) | 0;
+     HEAP32[96 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[96 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[80 >> 2] = i17 + i2;
+    HEAP32[68 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[84 >> 2] = HEAP32[544 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[68 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[68 >> 2] = i31;
+   i32 = HEAP32[80 >> 2] | 0;
+   HEAP32[80 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[72 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[76 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[64 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 96 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[14] = HEAP32[14] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 360 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[80 >> 2] | 0)) {
+   i21 = (HEAP32[68 >> 2] | 0) + i11 | 0;
+   HEAP32[68 >> 2] = i21;
+   HEAP32[80 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[76 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[76 >> 2] = 0;
+   HEAP32[64 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[76 >> 2] | 0)) {
+   i21 = (HEAP32[64 >> 2] | 0) + i11 | 0;
+   HEAP32[64 >> 2] = i21;
+   HEAP32[76 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 360 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[60 >> 2] = HEAP32[60 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 96 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[14] = HEAP32[14] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[76 >> 2] | 0)) {
+   HEAP32[64 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 96 + (i7 << 2) | 0;
+  i8 = HEAP32[14] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 96 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[14] = i8 | i6;
+   i4 = 96 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 360 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[60 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L205 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L205;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[72 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[72 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[60 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[88 >> 2] | 0) + -1 | 0;
+ HEAP32[88 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 512 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[88 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function __Z15fannkuch_workerPv(i9) {
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i3 = STACKTOP;
+ i7 = HEAP32[i9 + 4 >> 2] | 0;
+ i6 = i7 << 2;
+ i5 = _malloc(i6) | 0;
+ i2 = _malloc(i6) | 0;
+ i6 = _malloc(i6) | 0;
+ i10 = (i7 | 0) > 0;
+ if (i10) {
+  i8 = 0;
+  do {
+   HEAP32[i5 + (i8 << 2) >> 2] = i8;
+   i8 = i8 + 1 | 0;
+  } while ((i8 | 0) != (i7 | 0));
+  i8 = i7 + -1 | 0;
+  i17 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i5 + (i17 << 2) >> 2] = i8;
+  i9 = i5 + (i8 << 2) | 0;
+  HEAP32[i9 >> 2] = i17;
+  if (i10) {
+   i10 = i7 << 2;
+   i11 = 0;
+   i12 = i7;
+   L7 : while (1) {
+    if ((i12 | 0) > 1) {
+     while (1) {
+      i13 = i12 + -1 | 0;
+      HEAP32[i6 + (i13 << 2) >> 2] = i12;
+      if ((i13 | 0) > 1) {
+       i12 = i13;
+      } else {
+       i12 = 1;
+       break;
+      }
+     }
+    }
+    i13 = HEAP32[i5 >> 2] | 0;
+    if ((i13 | 0) != 0 ? (HEAP32[i9 >> 2] | 0) != (i8 | 0) : 0) {
+     _memcpy(i2 | 0, i5 | 0, i10 | 0) | 0;
+     i15 = 0;
+     i14 = HEAP32[i2 >> 2] | 0;
+     while (1) {
+      i17 = i14 + -1 | 0;
+      if ((i17 | 0) > 1) {
+       i16 = 1;
+       do {
+        i20 = i2 + (i16 << 2) | 0;
+        i19 = HEAP32[i20 >> 2] | 0;
+        i18 = i2 + (i17 << 2) | 0;
+        HEAP32[i20 >> 2] = HEAP32[i18 >> 2];
+        HEAP32[i18 >> 2] = i19;
+        i16 = i16 + 1 | 0;
+        i17 = i17 + -1 | 0;
+       } while ((i16 | 0) < (i17 | 0));
+      }
+      i15 = i15 + 1 | 0;
+      i20 = i2 + (i14 << 2) | 0;
+      i16 = HEAP32[i20 >> 2] | 0;
+      HEAP32[i20 >> 2] = i14;
+      if ((i16 | 0) == 0) {
+       break;
+      } else {
+       i14 = i16;
+      }
+     }
+     i11 = (i11 | 0) < (i15 | 0) ? i15 : i11;
+    }
+    if ((i12 | 0) >= (i8 | 0)) {
+     i8 = 34;
+     break;
+    }
+    while (1) {
+     if ((i12 | 0) > 0) {
+      i14 = 0;
+      while (1) {
+       i15 = i14 + 1 | 0;
+       HEAP32[i5 + (i14 << 2) >> 2] = HEAP32[i5 + (i15 << 2) >> 2];
+       if ((i15 | 0) == (i12 | 0)) {
+        i14 = i12;
+        break;
+       } else {
+        i14 = i15;
+       }
+      }
+     } else {
+      i14 = 0;
+     }
+     HEAP32[i5 + (i14 << 2) >> 2] = i13;
+     i14 = i6 + (i12 << 2) | 0;
+     i20 = (HEAP32[i14 >> 2] | 0) + -1 | 0;
+     HEAP32[i14 >> 2] = i20;
+     i14 = i12 + 1 | 0;
+     if ((i20 | 0) > 0) {
+      continue L7;
+     }
+     if ((i14 | 0) >= (i8 | 0)) {
+      i8 = 34;
+      break L7;
+     }
+     i13 = HEAP32[i5 >> 2] | 0;
+     i12 = i14;
+    }
+   }
+   if ((i8 | 0) == 34) {
+    _free(i5);
+    _free(i2);
+    _free(i6);
+    STACKTOP = i3;
+    return i11 | 0;
+   }
+  } else {
+   i1 = i9;
+   i4 = i8;
+  }
+ } else {
+  i4 = i7 + -1 | 0;
+  i20 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i5 + (i20 << 2) >> 2] = i4;
+  i1 = i5 + (i4 << 2) | 0;
+  HEAP32[i1 >> 2] = i20;
+ }
+ i11 = 0;
+ L36 : while (1) {
+  if ((i7 | 0) > 1) {
+   while (1) {
+    i8 = i7 + -1 | 0;
+    HEAP32[i6 + (i8 << 2) >> 2] = i7;
+    if ((i8 | 0) > 1) {
+     i7 = i8;
+    } else {
+     i7 = 1;
+     break;
+    }
+   }
+  }
+  i8 = HEAP32[i5 >> 2] | 0;
+  if ((i8 | 0) != 0 ? (HEAP32[i1 >> 2] | 0) != (i4 | 0) : 0) {
+   i10 = 0;
+   i9 = HEAP32[i2 >> 2] | 0;
+   while (1) {
+    i13 = i9 + -1 | 0;
+    if ((i13 | 0) > 1) {
+     i12 = 1;
+     do {
+      i18 = i2 + (i12 << 2) | 0;
+      i19 = HEAP32[i18 >> 2] | 0;
+      i20 = i2 + (i13 << 2) | 0;
+      HEAP32[i18 >> 2] = HEAP32[i20 >> 2];
+      HEAP32[i20 >> 2] = i19;
+      i12 = i12 + 1 | 0;
+      i13 = i13 + -1 | 0;
+     } while ((i12 | 0) < (i13 | 0));
+    }
+    i10 = i10 + 1 | 0;
+    i20 = i2 + (i9 << 2) | 0;
+    i12 = HEAP32[i20 >> 2] | 0;
+    HEAP32[i20 >> 2] = i9;
+    if ((i12 | 0) == 0) {
+     break;
+    } else {
+     i9 = i12;
+    }
+   }
+   i11 = (i11 | 0) < (i10 | 0) ? i10 : i11;
+  }
+  if ((i7 | 0) >= (i4 | 0)) {
+   i8 = 34;
+   break;
+  }
+  while (1) {
+   if ((i7 | 0) > 0) {
+    i9 = 0;
+    while (1) {
+     i10 = i9 + 1 | 0;
+     HEAP32[i5 + (i9 << 2) >> 2] = HEAP32[i5 + (i10 << 2) >> 2];
+     if ((i10 | 0) == (i7 | 0)) {
+      i9 = i7;
+      break;
+     } else {
+      i9 = i10;
+     }
+    }
+   } else {
+    i9 = 0;
+   }
+   HEAP32[i5 + (i9 << 2) >> 2] = i8;
+   i9 = i6 + (i7 << 2) | 0;
+   i20 = (HEAP32[i9 >> 2] | 0) + -1 | 0;
+   HEAP32[i9 >> 2] = i20;
+   i9 = i7 + 1 | 0;
+   if ((i20 | 0) > 0) {
+    continue L36;
+   }
+   if ((i9 | 0) >= (i4 | 0)) {
+    i8 = 34;
+    break L36;
+   }
+   i8 = HEAP32[i5 >> 2] | 0;
+   i7 = i9;
+  }
+ }
+ if ((i8 | 0) == 34) {
+  _free(i5);
+  _free(i2);
+  _free(i6);
+  STACKTOP = i3;
+  return i11 | 0;
+ }
+ return 0;
+}
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i1 = i2;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 10;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 11;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 12;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 9;
+     break L1;
+    }
+   case 48:
+    {
+     i11 = 0;
+     STACKTOP = i2;
+     return i11 | 0;
+    }
+   default:
+    {
+     HEAP32[i1 >> 2] = i3 + -48;
+     _printf(8, i1 | 0) | 0;
+     i11 = -1;
+     STACKTOP = i2;
+     return i11 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 11;
+ }
+ i5 = i3 + -1 | 0;
+ i6 = 0;
+ i7 = 0;
+ while (1) {
+  i4 = _malloc(12) | 0;
+  HEAP32[i4 >> 2] = i7;
+  HEAP32[i4 + 4 >> 2] = i3;
+  HEAP32[i4 + 8 >> 2] = i6;
+  i7 = i7 + 1 | 0;
+  if ((i7 | 0) == (i5 | 0)) {
+   break;
+  } else {
+   i6 = i4;
+  }
+ }
+ i5 = i3 << 2;
+ i6 = _malloc(i5) | 0;
+ i5 = _malloc(i5) | 0;
+ i7 = 0;
+ do {
+  HEAP32[i6 + (i7 << 2) >> 2] = i7;
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != (i3 | 0));
+ i8 = i3;
+ i7 = 30;
+ L19 : do {
+  i9 = 0;
+  do {
+   HEAP32[i1 >> 2] = (HEAP32[i6 + (i9 << 2) >> 2] | 0) + 1;
+   _printf(48, i1 | 0) | 0;
+   i9 = i9 + 1 | 0;
+  } while ((i9 | 0) != (i3 | 0));
+  _putchar(10) | 0;
+  i7 = i7 + -1 | 0;
+  if ((i8 | 0) <= 1) {
+   if ((i8 | 0) == (i3 | 0)) {
+    break;
+   }
+  } else {
+   while (1) {
+    i9 = i8 + -1 | 0;
+    HEAP32[i5 + (i9 << 2) >> 2] = i8;
+    if ((i9 | 0) > 1) {
+     i8 = i9;
+    } else {
+     i8 = 1;
+     break;
+    }
+   }
+  }
+  while (1) {
+   i9 = HEAP32[i6 >> 2] | 0;
+   if ((i8 | 0) > 0) {
+    i11 = 0;
+    while (1) {
+     i10 = i11 + 1 | 0;
+     HEAP32[i6 + (i11 << 2) >> 2] = HEAP32[i6 + (i10 << 2) >> 2];
+     if ((i10 | 0) == (i8 | 0)) {
+      i10 = i8;
+      break;
+     } else {
+      i11 = i10;
+     }
+    }
+   } else {
+    i10 = 0;
+   }
+   HEAP32[i6 + (i10 << 2) >> 2] = i9;
+   i9 = i5 + (i8 << 2) | 0;
+   i11 = (HEAP32[i9 >> 2] | 0) + -1 | 0;
+   HEAP32[i9 >> 2] = i11;
+   i9 = i8 + 1 | 0;
+   if ((i11 | 0) > 0) {
+    break;
+   }
+   if ((i9 | 0) == (i3 | 0)) {
+    break L19;
+   } else {
+    i8 = i9;
+   }
+  }
+ } while ((i7 | 0) != 0);
+ _free(i6);
+ _free(i5);
+ if ((i4 | 0) == 0) {
+  i5 = 0;
+ } else {
+  i5 = 0;
+  while (1) {
+   i6 = __Z15fannkuch_workerPv(i4) | 0;
+   i5 = (i5 | 0) < (i6 | 0) ? i6 : i5;
+   i6 = HEAP32[i4 + 8 >> 2] | 0;
+   _free(i4);
+   if ((i6 | 0) == 0) {
+    break;
+   } else {
+    i4 = i6;
+   }
+  }
+ }
+ HEAP32[i1 >> 2] = i3;
+ HEAP32[i1 + 4 >> 2] = i5;
+ _printf(24, i1 | 0) | 0;
+ i11 = 0;
+ STACKTOP = i2;
+ return i11 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_fflush": _fflush, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_putchar": _putchar, "_fputc": _fputc, "_send": _send, "_pwrite": _pwrite, "_abort": _abort, "__reallyNegative": __reallyNegative, "_fwrite": _fwrite, "_sbrk": _sbrk, "_mkport": _mkport, "_fprintf": _fprintf, "___setErrNo": ___setErrNo, "__formatString": __formatString, "_fileno": _fileno, "_printf": _printf, "_time": _time, "_sysconf": _sysconf, "_write": _write, "___errno_location": ___errno_location, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/fasta.js b/test/mjsunit/asm/embenchen/fasta.js
new file mode 100644
index 0000000..8c66354
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/fasta.js
@@ -0,0 +1,8605 @@
+var EXPECTED_OUTPUT =
+  'GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA\n' +
+  'TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT\n' +
+  'AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG\n' +
+  'GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG\n' +
+  'CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT\n' +
+  'GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA\n' +
+  'GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA\n' +
+  'TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG\n' +
+  'AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA\n' +
+  'GCCTGGGCGA\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(1155);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([38,2,0,0,0,0,0,0,42,0,0,0,0,0,0,0,97,0,0,0,113,61,138,62,0,0,0,0,99,0,0,0,143,194,245,61,0,0,0,0,103,0,0,0,143,194,245,61,0,0,0,0,116,0,0,0,113,61,138,62,0,0,0,0,66,0,0,0,10,215,163,60,0,0,0,0,68,0,0,0,10,215,163,60,0,0,0,0,72,0,0,0,10,215,163,60,0,0,0,0,75,0,0,0,10,215,163,60,0,0,0,0,77,0,0,0,10,215,163,60,0,0,0,0,78,0,0,0,10,215,163,60,0,0,0,0,82,0,0,0,10,215,163,60,0,0,0,0,83,0,0,0,10,215,163,60,0,0,0,0,86,0,0,0,10,215,163,60,0,0,0,0,87,0,0,0,10,215,163,60,0,0,0,0,89,0,0,0,10,215,163,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,97,0,0,0,233,28,155,62,0,0,0,0,99,0,0,0,114,189,74,62,0,0,0,0,103,0,0,0,215,73,74,62,0,0,0,0,116,0,0,0,114,95,154,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,114,114,111,114,58,32,37,100,10,0,0,0,0,0,0,71,71,67,67,71,71,71,67,71,67,71,71,84,71,71,67,84,67,65,67,71,67,67,84,71,84,65,65,84,67,67,67,65,71,67,65,67,84,84,84,71,71,71,65,71,71,67,67,71,65,71,71,67,71,71,71,67,71,71,65,84,67,65,67,67,84,71,65,71,71,84,67,65,71,71,65,71,84,84,67,71,65,71,65,67,67,65,71,67,67,84,71,71,67,67,65,65,67,65,84,71,71,84,71,65,65,65,67,67,67,67,71,84,67,84,67,84,65,67,84,65,65,65,65,65,84,65,67,65,65,65,65,65,84,84,65,71,67,67,71,71,71,67,71,84,71,71,84,71,71,67,71,67,71,67,71,67,67,84,71,84,65,65,84,67,67,67,65,71,67,84,65,67,84,67,71,71,71,65,71,71,67,84,71,65,71,71,67,65,71,71,65,71,65,65,84,67,71,67,84,84,71,65,65,67,67,67,71,71,71,65,71,71,67,71,71,65,71,71,84,84,71,67,65,71,84,71,65,71,67,67,71,65,71,65,84,67,71,67,71,67,67,65,67,84,71,67,65,67,84,67,67,65,71,67,67,84,71,71,71,67,71,65,67,65,71,65,71,67,71,65,71,65,67,84,67,67,71,84,67,84,67,65,65,65,65,65,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,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,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,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,120,4,0,0,1,0,0,0,2,0,0,0,1,0,0,0,0,0,0,0,115,116,100,58,58,98,97,100,95,97,108,108,111,99,0,0,83,116,57,98,97,100,95,97,108,108,111,99,0,0,0,0,8,0,0,0,104,4,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  function __ZSt18uncaught_exceptionv() { // std::uncaught_exception()
+      return !!__ZSt18uncaught_exceptionv.uncaught_exception;
+    }
+
+
+
+  function ___cxa_is_number_type(type) {
+      var isNumber = false;
+      try { if (type == __ZTIi) isNumber = true } catch(e){}
+      try { if (type == __ZTIj) isNumber = true } catch(e){}
+      try { if (type == __ZTIl) isNumber = true } catch(e){}
+      try { if (type == __ZTIm) isNumber = true } catch(e){}
+      try { if (type == __ZTIx) isNumber = true } catch(e){}
+      try { if (type == __ZTIy) isNumber = true } catch(e){}
+      try { if (type == __ZTIf) isNumber = true } catch(e){}
+      try { if (type == __ZTId) isNumber = true } catch(e){}
+      try { if (type == __ZTIe) isNumber = true } catch(e){}
+      try { if (type == __ZTIc) isNumber = true } catch(e){}
+      try { if (type == __ZTIa) isNumber = true } catch(e){}
+      try { if (type == __ZTIh) isNumber = true } catch(e){}
+      try { if (type == __ZTIs) isNumber = true } catch(e){}
+      try { if (type == __ZTIt) isNumber = true } catch(e){}
+      return isNumber;
+    }function ___cxa_does_inherit(definiteType, possibilityType, possibility) {
+      if (possibility == 0) return false;
+      if (possibilityType == 0 || possibilityType == definiteType)
+        return true;
+      var possibility_type_info;
+      if (___cxa_is_number_type(possibilityType)) {
+        possibility_type_info = possibilityType;
+      } else {
+        var possibility_type_infoAddr = HEAP32[((possibilityType)>>2)] - 8;
+        possibility_type_info = HEAP32[((possibility_type_infoAddr)>>2)];
+      }
+      switch (possibility_type_info) {
+      case 0: // possibility is a pointer
+        // See if definite type is a pointer
+        var definite_type_infoAddr = HEAP32[((definiteType)>>2)] - 8;
+        var definite_type_info = HEAP32[((definite_type_infoAddr)>>2)];
+        if (definite_type_info == 0) {
+          // Also a pointer; compare base types of pointers
+          var defPointerBaseAddr = definiteType+8;
+          var defPointerBaseType = HEAP32[((defPointerBaseAddr)>>2)];
+          var possPointerBaseAddr = possibilityType+8;
+          var possPointerBaseType = HEAP32[((possPointerBaseAddr)>>2)];
+          return ___cxa_does_inherit(defPointerBaseType, possPointerBaseType, possibility);
+        } else
+          return false; // one pointer and one non-pointer
+      case 1: // class with no base class
+        return false;
+      case 2: // class with base class
+        var parentTypeAddr = possibilityType + 8;
+        var parentType = HEAP32[((parentTypeAddr)>>2)];
+        return ___cxa_does_inherit(definiteType, parentType, possibility);
+      default:
+        return false; // some unencountered type
+      }
+    }
+
+
+
+  var ___cxa_last_thrown_exception=0;function ___resumeException(ptr) {
+      if (!___cxa_last_thrown_exception) { ___cxa_last_thrown_exception = ptr; }
+      throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+    }
+
+  var ___cxa_exception_header_size=8;function ___cxa_find_matching_catch(thrown, throwntype) {
+      if (thrown == -1) thrown = ___cxa_last_thrown_exception;
+      header = thrown - ___cxa_exception_header_size;
+      if (throwntype == -1) throwntype = HEAP32[((header)>>2)];
+      var typeArray = Array.prototype.slice.call(arguments, 2);
+
+      // If throwntype is a pointer, this means a pointer has been
+      // thrown. When a pointer is thrown, actually what's thrown
+      // is a pointer to the pointer. We'll dereference it.
+      if (throwntype != 0 && !___cxa_is_number_type(throwntype)) {
+        var throwntypeInfoAddr= HEAP32[((throwntype)>>2)] - 8;
+        var throwntypeInfo= HEAP32[((throwntypeInfoAddr)>>2)];
+        if (throwntypeInfo == 0)
+          thrown = HEAP32[((thrown)>>2)];
+      }
+      // The different catch blocks are denoted by different types.
+      // Due to inheritance, those types may not precisely match the
+      // type of the thrown object. Find one which matches, and
+      // return the type of the catch block which should be called.
+      for (var i = 0; i < typeArray.length; i++) {
+        if (___cxa_does_inherit(typeArray[i], throwntype, thrown))
+          return ((asm["setTempRet0"](typeArray[i]),thrown)|0);
+      }
+      // Shouldn't happen unless we have bogus data in typeArray
+      // or encounter a type for which emscripten doesn't have suitable
+      // typeinfo defined. Best-efforts match just in case.
+      return ((asm["setTempRet0"](throwntype),thrown)|0);
+    }function ___cxa_throw(ptr, type, destructor) {
+      if (!___cxa_throw.initialized) {
+        try {
+          HEAP32[((__ZTVN10__cxxabiv119__pointer_type_infoE)>>2)]=0; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        try {
+          HEAP32[((__ZTVN10__cxxabiv117__class_type_infoE)>>2)]=1; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        try {
+          HEAP32[((__ZTVN10__cxxabiv120__si_class_type_infoE)>>2)]=2; // Workaround for libcxxabi integration bug
+        } catch(e){}
+        ___cxa_throw.initialized = true;
+      }
+      var header = ptr - ___cxa_exception_header_size;
+      HEAP32[((header)>>2)]=type;
+      HEAP32[(((header)+(4))>>2)]=destructor;
+      ___cxa_last_thrown_exception = ptr;
+      if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
+        __ZSt18uncaught_exceptionv.uncaught_exception = 1;
+      } else {
+        __ZSt18uncaught_exceptionv.uncaught_exception++;
+      }
+      throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";
+    }
+
+
+  Module["_memset"] = _memset;
+
+  function _abort() {
+      Module['abort']();
+    }
+
+
+
+
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+
+  function _fputs(s, stream) {
+      // int fputs(const char *restrict s, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
+      var fd = _fileno(stream);
+      return _write(fd, s, _strlen(s));
+    }
+
+  function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }function _puts(s) {
+      // int puts(const char *s);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html
+      // NOTE: puts() always writes an extra newline.
+      var stdout = HEAP32[((_stdout)>>2)];
+      var ret = _fputs(s, stdout);
+      if (ret < 0) {
+        return ret;
+      } else {
+        var newlineRet = _fputc(10, stdout);
+        return (newlineRet < 0) ? -1 : ret + 1;
+      }
+    }
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+  function __ZNSt9exceptionD2Ev() {}
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;function ___cxa_allocate_exception(size) {
+      var ptr = _malloc(size + ___cxa_exception_header_size);
+      return ptr + ___cxa_exception_header_size;
+    }
+
+  var __ZTISt9exception=allocate([allocate([1,0,0,0,0,0,0], "i8", ALLOC_STATIC)+8, 0], "i32", ALLOC_STATIC);
+
+  function __ZTVN10__cxxabiv120__si_class_type_infoE() {
+  Module['printErr']('missing function: _ZTVN10__cxxabiv120__si_class_type_infoE'); abort(-1);
+  }
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function invoke_ii(index,a1) {
+  try {
+    return Module["dynCall_ii"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vi(index,a1) {
+  try {
+    Module["dynCall_vi"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_v(index) {
+  try {
+    Module["dynCall_v"](index);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+  var __ZTISt9exception=env.__ZTISt9exception|0;
+  var __ZTVN10__cxxabiv120__si_class_type_infoE=env.__ZTVN10__cxxabiv120__si_class_type_infoE|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var invoke_ii=env.invoke_ii;
+  var invoke_vi=env.invoke_vi;
+  var invoke_v=env.invoke_v;
+  var _send=env._send;
+  var ___setErrNo=env.___setErrNo;
+  var ___cxa_is_number_type=env.___cxa_is_number_type;
+  var ___cxa_allocate_exception=env.___cxa_allocate_exception;
+  var ___cxa_find_matching_catch=env.___cxa_find_matching_catch;
+  var _fflush=env._fflush;
+  var _time=env._time;
+  var _pwrite=env._pwrite;
+  var __reallyNegative=env.__reallyNegative;
+  var _sbrk=env._sbrk;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _fileno=env._fileno;
+  var ___resumeException=env.___resumeException;
+  var __ZSt18uncaught_exceptionv=env.__ZSt18uncaught_exceptionv;
+  var _sysconf=env._sysconf;
+  var _puts=env._puts;
+  var _mkport=env._mkport;
+  var _write=env._write;
+  var ___errno_location=env.___errno_location;
+  var __ZNSt9exceptionD2Ev=env.__ZNSt9exceptionD2Ev;
+  var _fputc=env._fputc;
+  var ___cxa_throw=env.___cxa_throw;
+  var _abort=env._abort;
+  var _fwrite=env._fwrite;
+  var ___cxa_does_inherit=env.___cxa_does_inherit;
+  var _fprintf=env._fprintf;
+  var __formatString=env.__formatString;
+  var _fputs=env._fputs;
+  var _printf=env._printf;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[146] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 624 + (i5 << 2) | 0;
+    i5 = 624 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[146] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[592 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 624 + (i7 << 2) | 0;
+     i7 = 624 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[146] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[592 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[604 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 624 + (i9 << 2) | 0;
+      i7 = HEAP32[146] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 624 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[146] = i7 | i8;
+       i28 = 624 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[592 >> 2] = i4;
+     HEAP32[604 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[588 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[888 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[600 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 888 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[592 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[604 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 624 + (i9 << 2) | 0;
+       i7 = HEAP32[146] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 624 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[146] = i7 | i8;
+        i25 = 624 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[592 >> 2] = i2;
+      HEAP32[604 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[588 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[888 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[888 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[592 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[600 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 888 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 624 + (i6 << 2) | 0;
+         i5 = HEAP32[146] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 624 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[146] = i5 | i4;
+          i21 = 624 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 888 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[588 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[588 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[600 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[592 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[604 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[604 >> 2] = i2 + i12;
+   HEAP32[592 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[592 >> 2] = 0;
+   HEAP32[604 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[596 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[596 >> 2] = i31;
+  i32 = HEAP32[608 >> 2] | 0;
+  HEAP32[608 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[264] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[1064 >> 2] = i18;
+    HEAP32[1060 >> 2] = i18;
+    HEAP32[1068 >> 2] = -1;
+    HEAP32[1072 >> 2] = -1;
+    HEAP32[1076 >> 2] = 0;
+    HEAP32[1028 >> 2] = 0;
+    HEAP32[264] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[1064 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[1024 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[1016 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[1028 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[608 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 1032 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[596 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[1060 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[1016 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[1024 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[1064 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[1028 >> 2] = HEAP32[1028 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[1016 >> 2] | 0) + i14 | 0;
+  HEAP32[1016 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[1020 >> 2] | 0) >>> 0) {
+   HEAP32[1020 >> 2] = i15;
+  }
+  i15 = HEAP32[608 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 1032 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[596 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[608 >> 2] = i15 + i3;
+     HEAP32[596 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[612 >> 2] = HEAP32[1072 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+     HEAP32[600 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 1032 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[608 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[604 >> 2] | 0)) {
+        i32 = (HEAP32[592 >> 2] | 0) + i10 | 0;
+        HEAP32[592 >> 2] = i32;
+        HEAP32[604 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 888 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 624 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[146] = HEAP32[146] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 624 + (i10 << 2) | 0;
+        i9 = HEAP32[146] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 624 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[146] = i9 | i5;
+         i3 = 624 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 888 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[588 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[588 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[600 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[596 >> 2] | 0) + i10 | 0;
+       HEAP32[596 >> 2] = i32;
+       HEAP32[608 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 1032 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[608 >> 2] = i17 + i4;
+    HEAP32[596 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[612 >> 2] = HEAP32[1072 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[1032 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[1036 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[1040 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[1044 >> 2];
+    HEAP32[1032 >> 2] = i17;
+    HEAP32[1036 >> 2] = i14;
+    HEAP32[1044 >> 2] = 0;
+    HEAP32[1040 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 624 + (i4 << 2) | 0;
+      i5 = HEAP32[146] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 624 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[146] = i5 | i3;
+       i7 = 624 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 888 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[588 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[588 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[600 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[600 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[600 >> 2] = i17;
+    }
+    HEAP32[1032 >> 2] = i17;
+    HEAP32[1036 >> 2] = i14;
+    HEAP32[1044 >> 2] = 0;
+    HEAP32[620 >> 2] = HEAP32[264];
+    HEAP32[616 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 624 + (i32 << 2) | 0;
+     HEAP32[624 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[624 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[608 >> 2] = i17 + i2;
+    HEAP32[596 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[612 >> 2] = HEAP32[1072 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[596 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[596 >> 2] = i31;
+   i32 = HEAP32[608 >> 2] | 0;
+   HEAP32[608 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[600 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[604 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[592 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 624 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[146] = HEAP32[146] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 888 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[608 >> 2] | 0)) {
+   i21 = (HEAP32[596 >> 2] | 0) + i11 | 0;
+   HEAP32[596 >> 2] = i21;
+   HEAP32[608 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[604 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[604 >> 2] = 0;
+   HEAP32[592 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[604 >> 2] | 0)) {
+   i21 = (HEAP32[592 >> 2] | 0) + i11 | 0;
+   HEAP32[592 >> 2] = i21;
+   HEAP32[604 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 888 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[588 >> 2] = HEAP32[588 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 624 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[146] = HEAP32[146] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[604 >> 2] | 0)) {
+   HEAP32[592 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 624 + (i7 << 2) | 0;
+  i8 = HEAP32[146] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 624 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[146] = i8 | i6;
+   i4 = 624 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 888 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[588 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L204 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L204;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[600 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[600 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[588 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[616 >> 2] | 0) + -1 | 0;
+ HEAP32[616 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 1040 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[616 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function _main(i7, i8) {
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, d9 = 0.0, d10 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 4272 | 0;
+ i3 = i2;
+ i5 = i2 + 4248 | 0;
+ i4 = i2 + 2128 | 0;
+ i1 = i2 + 8 | 0;
+ L1 : do {
+  if ((i7 | 0) > 1) {
+   i7 = HEAP8[HEAP32[i8 + 4 >> 2] | 0] | 0;
+   switch (i7 | 0) {
+   case 50:
+    {
+     i3 = 95e5;
+     break L1;
+    }
+   case 51:
+    {
+     i6 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 95e6;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 19e7;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 95e4;
+     break L1;
+    }
+   case 48:
+    {
+     i8 = 0;
+     STACKTOP = i2;
+     return i8 | 0;
+    }
+   default:
+    {
+     HEAP32[i3 >> 2] = i7 + -48;
+     _printf(280, i3 | 0) | 0;
+     i8 = -1;
+     STACKTOP = i2;
+     return i8 | 0;
+    }
+   }
+  } else {
+   i6 = 4;
+  }
+ } while (0);
+ if ((i6 | 0) == 4) {
+  i3 = 19e6;
+ }
+ HEAP32[i5 + 8 >> 2] = 0;
+ HEAP32[i5 + 4 >> 2] = 287;
+ i8 = __Znaj(347) | 0;
+ HEAP32[i5 >> 2] = i8;
+ _memcpy(i8 | 0, 296, 287) | 0;
+ i8 = i8 + 287 | 0;
+ i7 = 296 | 0;
+ i6 = i8 + 60 | 0;
+ do {
+  HEAP8[i8] = HEAP8[i7] | 0;
+  i8 = i8 + 1 | 0;
+  i7 = i7 + 1 | 0;
+ } while ((i8 | 0) < (i6 | 0));
+ i7 = i3 << 1;
+ while (1) {
+  i6 = i7 >>> 0 < 60 ? i7 : 60;
+  __ZN14RotatingString5writeEj(i5, i6);
+  if ((i7 | 0) == (i6 | 0)) {
+   break;
+  } else {
+   i7 = i7 - i6 | 0;
+  }
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  __ZdaPv(i5);
+ }
+ if ((HEAP32[6] | 0) == 0) {
+  i6 = 24;
+  i5 = 0;
+ } else {
+  i5 = 24;
+  d9 = 0.0;
+  while (1) {
+   i6 = i5 + 4 | 0;
+   d9 = d9 + +HEAPF32[i6 >> 2];
+   d10 = d9 < 1.0 ? d9 : 1.0;
+   HEAPF32[i6 >> 2] = d10;
+   HEAP32[i5 + 8 >> 2] = ~~(d10 * 512.0) >>> 0;
+   i5 = i5 + 12 | 0;
+   if ((HEAP32[i5 >> 2] | 0) == 0) {
+    i6 = 24;
+    i5 = 0;
+    break;
+   }
+  }
+ }
+ do {
+  while (1) {
+   i8 = HEAP32[i6 + 8 >> 2] | 0;
+   if (i5 >>> 0 > i8 >>> 0 & (i8 | 0) != 0) {
+    i6 = i6 + 12 | 0;
+   } else {
+    break;
+   }
+  }
+  HEAP32[i4 + (i5 << 2) >> 2] = i6;
+  i5 = i5 + 1 | 0;
+ } while ((i5 | 0) != 513);
+ HEAP32[i4 + 2116 >> 2] = 0;
+ __Z9makeFastaI10RandomizedEvPKcS2_jRT_(0, 0, i3 * 3 | 0, i4);
+ if ((HEAP32[54] | 0) == 0) {
+  i5 = 216;
+  i4 = 0;
+ } else {
+  i5 = 216;
+  d9 = 0.0;
+  while (1) {
+   i4 = i5 + 4 | 0;
+   d9 = d9 + +HEAPF32[i4 >> 2];
+   d10 = d9 < 1.0 ? d9 : 1.0;
+   HEAPF32[i4 >> 2] = d10;
+   HEAP32[i5 + 8 >> 2] = ~~(d10 * 512.0) >>> 0;
+   i5 = i5 + 12 | 0;
+   if ((HEAP32[i5 >> 2] | 0) == 0) {
+    i5 = 216;
+    i4 = 0;
+    break;
+   }
+  }
+ }
+ do {
+  while (1) {
+   i8 = HEAP32[i5 + 8 >> 2] | 0;
+   if (i4 >>> 0 > i8 >>> 0 & (i8 | 0) != 0) {
+    i5 = i5 + 12 | 0;
+   } else {
+    break;
+   }
+  }
+  HEAP32[i1 + (i4 << 2) >> 2] = i5;
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) != 513);
+ HEAP32[i1 + 2116 >> 2] = 0;
+ __Z9makeFastaI10RandomizedEvPKcS2_jRT_(0, 0, i3 * 5 | 0, i1);
+ i8 = 0;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function __Z9makeFastaI10RandomizedEvPKcS2_jRT_(i3, i2, i6, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i4 = 0, i5 = 0, i7 = 0, d8 = 0.0, i9 = 0;
+ i2 = STACKTOP;
+ if ((i6 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i1 + 2116 | 0;
+ i3 = i1 + 2052 | 0;
+ while (1) {
+  i5 = i6 >>> 0 < 60 ? i6 : 60;
+  if ((i5 | 0) != 0) {
+   i7 = 0;
+   do {
+    i9 = ((((HEAP32[4] | 0) * 3877 | 0) + 29573 | 0) >>> 0) % 139968 | 0;
+    HEAP32[4] = i9;
+    d8 = +(i9 >>> 0) / 139968.0;
+    i9 = HEAP32[i1 + (~~(d8 * 512.0) >>> 0 << 2) >> 2] | 0;
+    while (1) {
+     if (+HEAPF32[i9 + 4 >> 2] < d8) {
+      i9 = i9 + 12 | 0;
+     } else {
+      break;
+     }
+    }
+    HEAP8[i1 + i7 + 2052 | 0] = HEAP32[i9 >> 2];
+    i7 = i7 + 1 | 0;
+   } while ((i7 | 0) != (i5 | 0));
+  }
+  HEAP8[i1 + i5 + 2052 | 0] = 10;
+  i9 = i5 + 1 | 0;
+  HEAP8[i1 + i9 + 2052 | 0] = 0;
+  HEAP32[i4 >> 2] = i9;
+  i9 = _strlen(i3 | 0) | 0;
+  i7 = HEAP32[2] | 0;
+  if ((i9 | 0) > (i7 | 0)) {
+   if ((i7 | 0) > 0) {
+    HEAP8[i1 + i7 + 2052 | 0] = 0;
+    _puts(i3 | 0) | 0;
+    HEAP8[i1 + (HEAP32[2] | 0) + 2052 | 0] = 122;
+    HEAP32[2] = 0;
+   }
+  } else {
+   _puts(i3 | 0) | 0;
+   HEAP32[2] = (HEAP32[2] | 0) - i9;
+  }
+  if ((i6 | 0) == (i5 | 0)) {
+   break;
+  } else {
+   i6 = i6 - i5 | 0;
+  }
+ }
+ STACKTOP = i2;
+ return;
+}
+function __ZN14RotatingString5writeEj(i3, i4) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i5 = __Znaj(i4 + 2 | 0) | 0;
+ i2 = i3 + 8 | 0;
+ _memcpy(i5 | 0, (HEAP32[i3 >> 2] | 0) + (HEAP32[i2 >> 2] | 0) | 0, i4 | 0) | 0;
+ HEAP8[i5 + i4 | 0] = 0;
+ i7 = _strlen(i5 | 0) | 0;
+ i6 = HEAP32[2] | 0;
+ if ((i7 | 0) > (i6 | 0)) {
+  if ((i6 | 0) > 0) {
+   HEAP8[i5 + i6 | 0] = 0;
+   _puts(i5 | 0) | 0;
+   HEAP32[2] = 0;
+   i6 = 6;
+  } else {
+   i6 = 5;
+  }
+ } else {
+  _puts(i5 | 0) | 0;
+  HEAP32[2] = (HEAP32[2] | 0) - i7;
+  i6 = 5;
+ }
+ if ((i6 | 0) == 5 ? (i5 | 0) != 0 : 0) {
+  i6 = 6;
+ }
+ if ((i6 | 0) == 6) {
+  __ZdlPv(i5);
+ }
+ i4 = (HEAP32[i2 >> 2] | 0) + i4 | 0;
+ HEAP32[i2 >> 2] = i4;
+ i3 = HEAP32[i3 + 4 >> 2] | 0;
+ if (!(i4 >>> 0 > i3 >>> 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i2 >> 2] = i4 - i3;
+ STACKTOP = i1;
+ return;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function __Znwj(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i2 = (i2 | 0) == 0 ? 1 : i2;
+ while (1) {
+  i3 = _malloc(i2) | 0;
+  if ((i3 | 0) != 0) {
+   i2 = 6;
+   break;
+  }
+  i3 = HEAP32[270] | 0;
+  HEAP32[270] = i3 + 0;
+  if ((i3 | 0) == 0) {
+   i2 = 5;
+   break;
+  }
+  FUNCTION_TABLE_v[i3 & 0]();
+ }
+ if ((i2 | 0) == 5) {
+  i3 = ___cxa_allocate_exception(4) | 0;
+  HEAP32[i3 >> 2] = 1096;
+  ___cxa_throw(i3 | 0, 1144, 1);
+ } else if ((i2 | 0) == 6) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ return 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function __ZNSt9bad_allocD0Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZNSt9exceptionD2Ev(i1 | 0);
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function __ZNSt9bad_allocD2Ev(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZNSt9exceptionD2Ev(i1 | 0);
+ STACKTOP = i2;
+ return;
+}
+function __ZdlPv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i1 | 0) != 0) {
+  _free(i1);
+ }
+ STACKTOP = i2;
+ return;
+}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function __Znaj(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = __Znwj(i1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function runPostSets() {
+ HEAP32[286] = __ZTVN10__cxxabiv120__si_class_type_infoE;
+ HEAP32[288] = __ZTISt9exception;
+}
+function dynCall_ii(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_ii[i2 & 1](i1 | 0) | 0;
+}
+function __ZdaPv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ __ZdlPv(i1);
+ STACKTOP = i2;
+ return;
+}
+function dynCall_vi(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vi[i2 & 3](i1 | 0);
+}
+function dynCall_v(i1) {
+ i1 = i1 | 0;
+ FUNCTION_TABLE_v[i1 & 0]();
+}
+function __ZNKSt9bad_alloc4whatEv(i1) {
+ i1 = i1 | 0;
+ return 1112;
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function b0(i1) {
+ i1 = i1 | 0;
+ abort(0);
+ return 0;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+function b1(i1) {
+ i1 = i1 | 0;
+ abort(1);
+}
+function b2() {
+ abort(2);
+}
+
+// EMSCRIPTEN_END_FUNCS
+  var FUNCTION_TABLE_ii = [b0,__ZNKSt9bad_alloc4whatEv];
+  var FUNCTION_TABLE_vi = [b1,__ZNSt9bad_allocD2Ev,__ZNSt9bad_allocD0Ev,b1];
+  var FUNCTION_TABLE_v = [b2];
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_ii: dynCall_ii, dynCall_vi: dynCall_vi, dynCall_v: dynCall_v };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_ii": invoke_ii, "invoke_vi": invoke_vi, "invoke_v": invoke_v, "_send": _send, "___setErrNo": ___setErrNo, "___cxa_is_number_type": ___cxa_is_number_type, "___cxa_allocate_exception": ___cxa_allocate_exception, "___cxa_find_matching_catch": ___cxa_find_matching_catch, "_fflush": _fflush, "_time": _time, "_pwrite": _pwrite, "__reallyNegative": __reallyNegative, "_sbrk": _sbrk, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_fileno": _fileno, "___resumeException": ___resumeException, "__ZSt18uncaught_exceptionv": __ZSt18uncaught_exceptionv, "_sysconf": _sysconf, "_puts": _puts, "_mkport": _mkport, "_write": _write, "___errno_location": ___errno_location, "__ZNSt9exceptionD2Ev": __ZNSt9exceptionD2Ev, "_fputc": _fputc, "___cxa_throw": ___cxa_throw, "_abort": _abort, "_fwrite": _fwrite, "___cxa_does_inherit": ___cxa_does_inherit, "_fprintf": _fprintf, "__formatString": __formatString, "_fputs": _fputs, "_printf": _printf, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity, "__ZTISt9exception": __ZTISt9exception, "__ZTVN10__cxxabiv120__si_class_type_infoE": __ZTVN10__cxxabiv120__si_class_type_infoE }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var dynCall_ii = Module["dynCall_ii"] = asm["dynCall_ii"];
+var dynCall_vi = Module["dynCall_vi"] = asm["dynCall_vi"];
+var dynCall_v = Module["dynCall_v"] = asm["dynCall_v"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/lua_binarytrees.js b/test/mjsunit/asm/embenchen/lua_binarytrees.js
new file mode 100644
index 0000000..e3a5d8c
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/lua_binarytrees.js
@@ -0,0 +1,42710 @@
+var EXPECTED_OUTPUT =
+  'stretch tree of depth 10\t check: -1\n' +
+  '1448\t trees of depth 4\t check: -1448\n' +
+  '362\t trees of depth 6\t check: -362\n' +
+  '90\t trees of depth 8\t check: -90\n' +
+  'long lived tree of depth 9\t check: -1\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+
+var Module;
+if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
+if (!Module.expectedDataFileDownloads) {
+  Module.expectedDataFileDownloads = 0;
+  Module.finishedDataFileDownloads = 0;
+}
+Module.expectedDataFileDownloads++;
+(function() {
+
+  function runWithFS() {
+
+function assert(check, msg) {
+  if (!check) throw msg + new Error().stack;
+}
+Module['FS_createDataFile']('/', 'binarytrees.lua', [45, 45, 32, 84, 104, 101, 32, 67, 111, 109, 112, 117, 116, 101, 114, 32, 76, 97, 110, 103, 117, 97, 103, 101, 32, 66, 101, 110, 99, 104, 109, 97, 114, 107, 115, 32, 71, 97, 109, 101, 10, 45, 45, 32, 104, 116, 116, 112, 58, 47, 47, 98, 101, 110, 99, 104, 109, 97, 114, 107, 115, 103, 97, 109, 101, 46, 97, 108, 105, 111, 116, 104, 46, 100, 101, 98, 105, 97, 110, 46, 111, 114, 103, 47, 10, 45, 45, 32, 99, 111, 110, 116, 114, 105, 98, 117, 116, 101, 100, 32, 98, 121, 32, 77, 105, 107, 101, 32, 80, 97, 108, 108, 10, 10, 108, 111, 99, 97, 108, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 105, 116, 101, 109, 44, 32, 100, 101, 112, 116, 104, 41, 10, 32, 32, 105, 102, 32, 100, 101, 112, 116, 104, 32, 62, 32, 48, 32, 116, 104, 101, 110, 10, 32, 32, 32, 32, 108, 111, 99, 97, 108, 32, 105, 32, 61, 32, 105, 116, 101, 109, 32, 43, 32, 105, 116, 101, 109, 10, 32, 32, 32, 32, 100, 101, 112, 116, 104, 32, 61, 32, 100, 101, 112, 116, 104, 32, 45, 32, 49, 10, 32, 32, 32, 32, 108, 111, 99, 97, 108, 32, 108, 101, 102, 116, 44, 32, 114, 105, 103, 104, 116, 32, 61, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 105, 45, 49, 44, 32, 100, 101, 112, 116, 104, 41, 44, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 105, 44, 32, 100, 101, 112, 116, 104, 41, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 123, 32, 105, 116, 101, 109, 44, 32, 108, 101, 102, 116, 44, 32, 114, 105, 103, 104, 116, 32, 125, 10, 32, 32, 101, 108, 115, 101, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 123, 32, 105, 116, 101, 109, 32, 125, 10, 32, 32, 101, 110, 100, 10, 101, 110, 100, 10, 10, 108, 111, 99, 97, 108, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 116, 114, 101, 101, 41, 10, 32, 32, 105, 102, 32, 116, 114, 101, 101, 91, 50, 93, 32, 116, 104, 101, 110, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 116, 114, 101, 101, 91, 49, 93, 32, 43, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 116, 114, 101, 101, 91, 50, 93, 41, 32, 45, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 116, 114, 101, 101, 91, 51, 93, 41, 10, 32, 32, 101, 108, 115, 101, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 116, 114, 101, 101, 91, 49, 93, 10, 32, 32, 101, 110, 100, 10, 101, 110, 100, 10, 10, 108, 111, 99, 97, 108, 32, 78, 32, 61, 32, 116, 111, 110, 117, 109, 98, 101, 114, 40, 97, 114, 103, 32, 97, 110, 100, 32, 97, 114, 103, 91, 49, 93, 41, 32, 111, 114, 32, 52, 10, 10, 105, 102, 32, 78, 32, 61, 61, 32, 48, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 48, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 49, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 57, 46, 53, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 50, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 49, 49, 46, 57, 57, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 51, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 49, 50, 46, 56, 53, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 52, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 49, 52, 46, 55, 50, 10, 101, 108, 115, 101, 105, 102, 32, 78, 32, 61, 61, 32, 53, 32, 116, 104, 101, 110, 10, 32, 32, 78, 32, 61, 32, 49, 53, 46, 56, 50, 10, 101, 110, 100, 10, 10, 108, 111, 99, 97, 108, 32, 109, 105, 110, 100, 101, 112, 116, 104, 32, 61, 32, 52, 10, 108, 111, 99, 97, 108, 32, 109, 97, 120, 100, 101, 112, 116, 104, 32, 61, 32, 109, 105, 110, 100, 101, 112, 116, 104, 32, 43, 32, 50, 10, 105, 102, 32, 109, 97, 120, 100, 101, 112, 116, 104, 32, 60, 32, 78, 32, 116, 104, 101, 110, 32, 109, 97, 120, 100, 101, 112, 116, 104, 32, 61, 32, 78, 32, 101, 110, 100, 10, 10, 100, 111, 10, 32, 32, 108, 111, 99, 97, 108, 32, 115, 116, 114, 101, 116, 99, 104, 100, 101, 112, 116, 104, 32, 61, 32, 109, 97, 120, 100, 101, 112, 116, 104, 32, 43, 32, 49, 10, 32, 32, 108, 111, 99, 97, 108, 32, 115, 116, 114, 101, 116, 99, 104, 116, 114, 101, 101, 32, 61, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 48, 44, 32, 115, 116, 114, 101, 116, 99, 104, 100, 101, 112, 116, 104, 41, 10, 32, 32, 105, 111, 46, 119, 114, 105, 116, 101, 40, 115, 116, 114, 105, 110, 103, 46, 102, 111, 114, 109, 97, 116, 40, 34, 115, 116, 114, 101, 116, 99, 104, 32, 116, 114, 101, 101, 32, 111, 102, 32, 100, 101, 112, 116, 104, 32, 37, 100, 92, 116, 32, 99, 104, 101, 99, 107, 58, 32, 37, 100, 92, 110, 34, 44, 10, 32, 32, 32, 32, 115, 116, 114, 101, 116, 99, 104, 100, 101, 112, 116, 104, 44, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 115, 116, 114, 101, 116, 99, 104, 116, 114, 101, 101, 41, 41, 41, 10, 101, 110, 100, 10, 10, 108, 111, 99, 97, 108, 32, 108, 111, 110, 103, 108, 105, 118, 101, 100, 116, 114, 101, 101, 32, 61, 32, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 48, 44, 32, 109, 97, 120, 100, 101, 112, 116, 104, 41, 10, 10, 102, 111, 114, 32, 100, 101, 112, 116, 104, 61, 109, 105, 110, 100, 101, 112, 116, 104, 44, 109, 97, 120, 100, 101, 112, 116, 104, 44, 50, 32, 100, 111, 10, 32, 32, 108, 111, 99, 97, 108, 32, 105, 116, 101, 114, 97, 116, 105, 111, 110, 115, 32, 61, 32, 50, 32, 94, 32, 40, 109, 97, 120, 100, 101, 112, 116, 104, 32, 45, 32, 100, 101, 112, 116, 104, 32, 43, 32, 109, 105, 110, 100, 101, 112, 116, 104, 41, 10, 32, 32, 108, 111, 99, 97, 108, 32, 99, 104, 101, 99, 107, 32, 61, 32, 48, 10, 32, 32, 102, 111, 114, 32, 105, 61, 49, 44, 105, 116, 101, 114, 97, 116, 105, 111, 110, 115, 32, 100, 111, 10, 32, 32, 32, 32, 99, 104, 101, 99, 107, 32, 61, 32, 99, 104, 101, 99, 107, 32, 43, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 49, 44, 32, 100, 101, 112, 116, 104, 41, 41, 32, 43, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 66, 111, 116, 116, 111, 109, 85, 112, 84, 114, 101, 101, 40, 45, 49, 44, 32, 100, 101, 112, 116, 104, 41, 41, 10, 32, 32, 101, 110, 100, 10, 32, 32, 105, 111, 46, 119, 114, 105, 116, 101, 40, 115, 116, 114, 105, 110, 103, 46, 102, 111, 114, 109, 97, 116, 40, 34, 37, 100, 92, 116, 32, 116, 114, 101, 101, 115, 32, 111, 102, 32, 100, 101, 112, 116, 104, 32, 37, 100, 92, 116, 32, 99, 104, 101, 99, 107, 58, 32, 37, 100, 92, 110, 34, 44, 10, 32, 32, 32, 32, 105, 116, 101, 114, 97, 116, 105, 111, 110, 115, 42, 50, 44, 32, 100, 101, 112, 116, 104, 44, 32, 99, 104, 101, 99, 107, 41, 41, 10, 101, 110, 100, 10, 10, 105, 111, 46, 119, 114, 105, 116, 101, 40, 115, 116, 114, 105, 110, 103, 46, 102, 111, 114, 109, 97, 116, 40, 34, 108, 111, 110, 103, 32, 108, 105, 118, 101, 100, 32, 116, 114, 101, 101, 32, 111, 102, 32, 100, 101, 112, 116, 104, 32, 37, 100, 92, 116, 32, 99, 104, 101, 99, 107, 58, 32, 37, 100, 92, 110, 34, 44, 10, 32, 32, 109, 97, 120, 100, 101, 112, 116, 104, 44, 32, 73, 116, 101, 109, 67, 104, 101, 99, 107, 40, 108, 111, 110, 103, 108, 105, 118, 101, 100, 116, 114, 101, 101, 41, 41, 41, 10], true, true);
+
+  }
+  if (Module['calledRun']) {
+    runWithFS();
+  } else {
+    if (!Module['preRun']) Module['preRun'] = [];
+    Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
+  }
+
+})();
+
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(13467);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([99,97,110,110,111,116,32,99,114,101,97,116,101,32,115,116,97,116,101,58,32,110,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121,0,0,40,101,114,114,111,114,32,111,98,106,101,99,116,32,105,115,32,110,111,116,32,97,32,115,116,114,105,110,103,41,0,0,88,0,0,0,0,0,0,0,108,117,97,0,0,0,0,0,76,85,65,95,78,79,69,78,86,0,0,0,0,0,0,0,116,111,111,32,109,97,110,121,32,114,101,115,117,108,116,115,32,116,111,32,112,114,105,110,116,0,0,0,0,0,0,0,112,114,105,110,116,0,0,0,101,114,114,111,114,32,99,97,108,108,105,110,103,32,39,112,114,105,110,116,39,32,40,37,115,41,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,105,110,116,101,114,114,117,112,116,101,100,33,0,0,0,0,95,95,116,111,115,116,114,105,110,103,0,0,0,0,0,0,40,110,111,32,101,114,114,111,114,32,109,101,115,115,97,103,101,41,0,0,0,0,0,0,61,115,116,100,105,110,0,0,60,101,111,102,62,0,0,0,114,101,116,117,114,110,32,37,115,0,0,0,0,0,0,0,95,80,82,79,77,80,84,0,95,80,82,79,77,80,84,50,0,0,0,0,0,0,0,0,62,32,0,0,0,0,0,0,62,62,32,0,0,0,0,0,97,114,103,0,0,0,0,0,45,0,0,0,0,0,0,0,45,45,0,0,0,0,0,0,116,111,111,32,109,97,110,121,32,97,114,103,117,109,101,110,116,115,32,116,111,32,115,99,114,105,112,116,0,0,0,0,61,40,99,111,109,109,97,110,100,32,108,105,110,101,41,0,114,101,113,117,105,114,101,0,61,76,85,65,95,73,78,73,84,95,53,95,50,0,0,0,61,76,85,65,95,73,78,73,84,0,0,0,0,0,0,0,76,117,97,32,53,46,50,46,50,32,32,67,111,112,121,114,105,103,104,116,32,40,67,41,32,49,57,57,52,45,50,48,49,51,32,76,117,97,46,111,114,103,44,32,80,85,67,45,82,105,111,0,0,0,0,0,37,115,58,32,0,0,0,0,39,37,115,39,32,110,101,101,100,115,32,97,114,103,117,109,101,110,116,10,0,0,0,0,117,110,114,101,99,111,103,110,105,122,101,100,32,111,112,116,105,111,110,32,39,37,115,39,10,0,0,0,0,0,0,0,117,115,97,103,101,58,32,37,115,32,91,111,112,116,105,111,110,115,93,32,91,115,99,114,105,112,116,32,91,97,114,103,115,93,93,10,65,118,97,105,108,97,98,108,101,32,111,112,116,105,111,110,115,32,97,114,101,58,10,32,32,45,101,32,115,116,97,116,32,32,101,120,101,99,117,116,101,32,115,116,114,105,110,103,32,39,115,116,97,116,39,10,32,32,45,105,32,32,32,32,32,32,32,101,110,116,101,114,32,105,110,116,101,114,97,99,116,105,118,101,32,109,111,100,101,32,97,102,116,101,114,32,101,120,101,99,117,116,105,110,103,32,39,115,99,114,105,112,116,39,10,32,32,45,108,32,110,97,109,101,32,32,114,101,113,117,105,114,101,32,108,105,98,114,97,114,121,32,39,110,97,109,101,39,10,32,32,45,118,32,32,32,32,32,32,32,115,104,111,119,32,118,101,114,115,105,111,110,32,105,110,102,111,114,109,97,116,105,111,110,10,32,32,45,69,32,32,32,32,32,32,32,105,103,110,111,114,101,32,101,110,118,105,114,111,110,109,101,110,116,32,118,97,114,105,97,98,108,101,115,10,32,32,45,45,32,32,32,32,32,32,32,115,116,111,112,32,104,97,110,100,108,105,110,103,32,111,112,116,105,111,110,115,10,32,32,45,32,32,32,32,32,32,32,32,115,116,111,112,32,104,97,110,100,108,105,110,103,32,111,112,116,105,111,110,115,32,97,110,100,32,101,120,101,99,117,116,101,32,115,116,100,105,110,10,0,0,0,0,0,0,0,37,115,10,0,0,0,0,0,0,0,0,0,0,96,127,64,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,115,10,0,0,0,0,0,115,116,97,99,107,32,116,114,97,99,101,98,97,99,107,58,0,0,0,0,0,0,0,0,10,9,46,46,46,0,0,0,83,108,110,116,0,0,0,0,10,9,37,115,58,0,0,0,37,100,58,0,0,0,0,0,32,105,110,32,0,0,0,0,10,9,40,46,46,46,116,97,105,108,32,99,97,108,108,115,46,46,46,41,0,0,0,0,98,97,100,32,97,114,103,117,109,101,110,116,32,35,37,100,32,40,37,115,41,0,0,0,110,0,0,0,0,0,0,0,109,101,116,104,111,100,0,0,99,97,108,108,105,110,103,32,39,37,115,39,32,111,110,32,98,97,100,32,115,101,108,102,32,40,37,115,41,0,0,0,63,0,0,0,0,0,0,0,98,97,100,32,97,114,103,117,109,101,110,116,32,35,37,100,32,116,111,32,39,37,115,39,32,40,37,115,41,0,0,0,83,108,0,0,0,0,0,0,37,115,58,37,100,58,32,0,0,0,0,0,0,0,0,0,37,115,58,32,37,115,0,0,101,120,105,116,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,39,37,115,39,0,0,0,0,0,115,116,97,99,107,32,111,118,101,114,102,108,111,119,32,40,37,115,41,0,0,0,0,0,115,116,97,99,107,32,111,118,101,114,102,108,111,119,0,0,118,97,108,117,101,32,101,120,112,101,99,116,101,100,0,0,98,117,102,102,101,114,32,116,111,111,32,108,97,114,103,101,0,0,0,0,0,0,0,0,61,115,116,100,105,110,0,0,64,37,115,0,0,0,0,0,114,0,0,0,0,0,0,0,111,112,101,110,0,0,0,0,114,98,0,0,0,0,0,0,114,101,111,112,101,110,0,0,114,101,97,100,0,0,0,0,111,98,106,101,99,116,32,108,101,110,103,116,104,32,105,115,32,110,111,116,32,97,32,110,117,109,98,101,114,0,0,0,95,95,116,111,115,116,114,105,110,103,0,0,0,0,0,0,116,114,117,101,0,0,0,0,102,97,108,115,101,0,0,0,110,105,108,0,0,0,0,0,37,115,58,32,37,112,0,0,95,76,79,65,68,69,68,0,110,97,109,101,32,99,111,110,102,108,105,99,116,32,102,111,114,32,109,111,100,117,108,101,32,39,37,115,39,0,0,0,116,111,111,32,109,97,110,121,32,117,112,118,97,108,117,101,115,0,0,0,0,0,0,0,109,117,108,116,105,112,108,101,32,76,117,97,32,86,77,115,32,100,101,116,101,99,116,101,100,0,0,0,0,0,0,0,118,101,114,115,105,111,110,32,109,105,115,109,97,116,99,104,58,32,97,112,112,46,32,110,101,101,100,115,32,37,102,44,32,76,117,97,32,99,111,114,101,32,112,114,111,118,105,100,101,115,32,37,102,0,0,0,98,97,100,32,99,111,110,118,101,114,115,105,111,110,32,110,117,109,98,101,114,45,62,105,110,116,59,32,109,117,115,116,32,114,101,99,111,109,112,105,108,101,32,76,117,97,32,119,105,116,104,32,112,114,111,112,101,114,32,115,101,116,116,105,110,103,115,0,0,0,0,0,80,65,78,73,67,58,32,117,110,112,114,111,116,101,99,116,101,100,32,101,114,114,111,114,32,105,110,32,99,97,108,108,32,116,111,32,76,117,97,32,65,80,73,32,40,37,115,41,10,0,0,0,0,0,0,0,239,187,191,0,0,0,0,0,99,97,110,110,111,116,32,37,115,32,37,115,58,32,37,115,0,0,0,0,0,0,0,0,37,115,32,101,120,112,101,99,116,101,100,44,32,103,111,116,32,37,115,0,0,0,0,0,102,0,0,0,0,0,0,0,46,0,0,0,0,0,0,0,102,117,110,99,116,105,111,110,32,39,37,115,39,0,0,0,109,97,105,110,32,99,104,117,110,107,0,0,0,0,0,0,102,117,110,99,116,105,111,110,32,60,37,115,58,37,100,62,0,0,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,37,115,32,37,115,32,39,37,115,39,32,40,97,32,37,115,32,118,97,108,117,101,41,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,37,115,32,97,32,37,115,32,118,97,108,117,101,0,0,0,0,0,0,0,0,99,111,110,99,97,116,101,110,97,116,101,0,0,0,0,0,112,101,114,102,111,114,109,32,97,114,105,116,104,109,101,116,105,99,32,111,110,0,0,0,97,116,116,101,109,112,116,32,116,111,32,99,111,109,112,97,114,101,32,116,119,111,32,37,115,32,118,97,108,117,101,115,0,0,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,99,111,109,112,97,114,101,32,37,115,32,119,105,116,104,32,37,115,0,0,0,37,115,58,37,100,58,32,37,115,0,0,0,0,0,0,0,108,111,99,97,108,0,0,0,95,69,78,86,0,0,0,0,103,108,111,98,97,108,0,0,102,105,101,108,100,0,0,0,117,112,118,97,108,117,101,0,99,111,110,115,116,97,110,116,0,0,0,0,0,0,0,0,109,101,116,104,111,100,0,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,102,111,114,32,105,116,101,114,97,116,111,114,0,0,0,0,109,101,116,97,109,101,116,104,111,100,0,0,0,0,0,0,61,91,67,93,0,0,0,0,67,0,0,0,0,0,0,0,61,63,0,0,0,0,0,0,109,97,105,110,0,0,0,0,76,117,97,0,0,0,0,0,40,42,116,101,109,112,111,114,97,114,121,41,0,0,0,0,40,42,118,97,114,97,114,103,41,0,0,0,0,0,0,0,115,116,97,99,107,32,111,118,101,114,102,108,111,119,0,0,67,32,115,116,97,99,107,32,111,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,121,105,101,108,100,32,97,99,114,111,115,115,32,97,32,67,45,99,97,108,108,32,98,111,117,110,100,97,114,121,0,0,0,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,121,105,101,108,100,32,102,114,111,109,32,111,117,116,115,105,100,101,32,97,32,99,111,114,111,117,116,105,110,101,0,0,0,0,0,0,0,98,105,110,97,114,121,0,0,116,101,120,116,0,0,0,0,97,116,116,101,109,112,116,32,116,111,32,108,111,97,100,32,97,32,37,115,32,99,104,117,110,107,32,40,109,111,100,101,32,105,115,32,39,37,115,39,41,0,0,0,0,0,0,0,101,114,114,111,114,32,105,110,32,101,114,114,111,114,32,104,97,110,100,108,105,110,103,0,99,97,110,110,111,116,32,114,101,115,117,109,101,32,110,111,110,45,115,117,115,112,101,110,100,101,100,32,99,111,114,111,117,116,105,110,101,0,0,0,99,97,110,110,111,116,32,114,101,115,117,109,101,32,100,101,97,100,32,99,111,114,111,117,116,105,110,101,0,0,0,0,99,97,108,108,0,0,0,0,110,111,32,109,101,115,115,97,103,101,0,0,0,0,0,0,101,114,114,111,114,32,105,110,32,95,95,103,99,32,109,101,116,97,109,101,116,104,111,100,32,40,37,115,41,0,0,0,95,80,82,69,76,79,65,68,0,0,0,0,0,0,0,0,95,71,0,0,0,0,0,0,112,97,99,107,97,103,101,0,99,111,114,111,117,116,105,110,101,0,0,0,0,0,0,0,116,97,98,108,101,0,0,0,105,111,0,0,0,0,0,0,111,115,0,0,0,0,0,0,115,116,114,105,110,103,0,0,98,105,116,51,50,0,0,0,109,97,116,104,0,0,0,0,100,101,98,117,103,0,0,0,144,11,0,0,1,0,0,0,152,11,0,0,2,0,0,0,48,13,0,0,3,0,0,0,160,11,0,0,4,0,0,0,56,13,0,0,5,0,0,0,64,13,0,0,6,0,0,0,72,13,0,0,7,0,0,0,168,11,0,0,8,0,0,0,80,13,0,0,9,0,0,0,88,13,0,0,10,0,0,0,192,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,95,73,79,95,105,110,112,117,116,0,0,0,0,0,0,0,115,116,100,105,110,0,0,0,95,73,79,95,111,117,116,112,117,116,0,0,0,0,0,0,115,116,100,111,117,116,0,0,115,116,100,101,114,114,0,0,70,73,76,69,42,0,0,0,99,97,110,110,111,116,32,99,108,111,115,101,32,115,116,97,110,100,97,114,100,32,102,105,108,101,0,0,0,0,0,0,95,95,105,110,100,101,120,0,144,11,0,0,1,0,0,0,152,11,0,0,12,0,0,0,160,11,0,0,13,0,0,0,168,11,0,0,14,0,0,0,176,11,0,0,15,0,0,0,184,11,0,0,16,0,0,0,192,11,0,0,17,0,0,0,200,11,0,0,18,0,0,0,208,11,0,0,19,0,0,0,0,0,0,0,0,0,0,0,99,108,111,115,101,0,0,0,102,108,117,115,104,0,0,0,108,105,110,101,115,0,0,0,114,101,97,100,0,0,0,0,115,101,101,107,0,0,0,0,115,101,116,118,98,117,102,0,119,114,105,116,101,0,0,0,95,95,103,99,0,0,0,0,95,95,116,111,115,116,114,105,110,103,0,0,0,0,0,0,102,105,108,101,32,40,99,108,111,115,101,100,41,0,0,0,102,105,108,101,32,40,37,112,41,0,0,0,0,0,0,0,37,46,49,52,103,0,0,0,97,116,116,101,109,112,116,32,116,111,32,117,115,101,32,97,32,99,108,111,115,101,100,32,102,105,108,101,0,0,0,0,2,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,72,12,0,0,80,12,0,0,88,12,0,0,0,0,0,0,110,111,0,0,0,0,0,0,102,117,108,108,0,0,0,0,108,105,110,101,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,128,12,0,0,136,12,0,0,144,12,0,0,0,0,0,0,115,101,116,0,0,0,0,0,99,117,114,0,0,0,0,0,101,110,100,0,0,0,0,0,110,111,116,32,97,110,32,105,110,116,101,103,101,114,32,105,110,32,112,114,111,112,101,114,32,114,97,110,103,101,0,0,116,111,111,32,109,97,110,121,32,97,114,103,117,109,101,110,116,115,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,0,0,105,110,118,97,108,105,100,32,102,111,114,109,97,116,0,0,37,108,102,0,0,0,0,0,116,111,111,32,109,97,110,121,32,111,112,116,105,111,110,115,0,0,0,0,0,0,0,0,102,105,108,101,32,105,115,32,97,108,114,101,97,100,121,32,99,108,111,115,101,100,0,0,37,115,0,0,0,0,0,0,105,110,112,117,116,0,0,0,111,112,101,110,0,0,0,0,111,117,116,112,117,116,0,0,112,111,112,101,110,0,0,0,116,109,112,102,105,108,101,0,116,121,112,101,0,0,0,0,115,116,97,110,100,97,114,100,32,37,115,32,102,105,108,101,32,105,115,32,99,108,111,115,101,100,0,0,0,0,0,0,99,108,111,115,101,100,32,102,105,108,101,0,0,0,0,0,102,105,108,101,0,0,0,0,114,0,0,0,0,0,0,0,39,112,111,112,101,110,39,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,0,0,119,0,0,0,0,0,0,0,99,97,110,110,111,116,32,111,112,101,110,32,102,105,108,101,32,39,37,115,39,32,40,37,115,41,0,0,0,0,0,0,114,119,97,0,0,0,0,0,105,110,118,97,108,105,100,32,109,111,100,101,0,0,0,0,240,14,0,0,20,0,0,0,248,14,0,0,21,0,0,0,0,15,0,0,22,0,0,0,8,15,0,0,23,0,0,0,16,15,0,0,24,0,0,0,24,15,0,0,25,0,0,0,32,15,0,0,26,0,0,0,40,15,0,0,27,0,0,0,48,15,0,0,28,0,0,0,56,15,0,0,29,0,0,0,64,15,0,0,30,0,0,0,72,15,0,0,31,0,0,0,80,15,0,0,32,0,0,0,88,15,0,0,33,0,0,0,96,15,0,0,34,0,0,0,104,15,0,0,35,0,0,0,112,15,0,0,36,0,0,0,120,15,0,0,37,0,0,0,128,15,0,0,38,0,0,0,136,15,0,0,39,0,0,0,144,15,0,0,40,0,0,0,152,15,0,0,41,0,0,0,160,15,0,0,42,0,0,0,176,15,0,0,43,0,0,0,184,15,0,0,44,0,0,0,192,15,0,0,45,0,0,0,200,15,0,0,46,0,0,0,208,15,0,0,47,0,0,0,0,0,0,0,0,0,0,0,112,105,0,0,0,0,0,0,104,117,103,101,0,0,0,0,97,98,115,0,0,0,0,0,97,99,111,115,0,0,0,0,97,115,105,110,0,0,0,0,97,116,97,110,50,0,0,0,97,116,97,110,0,0,0,0,99,101,105,108,0,0,0,0,99,111,115,104,0,0,0,0,99,111,115,0,0,0,0,0,100,101,103,0,0,0,0,0,101,120,112,0,0,0,0,0,102,108,111,111,114,0,0,0,102,109,111,100,0,0,0,0,102,114,101,120,112,0,0,0,108,100,101,120,112,0,0,0,108,111,103,49,48,0,0,0,108,111,103,0,0,0,0,0,109,97,120,0,0,0,0,0,109,105,110,0,0,0,0,0,109,111,100,102,0,0,0,0,112,111,119,0,0,0,0,0,114,97,100,0,0,0,0,0,114,97,110,100,111,109,0,0,114,97,110,100,111,109,115,101,101,100,0,0,0,0,0,0,115,105,110,104,0,0,0,0,115,105,110,0,0,0,0,0,115,113,114,116,0,0,0,0,116,97,110,104,0,0,0,0,116,97,110,0,0,0,0,0,105,110,116,101,114,118,97,108,32,105,115,32,101,109,112,116,121,0,0,0,0,0,0,0,119,114,111,110,103,32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,0,0,0,0,0,0,0,116,111,111,32,109,97,110,121,32,37,115,32,40,108,105,109,105,116,32,105,115,32,37,100,41,0,0,0,0,0,0,0,109,101,109,111,114,121,32,97,108,108,111,99,97,116,105,111,110,32,101,114,114,111,114,58,32,98,108,111,99,107,32,116,111,111,32,98,105,103,0,0,95,67,76,73,66,83,0,0,95,95,103,99,0,0,0,0,16,20,0,0,48,0,0,0,24,20,0,0,49,0,0,0,40,20,0,0,50,0,0,0,0,0,0,0,0,0,0,0,108,111,97,100,101,114,115,0,115,101,97,114,99,104,101,114,115,0,0,0,0,0,0,0,112,97,116,104,0,0,0,0,76,85,65,95,80,65,84,72,95,53,95,50,0,0,0,0,76,85,65,95,80,65,84,72,0,0,0,0,0,0,0,0,47,117,115,114,47,108,111,99,97,108,47,115,104,97,114,101,47,108,117,97,47,53,46,50,47,63,46,108,117,97,59,47,117,115,114,47,108,111,99,97,108,47,115,104,97,114,101,47,108,117,97,47,53,46,50,47,63,47,105,110,105,116,46,108,117,97,59,47,117,115,114,47,108,111,99,97,108,47,108,105,98,47,108,117,97,47,53,46,50,47,63,46,108,117,97,59,47,117,115,114,47,108,111,99,97,108,47,108,105,98,47,108,117,97,47,53,46,50,47,63,47,105,110,105,116,46,108,117,97,59,46,47,63,46,108,117,97,0,0,0,0,0,0,0,99,112,97,116,104,0,0,0,76,85,65,95,67,80,65,84,72,95,53,95,50,0,0,0,76,85,65,95,67,80,65,84,72,0,0,0,0,0,0,0,47,117,115,114,47,108,111,99,97,108,47,108,105,98,47,108,117,97,47,53,46,50,47,63,46,115,111,59,47,117,115,114,47,108,111,99,97,108,47,108,105,98,47,108,117,97,47,53,46,50,47,108,111,97,100,97,108,108,46,115,111,59,46,47,63,46,115,111,0,0,0,0,47,10,59,10,63,10,33,10,45,10,0,0,0,0,0,0,99,111,110,102,105,103,0,0,95,76,79,65,68,69,68,0,108,111,97,100,101,100,0,0,95,80,82,69,76,79,65,68,0,0,0,0,0,0,0,0,112,114,101,108,111,97,100,0,32,18,0,0,51,0,0,0,40,18,0,0,52,0,0,0,0,0,0,0,0,0,0,0,109,111,100,117,108,101,0,0,114,101,113,117,105,114,101,0,39,112,97,99,107,97,103,101,46,115,101,97,114,99,104,101,114,115,39,32,109,117,115,116,32,98,101,32,97,32,116,97,98,108,101,0,0,0,0,0,109,111,100,117,108,101,32,39,37,115,39,32,110,111,116,32,102,111,117,110,100,58,37,115,0,0,0,0,0,0,0,0,95,78,65,77,69,0,0,0,102,0,0,0,0,0,0,0,39,109,111,100,117,108,101,39,32,110,111,116,32,99,97,108,108,101,100,32,102,114,111,109,32,97,32,76,117,97,32,102,117,110,99,116,105,111,110,0,95,77,0,0,0,0,0,0,95,80,65,67,75,65,71,69,0,0,0,0,0,0,0,0,59,59,0,0,0,0,0,0,59,1,59,0,0,0,0,0,1,0,0,0,0,0,0,0,76,85,65,95,78,79,69,78,86,0,0,0,0,0,0,0,47,0,0,0,0,0,0,0,10,9,110,111,32,109,111,100,117,108,101,32,39,37,115,39,32,105,110,32,102,105,108,101,32,39,37,115,39,0,0,0,101,114,114,111,114,32,108,111,97,100,105,110,103,32,109,111,100,117,108,101,32,39,37,115,39,32,102,114,111,109,32,102,105,108,101,32,39,37,115,39,58,10,9,37,115,0,0,0,46,0,0,0,0,0,0,0,95,0,0,0,0,0,0,0,108,117,97,111,112,101,110,95,37,115,0,0,0,0,0,0,100,121,110,97,109,105,99,32,108,105,98,114,97,114,105,101,115,32,110,111,116,32,101,110,97,98,108,101,100,59,32,99,104,101,99,107,32,121,111,117,114,32,76,117,97,32,105,110,115,116,97,108,108,97,116,105,111,110,0,0,0,0,0,0,39,112,97,99,107,97,103,101,46,37,115,39,32,109,117,115,116,32,98,101,32,97,32,115,116,114,105,110,103,0,0,0,63,0,0,0,0,0,0,0,10,9,110,111,32,102,105,108,101,32,39,37,115,39,0,0,114,0,0,0,0,0,0,0,10,9,110,111,32,102,105,101,108,100,32,112,97,99,107,97,103,101,46,112,114,101,108,111,97,100,91,39,37,115,39,93,0,0,0,0,0,0,0,0,108,111,97,100,108,105,98,0,115,101,97,114,99,104,112,97,116,104,0,0,0,0,0,0,115,101,101,97,108,108,0,0,95,95,105,110,100,101,120,0,97,98,115,101,110,116,0,0,105,110,105,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,110,78,0,0,0,0,0,0,120,88,0,0,0,0,0,0,40,110,117,108,108,41,0,0,37,112,0,0,0,0,0,0,37,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,39,37,37,37,99,39,32,116,111,32,39,108,117,97,95,112,117,115,104,102,115,116,114,105,110,103,39,0,0,0,0,0,0,46,46,46,0,0,0,0,0,91,115,116,114,105,110,103,32,34,0,0,0,0,0,0,0,34,93,0,0,0,0,0,0,96,113,65,84,80,80,92,108,60,16,60,84,108,124,124,124,124,124,124,96,96,96,104,34,188,188,188,132,228,84,84,16,98,98,4,98,20,81,80,23,88,22,0,0,53,0,0,0,96,22,0,0,54,0,0,0,104,22,0,0,55,0,0,0,120,22,0,0,56,0,0,0,128,22,0,0,57,0,0,0,136,22,0,0,58,0,0,0,144,22,0,0,59,0,0,0,152,22,0,0,60,0,0,0,160,22,0,0,61,0,0,0,176,22,0,0,62,0,0,0,184,22,0,0,63,0,0,0,0,0,0,0,0,0,0,0,99,108,111,99,107,0,0,0,100,97,116,101,0,0,0,0,100,105,102,102,116,105,109,101,0,0,0,0,0,0,0,0,101,120,101,99,117,116,101,0,101,120,105,116,0,0,0,0,103,101,116,101,110,118,0,0,114,101,109,111,118,101,0,0,114,101,110,97,109,101,0,0,115,101,116,108,111,99,97,108,101,0,0,0,0,0,0,0,116,105,109,101,0,0,0,0,116,109,112,110,97,109,101,0,117,110,97,98,108,101,32,116,111,32,103,101,110,101,114,97,116,101,32,97,32,117,110,105,113,117,101,32,102,105,108,101,110,97,109,101,0,0,0,0,115,101,99,0,0,0,0,0,109,105,110,0,0,0,0,0,104,111,117,114,0,0,0,0,100,97,121,0,0,0,0,0,109,111,110,116,104,0,0,0,121,101,97,114,0,0,0,0,105,115,100,115,116,0,0,0,102,105,101,108,100,32,39,37,115,39,32,109,105,115,115,105,110,103,32,105,110,32,100,97,116,101,32,116,97,98,108,101,0,0,0,0,0,0,0,0,6,0,0,0,3,0,0,0,0,0,0,0,4,0,0,0,1,0,0,0,2,0,0,0,128,23,0,0,136,23,0,0,144,23,0,0,152,23,0,0,168,23,0,0,176,22,0,0,0,0,0,0,0,0,0,0,97,108,108,0,0,0,0,0,99,111,108,108,97,116,101,0,99,116,121,112,101,0,0,0,109,111,110,101,116,97,114,121,0,0,0,0,0,0,0,0,110,117,109,101,114,105,99,0,37,99,0,0,0,0,0,0,42,116,0,0,0,0,0,0,119,100,97,121,0,0,0,0,121,100,97,121,0,0,0,0,97,65,98,66,99,100,72,73,106,109,77,112,83,85,119,87,120,88,121,89,122,37,0,0,105,110,118,97,108,105,100,32,99,111,110,118,101,114,115,105,111,110,32,115,112,101,99,105,102,105,101,114,32,39,37,37,37,115,39,0,0,0,0,0,60,37,115,62,32,97,116,32,108,105,110,101,32,37,100,32,110,111,116,32,105,110,115,105,100,101,32,97,32,108,111,111,112,0,0,0,0,0,0,0,110,111,32,118,105,115,105,98,108,101,32,108,97,98,101,108,32,39,37,115,39,32,102,111,114,32,60,103,111,116,111,62,32,97,116,32,108,105,110,101,32,37,100,0,0,0,0,0,60,103,111,116,111,32,37,115,62,32,97,116,32,108,105,110,101,32,37,100,32,106,117,109,112,115,32,105,110,116,111,32,116,104,101,32,115,99,111,112,101,32,111,102,32,108,111,99,97,108,32,39,37,115,39,0,98,114,101,97,107,0,0,0,108,97,98,101,108,115,47,103,111,116,111,115,0,0,0,0,37,115,32,101,120,112,101,99,116,101,100,0,0,0,0,0,115,121,110,116,97,120,32,101,114,114,111,114,0,0,0,0,67,32,108,101,118,101,108,115,0,0,0,0,0,0,0,0,6,6,6,6,7,7,7,7,7,7,10,9,5,4,3,3,3,3,3,3,3,3,3,3,3,3,2,2,1,1,0,0,99,97,110,110,111,116,32,117,115,101,32,39,46,46,46,39,32,111,117,116,115,105,100,101,32,97,32,118,97,114,97,114,103,32,102,117,110,99,116,105,111,110,0,0,0,0,0,0,115,101,108,102,0,0,0,0,60,110,97,109,101,62,32,111,114,32,39,46,46,46,39,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,0,0,108,111,99,97,108,32,118,97,114,105,97,98,108,101,115,0,102,117,110,99,116,105,111,110,115,0,0,0,0,0,0,0,105,116,101,109,115,32,105,110,32,97,32,99,111,110,115,116,114,117,99,116,111,114,0,0,109,97,105,110,32,102,117,110,99,116,105,111,110,0,0,0,102,117,110,99,116,105,111,110,32,97,116,32,108,105,110,101,32,37,100,0,0,0,0,0,116,111,111,32,109,97,110,121,32,37,115,32,40,108,105,109,105,116,32,105,115,32,37,100,41,32,105,110,32,37,115,0,102,117,110,99,116,105,111,110,32,97,114,103,117,109,101,110,116,115,32,101,120,112,101,99,116,101,100,0,0,0,0,0,117,110,101,120,112,101,99,116,101,100,32,115,121,109,98,111,108,0,0,0,0,0,0,0,108,97,98,101,108,32,39,37,115,39,32,97,108,114,101,97,100,121,32,100,101,102,105,110,101,100,32,111,110,32,108,105,110,101,32,37,100,0,0,0,39,61,39,32,111,114,32,39,105,110,39,32,101,120,112,101,99,116,101,100,0,0,0,0,40,102,111,114,32,103,101,110,101,114,97,116,111,114,41,0,40,102,111,114,32,115,116,97,116,101,41,0,0,0,0,0,40,102,111,114,32,99,111,110,116,114,111,108,41,0,0,0,40,102,111,114,32,105,110,100,101,120,41,0,0,0,0,0,40,102,111,114,32,108,105,109,105,116,41,0,0,0,0,0,40,102,111,114,32,115,116,101,112,41,0,0,0,0,0,0,37,115,32,101,120,112,101,99,116,101,100,32,40,116,111,32,99,108,111,115,101,32,37,115,32,97,116,32,108,105,110,101,32,37,100,41,0,0,0,0,117,112,118,97,108,117,101,115,0,0,0,0,0,0,0,0,110,111,116,32,101,110,111,117,103,104,32,109,101,109,111,114,121,0,0,0,0,0,0,0,144,27,0,0,64,0,0,0,152,27,0,0,65,0,0,0,160,27,0,0,66,0,0,0,168,27,0,0,67,0,0,0,176,27,0,0,68,0,0,0,184,27,0,0,69,0,0,0,192,27,0,0,70,0,0,0,200,27,0,0,71,0,0,0,208,27,0,0,72,0,0,0,216,27,0,0,73,0,0,0,224,27,0,0,74,0,0,0,232,27,0,0,75,0,0,0,240,27,0,0,76,0,0,0,248,27,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,95,105,110,100,101,120,0,98,121,116,101,0,0,0,0,99,104,97,114,0,0,0,0,100,117,109,112,0,0,0,0,102,105,110,100,0,0,0,0,102,111,114,109,97,116,0,0,103,109,97,116,99,104,0,0,103,115,117,98,0,0,0,0,108,101,110,0,0,0,0,0,108,111,119,101,114,0,0,0,109,97,116,99,104,0,0,0,114,101,112,0,0,0,0,0,114,101,118,101,114,115,101,0,115,117,98,0,0,0,0,0,117,112,112,101,114,0,0,0,114,101,115,117,108,116,105,110,103,32,115,116,114,105,110,103,32,116,111,111,32,108,97,114,103,101,0,0,0,0,0,0,116,111,111,32,109,97,110,121,32,99,97,112,116,117,114,101,115,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,99,97,112,116,117,114,101,32,105,110,100,101,120,0,0,0,117,110,102,105,110,105,115,104,101,100,32,99,97,112,116,117,114,101,0,0,0,0,0,0,112,97,116,116,101,114,110,32,116,111,111,32,99,111,109,112,108,101,120,0,0,0,0,0,109,105,115,115,105,110,103,32,39,91,39,32,97,102,116,101,114,32,39,37,37,102,39,32,105,110,32,112,97,116,116,101,114,110,0,0,0,0,0,0,105,110,118,97,108,105,100,32,99,97,112,116,117,114,101,32,105,110,100,101,120,32,37,37,37,100,0,0,0,0,0,0,109,97,108,102,111,114,109,101,100,32,112,97,116,116,101,114,110,32,40,101,110,100,115,32,119,105,116,104,32,39,37,37,39,41,0,0,0,0,0,0,109,97,108,102,111,114,109,101,100,32,112,97,116,116,101,114,110,32,40,109,105,115,115,105,110,103,32,39,93,39,41,0,109,97,108,102,111,114,109,101,100,32,112,97,116,116,101,114,110,32,40,109,105,115,115,105,110,103,32,97,114,103,117,109,101,110,116,115,32,116,111,32,39,37,37,98,39,41,0,0,105,110,118,97,108,105,100,32,112,97,116,116,101,114,110,32,99,97,112,116,117,114,101,0,94,36,42,43,63,46,40,91,37,45,0,0,0,0,0,0,115,116,114,105,110,103,47,102,117,110,99,116,105,111,110,47,116,97,98,108,101,32,101,120,112,101,99,116,101,100,0,0,105,110,118,97,108,105,100,32,114,101,112,108,97,99,101,109,101,110,116,32,118,97,108,117,101,32,40,97,32,37,115,41,0,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,117,115,101,32,111,102,32,39,37,99,39,32,105,110,32,114,101,112,108,97,99,101,109,101,110,116,32,115,116,114,105,110,103,0,0,0,0,0,0,0,110,111,32,118,97,108,117,101,0,0,0,0,0,0,0,0,110,111,116,32,97,32,110,117,109,98,101,114,32,105,110,32,112,114,111,112,101,114,32,114,97,110,103,101,0,0,0,0,110,111,116,32,97,32,110,111,110,45,110,101,103,97,116,105,118,101,32,110,117,109,98,101,114,32,105,110,32,112,114,111,112,101,114,32,114,97,110,103,101,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,32,39,37,37,37,99,39,32,116,111,32,39,102,111,114,109,97,116,39,0,0,0,0,0,0,0,92,37,100,0,0,0,0,0,92,37,48,51,100,0,0,0,45,43,32,35,48,0,0,0,105,110,118,97,108,105,100,32,102,111,114,109,97,116,32,40,114,101,112,101,97,116,101,100,32,102,108,97,103,115,41,0,105,110,118,97,108,105,100,32,102,111,114,109,97,116,32,40,119,105,100,116,104,32,111,114,32,112,114,101,99,105,115,105,111,110,32,116,111,111,32,108,111,110,103,41,0,0,0,0,117,110,97,98,108,101,32,116,111,32,100,117,109,112,32,103,105,118,101,110,32,102,117,110,99,116,105,111,110,0,0,0,118,97,108,117,101,32,111,117,116,32,111,102,32,114,97,110,103,101,0,0,0,0,0,0,115,116,114,105,110,103,32,115,108,105,99,101,32,116,111,111,32,108,111,110,103,0,0,0,116,97,98,108,101,32,105,110,100,101,120,32,105,115,32,110,105,108,0,0,0,0,0,0,116,97,98,108,101,32,105,110,100,101,120,32,105,115,32,78,97,78,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,116,97,98,108,101,32,111,118,101,114,102,108,111,119,0,0,105,110,118,97,108,105,100,32,107,101,121,32,116,111,32,39,110,101,120,116,39,0,0,0,224,31,0,0,78,0,0,0,232,31,0,0,79,0,0,0,240,31,0,0,80,0,0,0,248,31,0,0,81,0,0,0,216,31,0,0,82,0,0,0,0,32,0,0,83,0,0,0,8,32,0,0,84,0,0,0,0,0,0,0,0,0,0,0,117,110,112,97,99,107,0,0,99,111,110,99,97,116,0,0,109,97,120,110,0,0,0,0,105,110,115,101,114,116,0,0,112,97,99,107,0,0,0,0,114,101,109,111,118,101,0,0,115,111,114,116,0,0,0,0,0,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,114,100,101,114,32,102,117,110,99,116,105,111,110,32,102,111,114,32,115,111,114,116,105,110,103,0,0,0,0,0,0,112,111,115,105,116,105,111,110,32,111,117,116,32,111,102,32,98,111,117,110,100,115,0,0,116,111,111,32,109,97,110,121,32,114,101,115,117,108,116,115,32,116,111,32,117,110,112,97,99,107,0,0,0,0,0,0,110,0,0,0,0,0,0,0,119,114,111,110,103,32,110,117,109,98,101,114,32,111,102,32,97,114,103,117,109,101,110,116,115,32,116,111,32,39,105,110,115,101,114,116,39,0,0,0,105,110,118,97,108,105,100,32,118,97,108,117,101,32,40,37,115,41,32,97,116,32,105,110,100,101,120,32,37,100,32,105,110,32,116,97,98,108,101,32,102,111,114,32,39,99,111,110,99,97,116,39,0,0,0,0,110,111,32,118,97,108,117,101,0,0,0,0,0,0,0,0,110,105,108,0,0,0,0,0,98,111,111,108,101,97,110,0,117,115,101,114,100,97,116,97,0,0,0,0,0,0,0,0,110,117,109,98,101,114,0,0,115,116,114,105,110,103,0,0,116,97,98,108,101,0,0,0,102,117,110,99,116,105,111,110,0,0,0,0,0,0,0,0,116,104,114,101,97,100,0,0,112,114,111,116,111,0,0,0,117,112,118,97,108,0,0,0,224,32,0,0,240,32,0,0,248,32,0,0,0,33,0,0,16,33,0,0,24,33,0,0,32,33,0,0,40,33,0,0,0,33,0,0,56,33,0,0,64,33,0,0,72,33,0,0,200,33,0,0,208,33,0,0,224,33,0,0,232,33,0,0,240,33,0,0,248,33,0,0,0,34,0,0,8,34,0,0,16,34,0,0,24,34,0,0,32,34,0,0,40,34,0,0,48,34,0,0,56,34,0,0,64,34,0,0,72,34,0,0,88,34,0,0,0,0,0,0,95,95,105,110,100,101,120,0,95,95,110,101,119,105,110,100,101,120,0,0,0,0,0,0,95,95,103,99,0,0,0,0,95,95,109,111,100,101,0,0,95,95,108,101,110,0,0,0,95,95,101,113,0,0,0,0,95,95,97,100,100,0,0,0,95,95,115,117,98,0,0,0,95,95,109,117,108,0,0,0,95,95,100,105,118,0,0,0,95,95,109,111,100,0,0,0,95,95,112,111,119,0,0,0,95,95,117,110,109,0,0,0,95,95,108,116,0,0,0,0,95,95,108,101,0,0,0,0,95,95,99,111,110,99,97,116,0,0,0,0,0,0,0,0,95,95,99,97,108,108,0,0,98,105,110,97,114,121,32,115,116,114,105,110,103,0,0,0,25,147,13,10,26,10,0,0,116,114,117,110,99,97,116,101,100,0,0,0,0,0,0,0,37,115,58,32,37,115,32,112,114,101,99,111,109,112,105,108,101,100,32,99,104,117,110,107,0,0,0,0,0,0,0,0,99,111,114,114,117,112,116,101,100,0,0,0,0,0,0,0,110,111,116,32,97,0,0,0,118,101,114,115,105,111,110,32,109,105,115,109,97,116,99,104,32,105,110,0,0,0,0,0,105,110,99,111,109,112,97,116,105,98,108,101,0,0,0,0,37,46,49,52,103,0,0,0,105,110,100,101,120,0,0,0,108,111,111,112,32,105,110,32,103,101,116,116,97,98,108,101,0,0,0,0,0,0,0,0,108,111,111,112,32,105,110,32,115,101,116,116,97,98,108,101,0,0,0,0,0,0,0,0,115,116,114,105,110,103,32,108,101,110,103,116,104,32,111,118,101,114,102,108,111,119,0,0,103,101,116,32,108,101,110,103,116,104,32,111,102,0,0,0,39,102,111,114,39,32,105,110,105,116,105,97,108,32,118,97,108,117,101,32,109,117,115,116,32,98,101,32,97,32,110,117,109,98,101,114,0,0,0,0,39,102,111,114,39,32,108,105,109,105,116,32,109,117,115,116,32,98,101,32,97,32,110,117,109,98,101,114,0,0,0,0,39,102,111,114,39,32,115,116,101,112,32,109,117,115,116,32,98,101,32,97,32,110,117,109,98,101,114,0,0,0,0,0,95,71,0,0,0,0,0,0,152,36,0,0,85,0,0,0,160,36,0,0,86,0,0,0,176,36,0,0,87,0,0,0,184,36,0,0,88,0,0,0,192,36,0,0,89,0,0,0,208,36,0,0,90,0,0,0,216,36,0,0,91,0,0,0,232,36,0,0,92,0,0,0,240,36,0,0,92,0,0,0,0,37,0,0,93,0,0,0,8,37,0,0,94,0,0,0,16,37,0,0,95,0,0,0,24,37,0,0,96,0,0,0,32,37,0,0,97,0,0,0,48,37,0,0,98,0,0,0,56,37,0,0,99,0,0,0,64,37,0,0,100,0,0,0,72,37,0,0,101,0,0,0,80,37,0,0,102,0,0,0,96,37,0,0,103,0,0,0,112,37,0,0,104,0,0,0,128,37,0,0,105,0,0,0,136,37,0,0,106,0,0,0,0,0,0,0,0,0,0,0,76,117,97,32,53,46,50,0,95,86,69,82,83,73,79,78,0,0,0,0,0,0,0,0,97,115,115,101,114,116,0,0,99,111,108,108,101,99,116,103,97,114,98,97,103,101,0,0,100,111,102,105,108,101,0,0,101,114,114,111,114,0,0,0,103,101,116,109,101,116,97,116,97,98,108,101,0,0,0,0,105,112,97,105,114,115,0,0,108,111,97,100,102,105,108,101,0,0,0,0,0,0,0,0,108,111,97,100,0,0,0,0,108,111,97,100,115,116,114,105,110,103,0,0,0,0,0,0,110,101,120,116,0,0,0,0,112,97,105,114,115,0,0,0,112,99,97,108,108,0,0,0,112,114,105,110,116,0,0,0,114,97,119,101,113,117,97,108,0,0,0,0,0,0,0,0,114,97,119,108,101,110,0,0,114,97,119,103,101,116,0,0,114,97,119,115,101,116,0,0,115,101,108,101,99,116,0,0,115,101,116,109,101,116,97,116,97,98,108,101,0,0,0,0,116,111,110,117,109,98,101,114,0,0,0,0,0,0,0,0,116,111,115,116,114,105,110,103,0,0,0,0,0,0,0,0,116,121,112,101,0,0,0,0,120,112,99,97,108,108,0,0,118,97,108,117,101,32,101,120,112,101,99,116,101,100,0,0,115,116,97,99,107,32,111,118,101,114,102,108,111,119,0,0,98,97,115,101,32,111,117,116,32,111,102,32,114,97,110,103,101,0,0,0,0,0,0,0,32,12,10,13,9,11,0,0,110,105,108,32,111,114,32,116,97,98,108,101,32,101,120,112,101,99,116,101,100,0,0,0,95,95,109,101,116,97,116,97,98,108,101,0,0,0,0,0,99,97,110,110,111,116,32,99,104,97,110,103,101,32,97,32,112,114,111,116,101,99,116,101,100,32,109,101,116,97,116,97,98,108,101,0,0,0,0,0,105,110,100,101,120,32,111,117,116,32,111,102,32,114,97,110,103,101,0,0,0,0,0,0,116,97,98,108,101,32,111,114,32,115,116,114,105,110,103,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,0,0,39,116,111,115,116,114,105,110,103,39,32,109,117,115,116,32,114,101,116,117,114,110,32,97,32,115,116,114,105,110,103,32,116,111,32,39,112,114,105,110,116,39,0,0,0,0,0,0,95,95,112,97,105,114,115,0,98,116,0,0,0,0,0,0,61,40,108,111,97,100,41,0,116,111,111,32,109,97,110,121,32,110,101,115,116,101,100,32,102,117,110,99,116,105,111,110,115,0,0,0,0,0,0,0,114,101,97,100,101,114,32,102,117,110,99,116,105,111,110,32,109,117,115,116,32,114,101,116,117,114,110,32,97,32,115,116,114,105,110,103,0,0,0,0,95,95,105,112,97,105,114,115,0,0,0,0,0,0,0,0,40,39,0,0,48,39,0,0,56,39,0,0,64,39,0,0,72,39,0,0,80,39,0,0,96,39,0,0,112,39,0,0,128,39,0,0,144,39,0,0,160,39,0,0,0,0,0,0,115,116,111,112,0,0,0,0,114,101,115,116,97,114,116,0,99,111,108,108,101,99,116,0,99,111,117,110,116,0,0,0,115,116,101,112,0,0,0,0,115,101,116,112,97,117,115,101,0,0,0,0,0,0,0,0,115,101,116,115,116,101,112,109,117,108,0,0,0,0,0,0,115,101,116,109,97,106,111,114,105,110,99,0,0,0,0,0,105,115,114,117,110,110,105,110,103,0,0,0,0,0,0,0,103,101,110,101,114,97,116,105,111,110,97,108,0,0,0,0,105,110,99,114,101,109,101,110,116,97,108,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,5,0,0,0,6,0,0,0,7,0,0,0,8,0,0,0,9,0,0,0,10,0,0,0,11,0,0,0,0,0,0,0,37,115,0,0,0,0,0,0,97,115,115,101,114,116,105,111,110,32,102,97,105,108,101,100,33,0,0,0,0,0,0,0,104,40,0,0,107], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+/* memory initializer */ allocate([112,40,0,0,108,0,0,0,120,40,0,0,109,0,0,0,128,40,0,0,110,0,0,0,136,40,0,0,111,0,0,0,144,40,0,0,112,0,0,0,152,40,0,0,113,0,0,0,160,40,0,0,114,0,0,0,168,40,0,0,115,0,0,0,176,40,0,0,116,0,0,0,184,40,0,0,117,0,0,0,192,40,0,0,118,0,0,0,0,0,0,0,0,0,0,0,97,114,115,104,105,102,116,0,98,97,110,100,0,0,0,0,98,110,111,116,0,0,0,0,98,111,114,0,0,0,0,0,98,120,111,114,0,0,0,0,98,116,101,115,116,0,0,0,101,120,116,114,97,99,116,0,108,114,111,116,97,116,101,0,108,115,104,105,102,116,0,0,114,101,112,108,97,99,101,0,114,114,111,116,97,116,101,0,114,115,104,105,102,116,0,0,102,105,101,108,100,32,99,97,110,110,111,116,32,98,101,32,110,101,103,97,116,105,118,101,0,0,0,0,0,0,0,0,119,105,100,116,104,32,109,117,115,116,32,98,101,32,112,111,115,105,116,105,118,101,0,0,116,114,121,105,110,103,32,116,111,32,97,99,99,101,115,115,32,110,111,110,45,101,120,105,115,116,101,110,116,32,98,105,116,115,0,0,0,0,0,0,102,117,110,99,116,105,111,110,32,111,114,32,101,120,112,114,101,115,115,105,111,110,32,116,111,111,32,99,111,109,112,108,101,120,0,0,0,0,0,0,99,111,110,115,116,114,117,99,116,111,114,32,116,111,111,32,108,111,110,103,0,0,0,0,99,111,110,115,116,97,110,116,115,0,0,0,0,0,0,0,111,112,99,111,100,101,115,0,99,111,110,116,114,111,108,32,115,116,114,117,99,116,117,114,101,32,116,111,111,32,108,111,110,103,0,0,0,0,0,0,216,41,0,0,119,0,0,0,224,41,0,0,120,0,0,0,232,41,0,0,121,0,0,0,240,41,0,0,122,0,0,0,248,41,0,0,123,0,0,0,0,42,0,0,124,0,0,0,0,0,0,0,0,0,0,0,99,114,101,97,116,101,0,0,114,101,115,117,109,101,0,0,114,117,110,110,105,110,103,0,115,116,97,116,117,115,0,0,119,114,97,112,0,0,0,0,121,105,101,108,100,0,0,0,116,111,111,32,109,97,110,121,32,97,114,103,117,109,101,110,116,115,32,116,111,32,114,101,115,117,109,101,0,0,0,0,99,97,110,110,111,116,32,114,101,115,117,109,101,32,100,101,97,100,32,99,111,114,111,117,116,105,110,101,0,0,0,0,116,111,111,32,109,97,110,121,32,114,101,115,117,108,116,115,32,116,111,32,114,101,115,117,109,101,0,0,0,0,0,0,99,111,114,111,117,116,105,110,101,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,115,117,115,112,101,110,100,101,100,0,0,0,0,0,0,0,110,111,114,109,97,108,0,0,100,101,97,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,8,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,22,22,22,22,22,22,22,22,22,22,4,4,4,4,4,4,4,21,21,21,21,21,21,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,5,4,21,21,21,21,21,21,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,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,0,0,0,0,0,0,0,0,48,44,0,0,125,0,0,0,56,44,0,0,126,0,0,0,72,44,0,0,127,0,0,0,80,44,0,0,128,0,0,0,88,44,0,0,129,0,0,0,104,44,0,0,130,0,0,0,120,44,0,0,131,0,0,0,136,44,0,0,132,0,0,0,152,44,0,0,133,0,0,0,168,44,0,0,134,0,0,0,184,44,0,0,135,0,0,0,200,44,0,0,136,0,0,0,208,44,0,0,137,0,0,0,224,44,0,0,138,0,0,0,240,44,0,0,139,0,0,0,0,45,0,0,140,0,0,0,0,0,0,0,0,0,0,0,100,101,98,117,103,0,0,0,103,101,116,117,115,101,114,118,97,108,117,101,0,0,0,0,103,101,116,104,111,111,107,0,103,101,116,105,110,102,111,0,103,101,116,108,111,99,97,108,0,0,0,0,0,0,0,0,103,101,116,114,101,103,105,115,116,114,121,0,0,0,0,0,103,101,116,109,101,116,97,116,97,98,108,101,0,0,0,0,103,101,116,117,112,118,97,108,117,101,0,0,0,0,0,0,117,112,118,97,108,117,101,106,111,105,110,0,0,0,0,0,117,112,118,97,108,117,101,105,100,0,0,0,0,0,0,0,115,101,116,117,115,101,114,118,97,108,117,101,0,0,0,0,115,101,116,104,111,111,107,0,115,101,116,108,111,99,97,108,0,0,0,0,0,0,0,0,115,101,116,109,101,116,97,116,97,98,108,101,0,0,0,0,115,101,116,117,112,118,97,108,117,101,0,0,0,0,0,0,116,114,97,99,101,98,97,99,107,0,0,0,0,0,0,0,110,105,108,32,111,114,32,116,97,98,108,101,32,101,120,112,101,99,116,101,100,0,0,0,108,101,118,101,108,32,111,117,116,32,111,102,32,114,97,110,103,101,0,0,0,0,0,0,95,72,75,69,89,0,0,0,107,0,0,0,0,0,0,0,95,95,109,111,100,101,0,0,112,45,0,0,120,45,0,0,128,45,0,0,136,45,0,0,144,45,0,0,0,0,0,0,99,97,108,108,0,0,0,0,114,101,116,117,114,110,0,0,108,105,110,101,0,0,0,0,99,111,117,110,116,0,0,0,116,97,105,108,32,99,97,108,108,0,0,0,0,0,0,0,102,117,108,108,32,117,115,101,114,100,97,116,97,32,101,120,112,101,99,116,101,100,44,32,103,111,116,32,108,105,103,104,116,32,117,115,101,114,100,97,116,97,0,0,0,0,0,0,62,117,0,0,0,0,0,0,105,110,118,97,108,105,100,32,117,112,118,97,108,117,101,32,105,110,100,101,120,0,0,0,76,117,97,32,102,117,110,99,116,105,111,110,32,101,120,112,101,99,116,101,100,0,0,0,102,108,110,83,116,117,0,0,62,37,115,0,0,0,0,0,102,117,110,99,116,105,111,110,32,111,114,32,108,101,118,101,108,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,105,110,118,97,108,105,100,32,111,112,116,105,111,110,0,0,115,111,117,114,99,101,0,0,115,104,111,114,116,95,115,114,99,0,0,0,0,0,0,0,108,105,110,101,100,101,102,105,110,101,100,0,0,0,0,0,108,97,115,116,108,105,110,101,100,101,102,105,110,101,100,0,119,104,97,116,0,0,0,0,99,117,114,114,101,110,116,108,105,110,101,0,0,0,0,0,110,117,112,115,0,0,0,0,110,112,97,114,97,109,115,0,105,115,118,97,114,97,114,103,0,0,0,0,0,0,0,0,110,97,109,101,0,0,0,0,110,97,109,101,119,104,97,116,0,0,0,0,0,0,0,0,105,115,116,97,105,108,99,97,108,108,0,0,0,0,0,0,97,99,116,105,118,101,108,105,110,101,115,0,0,0,0,0,102,117,110,99,0,0,0,0,101,120,116,101,114,110,97,108,32,104,111,111,107,0,0,0,108,117,97,95,100,101,98,117,103,62,32,0,0,0,0,0,99,111,110,116,10,0,0,0,61,40,100,101,98,117,103,32,99,111,109,109,97,110,100,41,0,0,0,0,0,0,0,0,37,115,10,0,0,0,0,0,80,49,0,0,88,49,0,0,96,49,0,0,104,49,0,0,112,49,0,0,120,49,0,0,128,49,0,0,136,49,0,0,144,49,0,0,160,49,0,0,168,49,0,0,176,49,0,0,184,49,0,0,192,49,0,0,200,49,0,0,208,49,0,0,216,49,0,0,224,49,0,0,232,49,0,0,240,49,0,0,248,49,0,0,0,50,0,0,8,50,0,0,16,50,0,0,24,50,0,0,32,50,0,0,40,50,0,0,48,50,0,0,56,50,0,0,64,50,0,0,72,50,0,0,88,50,0,0,96,50,0,0,0,0,0,0,39,37,99,39,0,0,0,0,99,104,97,114,40,37,100,41,0,0,0,0,0,0,0,0,39,37,115,39,0,0,0,0,95,69,78,86,0,0,0,0,105,110,118,97,108,105,100,32,108,111,110,103,32,115,116,114,105,110,103,32,100,101,108,105,109,105,116,101,114,0,0,0,46,0,0,0,0,0,0,0,69,101,0,0,0,0,0,0,88,120,0,0,0,0,0,0,80,112,0,0,0,0,0,0,43,45,0,0,0,0,0,0,109,97,108,102,111,114,109,101,100,32,110,117,109,98,101,114,0,0,0,0,0,0,0,0,108,101,120,105,99,97,108,32,101,108,101,109,101,110,116,32,116,111,111,32,108,111,110,103,0,0,0,0,0,0,0,0,117,110,102,105,110,105,115,104,101,100,32,115,116,114,105,110,103,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,101,115,99,97,112,101,32,115,101,113,117,101,110,99,101,0,100,101,99,105,109,97,108,32,101,115,99,97,112,101,32,116,111,111,32,108,97,114,103,101,0,0,0,0,0,0,0,0,104,101,120,97,100,101,99,105,109,97,108,32,100,105,103,105,116,32,101,120,112,101,99,116,101,100,0,0,0,0,0,0,117,110,102,105,110,105,115,104,101,100,32,108,111,110,103,32,115,116,114,105,110,103,0,0,117,110,102,105,110,105,115,104,101,100,32,108,111,110,103,32,99,111,109,109,101,110,116,0,99,104,117,110,107,32,104,97,115,32,116,111,111,32,109,97,110,121,32,108,105,110,101,115,0,0,0,0,0,0,0,0,37,115,58,37,100,58,32,37,115,0,0,0,0,0,0,0,37,115,32,110,101,97,114,32,37,115,0,0,0,0,0,0,97,110,100,0,0,0,0,0,98,114,101,97,107,0,0,0,100,111,0,0,0,0,0,0,101,108,115,101,0,0,0,0,101,108,115,101,105,102,0,0,101,110,100,0,0,0,0,0,102,97,108,115,101,0,0,0,102,111,114,0,0,0,0,0,102,117,110,99,116,105,111,110,0,0,0,0,0,0,0,0,103,111,116,111,0,0,0,0,105,102,0,0,0,0,0,0,105,110,0,0,0,0,0,0,108,111,99,97,108,0,0,0,110,105,108,0,0,0,0,0,110,111,116,0,0,0,0,0,111,114,0,0,0,0,0,0,114,101,112,101,97,116,0,0,114,101,116,117,114,110,0,0,116,104,101,110,0,0,0,0,116,114,117,101,0,0,0,0,117,110,116,105,108,0,0,0,119,104,105,108,101,0,0,0,46,46,0,0,0,0,0,0,46,46,46,0,0,0,0,0,61,61,0,0,0,0,0,0,62,61,0,0,0,0,0,0,60,61,0,0,0,0,0,0,126,61,0,0,0,0,0,0,58,58,0,0,0,0,0,0,60,101,111,102,62,0,0,0,60,110,117,109,98,101,114,62,0,0,0,0,0,0,0,0,60,110,97,109,101,62,0,0,60,115,116,114,105,110,103,62,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,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,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,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,105,110,102,105,110,105,116,121,0,0,0,0,0,0,0,0,110,97,110,0,0,0,0,0,95,112,137,0,255,9,47,15,10,0,0,0,100,0,0,0,232,3,0,0,16,39,0,0,160,134,1,0,64,66,15,0,128,150,152,0,0,225,245,5], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE+10240);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+  Module["_rand_r"] = _rand_r;
+
+  var ___rand_seed=allocate([0x0273459b, 0, 0, 0], "i32", ALLOC_STATIC);
+  Module["_rand"] = _rand;
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+  function _lseek(fildes, offset, whence) {
+      // off_t lseek(int fildes, off_t offset, int whence);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/lseek.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        return FS.llseek(stream, offset, whence);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fseek(stream, offset, whence) {
+      // int fseek(FILE *stream, long offset, int whence);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fseek.html
+      var fd = _fileno(stream);
+      var ret = _lseek(fd, offset, whence);
+      if (ret == -1) {
+        return -1;
+      }
+      stream = FS.getStreamFromPtr(stream);
+      stream.eof = false;
+      return 0;
+    }
+
+
+  Module["_i64Subtract"] = _i64Subtract;
+
+
+  Module["_i64Add"] = _i64Add;
+
+  function _setlocale(category, locale) {
+      if (!_setlocale.ret) _setlocale.ret = allocate([0], 'i8', ALLOC_NORMAL);
+      return _setlocale.ret;
+    }
+
+
+  function _close(fildes) {
+      // int close(int fildes);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/close.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        FS.close(stream);
+        return 0;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fsync(fildes) {
+      // int fsync(int fildes);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fsync.html
+      var stream = FS.getStream(fildes);
+      if (stream) {
+        // We write directly to the file system, so there's nothing to do here.
+        return 0;
+      } else {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+    }function _fclose(stream) {
+      // int fclose(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fclose.html
+      var fd = _fileno(stream);
+      _fsync(fd);
+      return _close(fd);
+    }
+
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _recv(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _read(fd, buf, len);
+    }
+
+  function _pread(fildes, buf, nbyte, offset) {
+      // ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.read(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _read(fildes, buf, nbyte) {
+      // ssize_t read(int fildes, void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.read(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _fread(ptr, size, nitems, stream) {
+      // size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fread.html
+      var bytesToRead = nitems * size;
+      if (bytesToRead == 0) {
+        return 0;
+      }
+      var bytesRead = 0;
+      var streamObj = FS.getStreamFromPtr(stream);
+      if (!streamObj) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return 0;
+      }
+      while (streamObj.ungotten.length && bytesToRead > 0) {
+        HEAP8[((ptr++)|0)]=streamObj.ungotten.pop();
+        bytesToRead--;
+        bytesRead++;
+      }
+      var err = _read(streamObj.fd, ptr, bytesToRead);
+      if (err == -1) {
+        if (streamObj) streamObj.error = true;
+        return 0;
+      }
+      bytesRead += err;
+      if (bytesRead < bytesToRead) streamObj.eof = true;
+      return Math.floor(bytesRead / size);
+    }
+
+  function _toupper(chr) {
+      if (chr >= 97 && chr <= 122) {
+        return chr - 97 + 65;
+      } else {
+        return chr;
+      }
+    }
+
+
+
+  function _open(path, oflag, varargs) {
+      // int open(const char *path, int oflag, ...);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
+      var mode = HEAP32[((varargs)>>2)];
+      path = Pointer_stringify(path);
+      try {
+        var stream = FS.open(path, oflag, mode);
+        return stream.fd;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _fopen(filename, mode) {
+      // FILE *fopen(const char *restrict filename, const char *restrict mode);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fopen.html
+      var flags;
+      mode = Pointer_stringify(mode);
+      if (mode[0] == 'r') {
+        if (mode.indexOf('+') != -1) {
+          flags = 2;
+        } else {
+          flags = 0;
+        }
+      } else if (mode[0] == 'w') {
+        if (mode.indexOf('+') != -1) {
+          flags = 2;
+        } else {
+          flags = 1;
+        }
+        flags |= 64;
+        flags |= 512;
+      } else if (mode[0] == 'a') {
+        if (mode.indexOf('+') != -1) {
+          flags = 2;
+        } else {
+          flags = 1;
+        }
+        flags |= 64;
+        flags |= 1024;
+      } else {
+        ___setErrNo(ERRNO_CODES.EINVAL);
+        return 0;
+      }
+      var fd = _open(filename, flags, allocate([0x1FF, 0, 0, 0], 'i32', ALLOC_STACK));  // All creation permissions.
+      return fd === -1 ? 0 : FS.getPtrForStream(FS.getStream(fd));
+    }
+
+  var _emscripten_check_longjmp=true;
+
+
+
+  function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }
+
+  var _log=Math_log;
+
+  var _emscripten_postinvoke=true;
+
+
+  function _putchar(c) {
+      // int putchar(int c);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/putchar.html
+      return _fputc(c, HEAP32[((_stdout)>>2)]);
+    }
+  Module["_saveSetjmp"] = _saveSetjmp;
+
+  function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+  function _system(command) {
+      // int system(const char *command);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/system.html
+      // Can't call external programs.
+      ___setErrNo(ERRNO_CODES.EAGAIN);
+      return -1;
+    }
+
+  function _frexp(x, exp_addr) {
+      var sig = 0, exp_ = 0;
+      if (x !== 0) {
+        var sign = 1;
+        if (x < 0) {
+          x = -x;
+          sign = -1;
+        }
+        var raw_exp = Math.log(x)/Math.log(2);
+        exp_ = Math.ceil(raw_exp);
+        if (exp_ === raw_exp) exp_ += 1;
+        sig = sign*x/Math.pow(2, exp_);
+      }
+      HEAP32[((exp_addr)>>2)]=exp_;
+      return sig;
+    }
+
+
+
+  var _tzname=allocate(8, "i32*", ALLOC_STATIC);
+
+  var _daylight=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _timezone=allocate(1, "i32*", ALLOC_STATIC);function _tzset() {
+      // TODO: Use (malleable) environment variables instead of system settings.
+      if (_tzset.called) return;
+      _tzset.called = true;
+
+      HEAP32[((_timezone)>>2)]=-(new Date()).getTimezoneOffset() * 60;
+
+      var winter = new Date(2000, 0, 1);
+      var summer = new Date(2000, 6, 1);
+      HEAP32[((_daylight)>>2)]=Number(winter.getTimezoneOffset() != summer.getTimezoneOffset());
+
+      var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1];
+      var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1];
+      var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
+      var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
+      HEAP32[((_tzname)>>2)]=winterNamePtr;
+      HEAP32[(((_tzname)+(4))>>2)]=summerNamePtr;
+    }function _mktime(tmPtr) {
+      _tzset();
+      var year = HEAP32[(((tmPtr)+(20))>>2)];
+      var timestamp = new Date(year >= 1900 ? year : year + 1900,
+                               HEAP32[(((tmPtr)+(16))>>2)],
+                               HEAP32[(((tmPtr)+(12))>>2)],
+                               HEAP32[(((tmPtr)+(8))>>2)],
+                               HEAP32[(((tmPtr)+(4))>>2)],
+                               HEAP32[((tmPtr)>>2)],
+                               0).getTime() / 1000;
+      HEAP32[(((tmPtr)+(24))>>2)]=new Date(timestamp).getDay();
+      var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24));
+      HEAP32[(((tmPtr)+(28))>>2)]=yday;
+      return timestamp;
+    }
+
+  function _isalpha(chr) {
+      return (chr >= 97 && chr <= 122) ||
+             (chr >= 65 && chr <= 90);
+    }
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;function _tmpnam(s, dir, prefix) {
+      // char *tmpnam(char *s);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpnam.html
+      // NOTE: The dir and prefix arguments are for internal use only.
+      var folder = FS.findObject(dir || '/tmp');
+      if (!folder || !folder.isFolder) {
+        dir = '/tmp';
+        folder = FS.findObject(dir);
+        if (!folder || !folder.isFolder) return 0;
+      }
+      var name = prefix || 'file';
+      do {
+        name += String.fromCharCode(65 + Math.floor(Math.random() * 25));
+      } while (name in folder.contents);
+      var result = dir + '/' + name;
+      if (!_tmpnam.buffer) _tmpnam.buffer = _malloc(256);
+      if (!s) s = _tmpnam.buffer;
+      writeAsciiToMemory(result, s);
+      return s;
+    }
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _log10(x) {
+      return Math.log(x) / Math.LN10;
+    }
+
+  function _isspace(chr) {
+      return (chr == 32) || (chr >= 9 && chr <= 13);
+    }
+
+
+  var ___tm_current=allocate(44, "i8", ALLOC_STATIC);
+
+
+  var ___tm_timezone=allocate(intArrayFromString("GMT"), "i8", ALLOC_STATIC);function _localtime_r(time, tmPtr) {
+      _tzset();
+      var date = new Date(HEAP32[((time)>>2)]*1000);
+      HEAP32[((tmPtr)>>2)]=date.getSeconds();
+      HEAP32[(((tmPtr)+(4))>>2)]=date.getMinutes();
+      HEAP32[(((tmPtr)+(8))>>2)]=date.getHours();
+      HEAP32[(((tmPtr)+(12))>>2)]=date.getDate();
+      HEAP32[(((tmPtr)+(16))>>2)]=date.getMonth();
+      HEAP32[(((tmPtr)+(20))>>2)]=date.getFullYear()-1900;
+      HEAP32[(((tmPtr)+(24))>>2)]=date.getDay();
+
+      var start = new Date(date.getFullYear(), 0, 1);
+      var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
+      HEAP32[(((tmPtr)+(28))>>2)]=yday;
+      HEAP32[(((tmPtr)+(36))>>2)]=start.getTimezoneOffset() * 60;
+
+      var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
+      HEAP32[(((tmPtr)+(32))>>2)]=dst;
+
+      HEAP32[(((tmPtr)+(40))>>2)]=___tm_timezone;
+
+      return tmPtr;
+    }function _localtime(time) {
+      return _localtime_r(time, ___tm_current);
+    }
+
+  function _srand(seed) {
+      HEAP32[((___rand_seed)>>2)]=seed
+    }
+
+  var _emscripten_prep_setjmp=true;
+
+
+
+
+  Module["_testSetjmp"] = _testSetjmp;function _longjmp(env, value) {
+      asm['setThrew'](env, value || 1);
+      throw 'longjmp';
+    }function _emscripten_longjmp(env, value) {
+      _longjmp(env, value);
+    }
+
+  var _ceil=Math_ceil;
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+  var _llvm_pow_f64=Math_pow;
+
+
+
+  Module["_strlen"] = _strlen;function _fputs(s, stream) {
+      // int fputs(const char *restrict s, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
+      var fd = _fileno(stream);
+      return _write(fd, s, _strlen(s));
+    }
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+
+  function _sinh(x) {
+      var p = Math.pow(Math.E, x);
+      return (p - (1 / p)) / 2;
+    }
+
+  function _cosh(x) {
+      var p = Math.pow(Math.E, x);
+      return (p + (1 / p)) / 2;
+    }function _tanh(x) {
+      return _sinh(x) / _cosh(x);
+    }
+
+  function _signal(sig, func) {
+      // TODO
+      return 0;
+    }
+
+
+
+  function __getFloat(text) {
+      return /^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?/.exec(text);
+    }function __scanString(format, get, unget, varargs) {
+      if (!__scanString.whiteSpace) {
+        __scanString.whiteSpace = {};
+        __scanString.whiteSpace[32] = 1;
+        __scanString.whiteSpace[9] = 1;
+        __scanString.whiteSpace[10] = 1;
+        __scanString.whiteSpace[11] = 1;
+        __scanString.whiteSpace[12] = 1;
+        __scanString.whiteSpace[13] = 1;
+      }
+      // Supports %x, %4x, %d.%d, %lld, %s, %f, %lf.
+      // TODO: Support all format specifiers.
+      format = Pointer_stringify(format);
+      var soFar = 0;
+      if (format.indexOf('%n') >= 0) {
+        // need to track soFar
+        var _get = get;
+        get = function get() {
+          soFar++;
+          return _get();
+        }
+        var _unget = unget;
+        unget = function unget() {
+          soFar--;
+          return _unget();
+        }
+      }
+      var formatIndex = 0;
+      var argsi = 0;
+      var fields = 0;
+      var argIndex = 0;
+      var next;
+
+      mainLoop:
+      for (var formatIndex = 0; formatIndex < format.length;) {
+        if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') {
+          var argPtr = HEAP32[(((varargs)+(argIndex))>>2)];
+          argIndex += Runtime.getAlignSize('void*', null, true);
+          HEAP32[((argPtr)>>2)]=soFar;
+          formatIndex += 2;
+          continue;
+        }
+
+        if (format[formatIndex] === '%') {
+          var nextC = format.indexOf('c', formatIndex+1);
+          if (nextC > 0) {
+            var maxx = 1;
+            if (nextC > formatIndex+1) {
+              var sub = format.substring(formatIndex+1, nextC);
+              maxx = parseInt(sub);
+              if (maxx != sub) maxx = 0;
+            }
+            if (maxx) {
+              var argPtr = HEAP32[(((varargs)+(argIndex))>>2)];
+              argIndex += Runtime.getAlignSize('void*', null, true);
+              fields++;
+              for (var i = 0; i < maxx; i++) {
+                next = get();
+                HEAP8[((argPtr++)|0)]=next;
+                if (next === 0) return i > 0 ? fields : fields-1; // we failed to read the full length of this field
+              }
+              formatIndex += nextC - formatIndex + 1;
+              continue;
+            }
+          }
+        }
+
+        // handle %[...]
+        if (format[formatIndex] === '%' && format.indexOf('[', formatIndex+1) > 0) {
+          var match = /\%([0-9]*)\[(\^)?(\]?[^\]]*)\]/.exec(format.substring(formatIndex));
+          if (match) {
+            var maxNumCharacters = parseInt(match[1]) || Infinity;
+            var negateScanList = (match[2] === '^');
+            var scanList = match[3];
+
+            // expand "middle" dashs into character sets
+            var middleDashMatch;
+            while ((middleDashMatch = /([^\-])\-([^\-])/.exec(scanList))) {
+              var rangeStartCharCode = middleDashMatch[1].charCodeAt(0);
+              var rangeEndCharCode = middleDashMatch[2].charCodeAt(0);
+              for (var expanded = ''; rangeStartCharCode <= rangeEndCharCode; expanded += String.fromCharCode(rangeStartCharCode++));
+              scanList = scanList.replace(middleDashMatch[1] + '-' + middleDashMatch[2], expanded);
+            }
+
+            var argPtr = HEAP32[(((varargs)+(argIndex))>>2)];
+            argIndex += Runtime.getAlignSize('void*', null, true);
+            fields++;
+
+            for (var i = 0; i < maxNumCharacters; i++) {
+              next = get();
+              if (negateScanList) {
+                if (scanList.indexOf(String.fromCharCode(next)) < 0) {
+                  HEAP8[((argPtr++)|0)]=next;
+                } else {
+                  unget();
+                  break;
+                }
+              } else {
+                if (scanList.indexOf(String.fromCharCode(next)) >= 0) {
+                  HEAP8[((argPtr++)|0)]=next;
+                } else {
+                  unget();
+                  break;
+                }
+              }
+            }
+
+            // write out null-terminating character
+            HEAP8[((argPtr++)|0)]=0;
+            formatIndex += match[0].length;
+
+            continue;
+          }
+        }
+        // remove whitespace
+        while (1) {
+          next = get();
+          if (next == 0) return fields;
+          if (!(next in __scanString.whiteSpace)) break;
+        }
+        unget();
+
+        if (format[formatIndex] === '%') {
+          formatIndex++;
+          var suppressAssignment = false;
+          if (format[formatIndex] == '*') {
+            suppressAssignment = true;
+            formatIndex++;
+          }
+          var maxSpecifierStart = formatIndex;
+          while (format[formatIndex].charCodeAt(0) >= 48 &&
+                 format[formatIndex].charCodeAt(0) <= 57) {
+            formatIndex++;
+          }
+          var max_;
+          if (formatIndex != maxSpecifierStart) {
+            max_ = parseInt(format.slice(maxSpecifierStart, formatIndex), 10);
+          }
+          var long_ = false;
+          var half = false;
+          var longLong = false;
+          if (format[formatIndex] == 'l') {
+            long_ = true;
+            formatIndex++;
+            if (format[formatIndex] == 'l') {
+              longLong = true;
+              formatIndex++;
+            }
+          } else if (format[formatIndex] == 'h') {
+            half = true;
+            formatIndex++;
+          }
+          var type = format[formatIndex];
+          formatIndex++;
+          var curr = 0;
+          var buffer = [];
+          // Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later
+          if (type == 'f' || type == 'e' || type == 'g' ||
+              type == 'F' || type == 'E' || type == 'G') {
+            next = get();
+            while (next > 0 && (!(next in __scanString.whiteSpace)))  {
+              buffer.push(String.fromCharCode(next));
+              next = get();
+            }
+            var m = __getFloat(buffer.join(''));
+            var last = m ? m[0].length : 0;
+            for (var i = 0; i < buffer.length - last + 1; i++) {
+              unget();
+            }
+            buffer.length = last;
+          } else {
+            next = get();
+            var first = true;
+
+            // Strip the optional 0x prefix for %x.
+            if ((type == 'x' || type == 'X') && (next == 48)) {
+              var peek = get();
+              if (peek == 120 || peek == 88) {
+                next = get();
+              } else {
+                unget();
+              }
+            }
+
+            while ((curr < max_ || isNaN(max_)) && next > 0) {
+              if (!(next in __scanString.whiteSpace) && // stop on whitespace
+                  (type == 's' ||
+                   ((type === 'd' || type == 'u' || type == 'i') && ((next >= 48 && next <= 57) ||
+                                                                     (first && next == 45))) ||
+                   ((type === 'x' || type === 'X') && (next >= 48 && next <= 57 ||
+                                     next >= 97 && next <= 102 ||
+                                     next >= 65 && next <= 70))) &&
+                  (formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up
+                buffer.push(String.fromCharCode(next));
+                next = get();
+                curr++;
+                first = false;
+              } else {
+                break;
+              }
+            }
+            unget();
+          }
+          if (buffer.length === 0) return 0;  // Failure.
+          if (suppressAssignment) continue;
+
+          var text = buffer.join('');
+          var argPtr = HEAP32[(((varargs)+(argIndex))>>2)];
+          argIndex += Runtime.getAlignSize('void*', null, true);
+          switch (type) {
+            case 'd': case 'u': case 'i':
+              if (half) {
+                HEAP16[((argPtr)>>1)]=parseInt(text, 10);
+              } else if (longLong) {
+                (tempI64 = [parseInt(text, 10)>>>0,(tempDouble=parseInt(text, 10),(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((argPtr)>>2)]=tempI64[0],HEAP32[(((argPtr)+(4))>>2)]=tempI64[1]);
+              } else {
+                HEAP32[((argPtr)>>2)]=parseInt(text, 10);
+              }
+              break;
+            case 'X':
+            case 'x':
+              HEAP32[((argPtr)>>2)]=parseInt(text, 16);
+              break;
+            case 'F':
+            case 'f':
+            case 'E':
+            case 'e':
+            case 'G':
+            case 'g':
+            case 'E':
+              // fallthrough intended
+              if (long_) {
+                HEAPF64[((argPtr)>>3)]=parseFloat(text);
+              } else {
+                HEAPF32[((argPtr)>>2)]=parseFloat(text);
+              }
+              break;
+            case 's':
+              var array = intArrayFromString(text);
+              for (var j = 0; j < array.length; j++) {
+                HEAP8[(((argPtr)+(j))|0)]=array[j];
+              }
+              break;
+          }
+          fields++;
+        } else if (format[formatIndex].charCodeAt(0) in __scanString.whiteSpace) {
+          next = get();
+          while (next in __scanString.whiteSpace) {
+            if (next <= 0) break mainLoop;  // End of input.
+            next = get();
+          }
+          unget(next);
+          formatIndex++;
+        } else {
+          // Not a specifier.
+          next = get();
+          if (format[formatIndex].charCodeAt(0) !== next) {
+            unget(next);
+            break mainLoop;
+          }
+          formatIndex++;
+        }
+      }
+      return fields;
+    }
+
+  function _fgetc(stream) {
+      // int fgetc(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetc.html
+      var streamObj = FS.getStreamFromPtr(stream);
+      if (!streamObj) return -1;
+      if (streamObj.eof || streamObj.error) return -1;
+      var ret = _fread(_fgetc.ret, 1, 1, stream);
+      if (ret == 0) {
+        return -1;
+      } else if (ret == -1) {
+        streamObj.error = true;
+        return -1;
+      } else {
+        return HEAPU8[((_fgetc.ret)|0)];
+      }
+    }
+
+  function _ungetc(c, stream) {
+      // int ungetc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/ungetc.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) {
+        return -1;
+      }
+      if (c === -1) {
+        // do nothing for EOF character
+        return c;
+      }
+      c = unSign(c & 0xFF);
+      stream.ungotten.push(c);
+      stream.eof = false;
+      return c;
+    }function _fscanf(stream, format, varargs) {
+      // int fscanf(FILE *restrict stream, const char *restrict format, ... );
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
+      var streamObj = FS.getStreamFromPtr(stream);
+      if (!streamObj) {
+        return -1;
+      }
+      var buffer = [];
+      function get() {
+        var c = _fgetc(stream);
+        buffer.push(c);
+        return c;
+      };
+      function unget() {
+        _ungetc(buffer.pop(), stream);
+      };
+      return __scanString(format, get, unget, varargs);
+    }
+
+  var _emscripten_preinvoke=true;
+
+  function _localeconv() {
+      // %struct.timeval = type { char* decimal point, other stuff... }
+      // var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] });
+      var me = _localeconv;
+      if (!me.ret) {
+      // These are defaults from the "C" locale
+        me.ret = allocate([
+          allocate(intArrayFromString('.'), 'i8', ALLOC_NORMAL),0,0,0, // decimal_point
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // thousands_sep
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // grouping
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // int_curr_symbol
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // currency_symbol
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_decimal_point
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_thousands_sep
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // mon_grouping
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0, // positive_sign
+          allocate(intArrayFromString(''), 'i8', ALLOC_NORMAL),0,0,0 // negative_sign
+        ], 'i8*', ALLOC_NORMAL); // Allocate strings in lconv, still don't allocate chars
+      }
+      return me.ret;
+    }
+
+
+  function _unlink(path) {
+      // int unlink(const char *path);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html
+      path = Pointer_stringify(path);
+      try {
+        FS.unlink(path);
+        return 0;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _rmdir(path) {
+      // int rmdir(const char *path);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html
+      path = Pointer_stringify(path);
+      try {
+        FS.rmdir(path);
+        return 0;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _remove(path) {
+      // int remove(const char *path);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/remove.html
+      var ret = _unlink(path);
+      if (ret == -1) ret = _rmdir(path);
+      return ret;
+    }
+
+  function _freopen(filename, mode, stream) {
+      // FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/freopen.html
+      if (!filename) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (!streamObj) {
+          ___setErrNo(ERRNO_CODES.EBADF);
+          return 0;
+        }
+        if (_freopen.buffer) _free(_freopen.buffer);
+        filename = intArrayFromString(streamObj.path);
+        filename = allocate(filename, 'i8', ALLOC_NORMAL);
+      }
+      _fclose(stream);
+      return _fopen(filename, mode);
+    }
+
+
+  function _rename(old_path, new_path) {
+      // int rename(const char *old, const char *new);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/rename.html
+      old_path = Pointer_stringify(old_path);
+      new_path = Pointer_stringify(new_path);
+      try {
+        FS.rename(old_path, new_path);
+        return 0;
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _tmpfile() {
+      // FILE *tmpfile(void);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpfile.html
+      // TODO: Delete the created file on closing.
+      if (_tmpfile.mode) {
+        _tmpfile.mode = allocate(intArrayFromString('w+'), 'i8', ALLOC_NORMAL);
+      }
+      return _fopen(_tmpnam(0), _tmpfile.mode);
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+
+  Module["_memset"] = _memset;
+
+
+
+  Module["_bitshift64Shl"] = _bitshift64Shl;
+
+  function _abort() {
+      Module['abort']();
+    }
+
+
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var origArg = currArg;
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (argSize == 8 && i64Math) {
+                  if (origArg[1]) {
+                    argText = (origArg[1]>>>0).toString(16);
+                    var lower = (origArg[0]>>>0).toString(16);
+                    while (lower.length < 8) lower = '0' + lower;
+                    argText += lower;
+                  } else {
+                    argText = (origArg[0]>>>0).toString(16);
+                  }
+                } else
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }
+
+  function _fgets(s, n, stream) {
+      // char *fgets(char *restrict s, int n, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fgets.html
+      var streamObj = FS.getStreamFromPtr(stream);
+      if (!streamObj) return 0;
+      if (streamObj.error || streamObj.eof) return 0;
+      var byte_;
+      for (var i = 0; i < n - 1 && byte_ != 10; i++) {
+        byte_ = _fgetc(stream);
+        if (byte_ == -1) {
+          if (streamObj.error || (streamObj.eof && i == 0)) return 0;
+          else if (streamObj.eof) break;
+        }
+        HEAP8[(((s)+(i))|0)]=byte_;
+      }
+      HEAP8[(((s)+(i))|0)]=0;
+      return s;
+    }
+
+  var _tan=Math_tan;
+
+  function _ispunct(chr) {
+      return (chr >= 33 && chr <= 47) ||
+             (chr >= 58 && chr <= 64) ||
+             (chr >= 91 && chr <= 96) ||
+             (chr >= 123 && chr <= 126);
+    }
+
+  function _feof(stream) {
+      // int feof(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/feof.html
+      stream = FS.getStreamFromPtr(stream);
+      return Number(stream && stream.eof);
+    }
+
+
+  Module["_tolower"] = _tolower;
+
+  var _asin=Math_asin;
+
+  function _clearerr(stream) {
+      // void clearerr(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/clearerr.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) {
+        return;
+      }
+      stream.eof = false;
+      stream.error = false;
+    }
+
+  var _fabs=Math_abs;
+
+  function _clock() {
+      if (_clock.start === undefined) _clock.start = Date.now();
+      return Math.floor((Date.now() - _clock.start) * (1000000/1000));
+    }
+
+
+  var _getc=_fgetc;
+
+  function _modf(x, intpart) {
+      HEAPF64[((intpart)>>3)]=Math.floor(x);
+      return x - HEAPF64[((intpart)>>3)];
+    }
+
+  var _sqrt=Math_sqrt;
+
+  function _isxdigit(chr) {
+      return (chr >= 48 && chr <= 57) ||
+             (chr >= 97 && chr <= 102) ||
+             (chr >= 65 && chr <= 70);
+    }
+
+  function _ftell(stream) {
+      // long ftell(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/ftell.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      if (FS.isChrdev(stream.node.mode)) {
+        ___setErrNo(ERRNO_CODES.ESPIPE);
+        return -1;
+      } else {
+        return stream.position;
+      }
+    }
+
+
+  function __exit(status) {
+      // void _exit(int status);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
+      Module['exit'](status);
+    }function _exit(status) {
+      __exit(status);
+    }
+
+
+  function _snprintf(s, n, format, varargs) {
+      // int snprintf(char *restrict s, size_t n, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var limit = (n === undefined) ? result.length
+                                    : Math.min(result.length, Math.max(n - 1, 0));
+      if (s < 0) {
+        s = -s;
+        var buf = _malloc(limit+1);
+        HEAP32[((s)>>2)]=buf;
+        s = buf;
+      }
+      for (var i = 0; i < limit; i++) {
+        HEAP8[(((s)+(i))|0)]=result[i];
+      }
+      if (limit < n || (n === undefined)) HEAP8[(((s)+(i))|0)]=0;
+      return result.length;
+    }function _sprintf(s, format, varargs) {
+      // int sprintf(char *restrict s, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      return _snprintf(s, undefined, format, varargs);
+    }
+
+  var _emscripten_get_longjmp_result=true;
+
+  var _sin=Math_sin;
+
+
+  function _fmod(x, y) {
+      return x % y;
+    }var _fmodl=_fmod;
+
+
+
+  var _atan=Math_atan;
+
+  function _ferror(stream) {
+      // int ferror(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/ferror.html
+      stream = FS.getStreamFromPtr(stream);
+      return Number(stream && stream.error);
+    }
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+  function _copysign(a, b) {
+      return __reallyNegative(a) === __reallyNegative(b) ? a : -a;
+    }
+
+
+  function _gmtime_r(time, tmPtr) {
+      var date = new Date(HEAP32[((time)>>2)]*1000);
+      HEAP32[((tmPtr)>>2)]=date.getUTCSeconds();
+      HEAP32[(((tmPtr)+(4))>>2)]=date.getUTCMinutes();
+      HEAP32[(((tmPtr)+(8))>>2)]=date.getUTCHours();
+      HEAP32[(((tmPtr)+(12))>>2)]=date.getUTCDate();
+      HEAP32[(((tmPtr)+(16))>>2)]=date.getUTCMonth();
+      HEAP32[(((tmPtr)+(20))>>2)]=date.getUTCFullYear()-1900;
+      HEAP32[(((tmPtr)+(24))>>2)]=date.getUTCDay();
+      HEAP32[(((tmPtr)+(36))>>2)]=0;
+      HEAP32[(((tmPtr)+(32))>>2)]=0;
+      var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC
+      start.setUTCDate(1);
+      start.setUTCMonth(0);
+      start.setUTCHours(0);
+      start.setUTCMinutes(0);
+      start.setUTCSeconds(0);
+      start.setUTCMilliseconds(0);
+      var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
+      HEAP32[(((tmPtr)+(28))>>2)]=yday;
+      HEAP32[(((tmPtr)+(40))>>2)]=___tm_timezone;
+
+      return tmPtr;
+    }function _gmtime(time) {
+      return _gmtime_r(time, ___tm_current);
+    }
+
+  function _isgraph(chr) {
+      return 0x20 < chr && chr < 0x7F;
+    }
+
+
+
+  function _strerror_r(errnum, strerrbuf, buflen) {
+      if (errnum in ERRNO_MESSAGES) {
+        if (ERRNO_MESSAGES[errnum].length > buflen - 1) {
+          return ___setErrNo(ERRNO_CODES.ERANGE);
+        } else {
+          var msg = ERRNO_MESSAGES[errnum];
+          writeAsciiToMemory(msg, strerrbuf);
+          return 0;
+        }
+      } else {
+        return ___setErrNo(ERRNO_CODES.EINVAL);
+      }
+    }function _strerror(errnum) {
+      if (!_strerror.buffer) _strerror.buffer = _malloc(256);
+      _strerror_r(errnum, _strerror.buffer, 256);
+      return _strerror.buffer;
+    }
+
+
+
+
+
+  var _environ=allocate(1, "i32*", ALLOC_STATIC);var ___environ=_environ;function ___buildEnvironment(env) {
+      // WARNING: Arbitrary limit!
+      var MAX_ENV_VALUES = 64;
+      var TOTAL_ENV_SIZE = 1024;
+
+      // Statically allocate memory for the environment.
+      var poolPtr;
+      var envPtr;
+      if (!___buildEnvironment.called) {
+        ___buildEnvironment.called = true;
+        // Set default values. Use string keys for Closure Compiler compatibility.
+        ENV['USER'] = 'root';
+        ENV['PATH'] = '/';
+        ENV['PWD'] = '/';
+        ENV['HOME'] = '/home/emscripten';
+        ENV['LANG'] = 'en_US.UTF-8';
+        ENV['_'] = './this.program';
+        // Allocate memory.
+        poolPtr = allocate(TOTAL_ENV_SIZE, 'i8', ALLOC_STATIC);
+        envPtr = allocate(MAX_ENV_VALUES * 4,
+                          'i8*', ALLOC_STATIC);
+        HEAP32[((envPtr)>>2)]=poolPtr;
+        HEAP32[((_environ)>>2)]=envPtr;
+      } else {
+        envPtr = HEAP32[((_environ)>>2)];
+        poolPtr = HEAP32[((envPtr)>>2)];
+      }
+
+      // Collect key=value lines.
+      var strings = [];
+      var totalSize = 0;
+      for (var key in env) {
+        if (typeof env[key] === 'string') {
+          var line = key + '=' + env[key];
+          strings.push(line);
+          totalSize += line.length;
+        }
+      }
+      if (totalSize > TOTAL_ENV_SIZE) {
+        throw new Error('Environment size exceeded TOTAL_ENV_SIZE!');
+      }
+
+      // Make new.
+      var ptrSize = 4;
+      for (var i = 0; i < strings.length; i++) {
+        var line = strings[i];
+        writeAsciiToMemory(line, poolPtr);
+        HEAP32[(((envPtr)+(i * ptrSize))>>2)]=poolPtr;
+        poolPtr += line.length + 1;
+      }
+      HEAP32[(((envPtr)+(strings.length * ptrSize))>>2)]=0;
+    }var ENV={};function _getenv(name) {
+      // char *getenv(const char *name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/getenv.html
+      if (name === 0) return 0;
+      name = Pointer_stringify(name);
+      if (!ENV.hasOwnProperty(name)) return 0;
+
+      if (_getenv.ret) _free(_getenv.ret);
+      _getenv.ret = allocate(intArrayFromString(ENV[name]), 'i8', ALLOC_NORMAL);
+      return _getenv.ret;
+    }
+
+  var _emscripten_setjmp=true;
+
+  var _cos=Math_cos;
+
+  function _isalnum(chr) {
+      return (chr >= 48 && chr <= 57) ||
+             (chr >= 97 && chr <= 122) ||
+             (chr >= 65 && chr <= 90);
+    }
+
+  var _BItoD=true;
+
+  function _difftime(time1, time0) {
+      return time1 - time0;
+    }
+
+  var _floor=Math_floor;
+
+  function _iscntrl(chr) {
+      return (0 <= chr && chr <= 0x1F) || chr === 0x7F;
+    }
+
+  var _atan2=Math_atan2;
+
+  function _setvbuf(stream, buf, type, size) {
+      // int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/setvbuf.html
+      // TODO: Implement custom buffering.
+      return 0;
+    }
+
+  var _exp=Math_exp;
+
+  var _copysignl=_copysign;
+
+  function _islower(chr) {
+      return chr >= 97 && chr <= 122;
+    }
+
+  var _acos=Math_acos;
+
+  function _isupper(chr) {
+      return chr >= 65 && chr <= 90;
+    }
+
+
+  function __isLeapYear(year) {
+        return year%4 === 0 && (year%100 !== 0 || year%400 === 0);
+    }
+
+  function __arraySum(array, index) {
+      var sum = 0;
+      for (var i = 0; i <= index; sum += array[i++]);
+      return sum;
+    }
+
+
+  var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];
+
+  var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date, days) {
+      var newDate = new Date(date.getTime());
+      while(days > 0) {
+        var leap = __isLeapYear(newDate.getFullYear());
+        var currentMonth = newDate.getMonth();
+        var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth];
+
+        if (days > daysInCurrentMonth-newDate.getDate()) {
+          // we spill over to next month
+          days -= (daysInCurrentMonth-newDate.getDate()+1);
+          newDate.setDate(1);
+          if (currentMonth < 11) {
+            newDate.setMonth(currentMonth+1)
+          } else {
+            newDate.setMonth(0);
+            newDate.setFullYear(newDate.getFullYear()+1);
+          }
+        } else {
+          // we stay in current month
+          newDate.setDate(newDate.getDate()+days);
+          return newDate;
+        }
+      }
+
+      return newDate;
+    }function _strftime(s, maxsize, format, tm) {
+      // size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html
+
+      var date = {
+        tm_sec: HEAP32[((tm)>>2)],
+        tm_min: HEAP32[(((tm)+(4))>>2)],
+        tm_hour: HEAP32[(((tm)+(8))>>2)],
+        tm_mday: HEAP32[(((tm)+(12))>>2)],
+        tm_mon: HEAP32[(((tm)+(16))>>2)],
+        tm_year: HEAP32[(((tm)+(20))>>2)],
+        tm_wday: HEAP32[(((tm)+(24))>>2)],
+        tm_yday: HEAP32[(((tm)+(28))>>2)],
+        tm_isdst: HEAP32[(((tm)+(32))>>2)]
+      };
+
+      var pattern = Pointer_stringify(format);
+
+      // expand format
+      var EXPANSION_RULES_1 = {
+        '%c': '%a %b %d %H:%M:%S %Y',     // Replaced by the locale's appropriate date and time representation - e.g., Mon Aug  3 14:02:01 2013
+        '%D': '%m/%d/%y',                 // Equivalent to %m / %d / %y
+        '%F': '%Y-%m-%d',                 // Equivalent to %Y - %m - %d
+        '%h': '%b',                       // Equivalent to %b
+        '%r': '%I:%M:%S %p',              // Replaced by the time in a.m. and p.m. notation
+        '%R': '%H:%M',                    // Replaced by the time in 24-hour notation
+        '%T': '%H:%M:%S',                 // Replaced by the time
+        '%x': '%m/%d/%y',                 // Replaced by the locale's appropriate date representation
+        '%X': '%H:%M:%S',                 // Replaced by the locale's appropriate date representation
+      };
+      for (var rule in EXPANSION_RULES_1) {
+        pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_1[rule]);
+      }
+
+      var WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
+      var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
+
+      function leadingSomething(value, digits, character) {
+        var str = typeof value === 'number' ? value.toString() : (value || '');
+        while (str.length < digits) {
+          str = character[0]+str;
+        }
+        return str;
+      };
+
+      function leadingNulls(value, digits) {
+        return leadingSomething(value, digits, '0');
+      };
+
+      function compareByDay(date1, date2) {
+        function sgn(value) {
+          return value < 0 ? -1 : (value > 0 ? 1 : 0);
+        };
+
+        var compare;
+        if ((compare = sgn(date1.getFullYear()-date2.getFullYear())) === 0) {
+          if ((compare = sgn(date1.getMonth()-date2.getMonth())) === 0) {
+            compare = sgn(date1.getDate()-date2.getDate());
+          }
+        }
+        return compare;
+      };
+
+      function getFirstWeekStartDate(janFourth) {
+          switch (janFourth.getDay()) {
+            case 0: // Sunday
+              return new Date(janFourth.getFullYear()-1, 11, 29);
+            case 1: // Monday
+              return janFourth;
+            case 2: // Tuesday
+              return new Date(janFourth.getFullYear(), 0, 3);
+            case 3: // Wednesday
+              return new Date(janFourth.getFullYear(), 0, 2);
+            case 4: // Thursday
+              return new Date(janFourth.getFullYear(), 0, 1);
+            case 5: // Friday
+              return new Date(janFourth.getFullYear()-1, 11, 31);
+            case 6: // Saturday
+              return new Date(janFourth.getFullYear()-1, 11, 30);
+          }
+      };
+
+      function getWeekBasedYear(date) {
+          var thisDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
+
+          var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4);
+          var janFourthNextYear = new Date(thisDate.getFullYear()+1, 0, 4);
+
+          var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
+          var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
+
+          if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {
+            // this date is after the start of the first week of this year
+            if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {
+              return thisDate.getFullYear()+1;
+            } else {
+              return thisDate.getFullYear();
+            }
+          } else {
+            return thisDate.getFullYear()-1;
+          }
+      };
+
+      var EXPANSION_RULES_2 = {
+        '%a': function(date) {
+          return WEEKDAYS[date.tm_wday].substring(0,3);
+        },
+        '%A': function(date) {
+          return WEEKDAYS[date.tm_wday];
+        },
+        '%b': function(date) {
+          return MONTHS[date.tm_mon].substring(0,3);
+        },
+        '%B': function(date) {
+          return MONTHS[date.tm_mon];
+        },
+        '%C': function(date) {
+          var year = date.tm_year+1900;
+          return leadingNulls(Math.floor(year/100),2);
+        },
+        '%d': function(date) {
+          return leadingNulls(date.tm_mday, 2);
+        },
+        '%e': function(date) {
+          return leadingSomething(date.tm_mday, 2, ' ');
+        },
+        '%g': function(date) {
+          // %g, %G, and %V give values according to the ISO 8601:2000 standard week-based year.
+          // In this system, weeks begin on a Monday and week 1 of the year is the week that includes
+          // January 4th, which is also the week that includes the first Thursday of the year, and
+          // is also the first week that contains at least four days in the year.
+          // If the first Monday of January is the 2nd, 3rd, or 4th, the preceding days are part of
+          // the last week of the preceding year; thus, for Saturday 2nd January 1999,
+          // %G is replaced by 1998 and %V is replaced by 53. If December 29th, 30th,
+          // or 31st is a Monday, it and any following days are part of week 1 of the following year.
+          // Thus, for Tuesday 30th December 1997, %G is replaced by 1998 and %V is replaced by 01.
+
+          return getWeekBasedYear(date).toString().substring(2);
+        },
+        '%G': function(date) {
+          return getWeekBasedYear(date);
+        },
+        '%H': function(date) {
+          return leadingNulls(date.tm_hour, 2);
+        },
+        '%I': function(date) {
+          return leadingNulls(date.tm_hour < 13 ? date.tm_hour : date.tm_hour-12, 2);
+        },
+        '%j': function(date) {
+          // Day of the year (001-366)
+          return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date.tm_mon-1), 3);
+        },
+        '%m': function(date) {
+          return leadingNulls(date.tm_mon+1, 2);
+        },
+        '%M': function(date) {
+          return leadingNulls(date.tm_min, 2);
+        },
+        '%n': function() {
+          return '\n';
+        },
+        '%p': function(date) {
+          if (date.tm_hour > 0 && date.tm_hour < 13) {
+            return 'AM';
+          } else {
+            return 'PM';
+          }
+        },
+        '%S': function(date) {
+          return leadingNulls(date.tm_sec, 2);
+        },
+        '%t': function() {
+          return '\t';
+        },
+        '%u': function(date) {
+          var day = new Date(date.tm_year+1900, date.tm_mon+1, date.tm_mday, 0, 0, 0, 0);
+          return day.getDay() || 7;
+        },
+        '%U': function(date) {
+          // Replaced by the week number of the year as a decimal number [00,53].
+          // The first Sunday of January is the first day of week 1;
+          // days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+          var janFirst = new Date(date.tm_year+1900, 0, 1);
+          var firstSunday = janFirst.getDay() === 0 ? janFirst : __addDays(janFirst, 7-janFirst.getDay());
+          var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
+
+          // is target date after the first Sunday?
+          if (compareByDay(firstSunday, endDate) < 0) {
+            // calculate difference in days between first Sunday and endDate
+            var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
+            var firstSundayUntilEndJanuary = 31-firstSunday.getDate();
+            var days = firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
+            return leadingNulls(Math.ceil(days/7), 2);
+          }
+
+          return compareByDay(firstSunday, janFirst) === 0 ? '01': '00';
+        },
+        '%V': function(date) {
+          // Replaced by the week number of the year (Monday as the first day of the week)
+          // as a decimal number [01,53]. If the week containing 1 January has four
+          // or more days in the new year, then it is considered week 1.
+          // Otherwise, it is the last week of the previous year, and the next week is week 1.
+          // Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
+          var janFourthThisYear = new Date(date.tm_year+1900, 0, 4);
+          var janFourthNextYear = new Date(date.tm_year+1901, 0, 4);
+
+          var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
+          var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
+
+          var endDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
+
+          if (compareByDay(endDate, firstWeekStartThisYear) < 0) {
+            // if given date is before this years first week, then it belongs to the 53rd week of last year
+            return '53';
+          }
+
+          if (compareByDay(firstWeekStartNextYear, endDate) <= 0) {
+            // if given date is after next years first week, then it belongs to the 01th week of next year
+            return '01';
+          }
+
+          // given date is in between CW 01..53 of this calendar year
+          var daysDifference;
+          if (firstWeekStartThisYear.getFullYear() < date.tm_year+1900) {
+            // first CW of this year starts last year
+            daysDifference = date.tm_yday+32-firstWeekStartThisYear.getDate()
+          } else {
+            // first CW of this year starts this year
+            daysDifference = date.tm_yday+1-firstWeekStartThisYear.getDate();
+          }
+          return leadingNulls(Math.ceil(daysDifference/7), 2);
+        },
+        '%w': function(date) {
+          var day = new Date(date.tm_year+1900, date.tm_mon+1, date.tm_mday, 0, 0, 0, 0);
+          return day.getDay();
+        },
+        '%W': function(date) {
+          // Replaced by the week number of the year as a decimal number [00,53].
+          // The first Monday of January is the first day of week 1;
+          // days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+          var janFirst = new Date(date.tm_year, 0, 1);
+          var firstMonday = janFirst.getDay() === 1 ? janFirst : __addDays(janFirst, janFirst.getDay() === 0 ? 1 : 7-janFirst.getDay()+1);
+          var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
+
+          // is target date after the first Monday?
+          if (compareByDay(firstMonday, endDate) < 0) {
+            var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
+            var firstMondayUntilEndJanuary = 31-firstMonday.getDate();
+            var days = firstMondayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
+            return leadingNulls(Math.ceil(days/7), 2);
+          }
+          return compareByDay(firstMonday, janFirst) === 0 ? '01': '00';
+        },
+        '%y': function(date) {
+          // Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
+          return (date.tm_year+1900).toString().substring(2);
+        },
+        '%Y': function(date) {
+          // Replaced by the year as a decimal number (for example, 1997). [ tm_year]
+          return date.tm_year+1900;
+        },
+        '%z': function(date) {
+          // Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ),
+          // or by no characters if no timezone is determinable.
+          // For example, "-0430" means 4 hours 30 minutes behind UTC (west of Greenwich).
+          // If tm_isdst is zero, the standard time offset is used.
+          // If tm_isdst is greater than zero, the daylight savings time offset is used.
+          // If tm_isdst is negative, no characters are returned.
+          // FIXME: we cannot determine time zone (or can we?)
+          return '';
+        },
+        '%Z': function(date) {
+          // Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [ tm_isdst]
+          // FIXME: we cannot determine time zone (or can we?)
+          return '';
+        },
+        '%%': function() {
+          return '%';
+        }
+      };
+      for (var rule in EXPANSION_RULES_2) {
+        if (pattern.indexOf(rule) >= 0) {
+          pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_2[rule](date));
+        }
+      }
+
+      var bytes = intArrayFromString(pattern, false);
+      if (bytes.length > maxsize) {
+        return 0;
+      }
+
+      writeArrayToMemory(bytes, s);
+      return bytes.length-1;
+    }
+
+
+
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+_fgetc.ret = allocate([0], "i8", ALLOC_STATIC);
+___buildEnvironment(ENV);
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+ var ctlz_i8 = allocate([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], "i8", ALLOC_DYNAMIC);
+ var cttz_i8 = allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0], "i8", ALLOC_DYNAMIC);
+
+var Math_min = Math.min;
+function invoke_iiii(index,a1,a2,a3) {
+  try {
+    return Module["dynCall_iiii"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vi(index,a1) {
+  try {
+    Module["dynCall_vi"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vii(index,a1,a2) {
+  try {
+    Module["dynCall_vii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_ii(index,a1) {
+  try {
+    return Module["dynCall_ii"](index,a1);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iiiii(index,a1,a2,a3,a4) {
+  try {
+    return Module["dynCall_iiiii"](index,a1,a2,a3,a4);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iii(index,a1,a2) {
+  try {
+    return Module["dynCall_iii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+  var cttz_i8=env.cttz_i8|0;
+  var ctlz_i8=env.ctlz_i8|0;
+  var ___rand_seed=env.___rand_seed|0;
+  var _stderr=env._stderr|0;
+  var _stdin=env._stdin|0;
+  var _stdout=env._stdout|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var invoke_iiii=env.invoke_iiii;
+  var invoke_vi=env.invoke_vi;
+  var invoke_vii=env.invoke_vii;
+  var invoke_ii=env.invoke_ii;
+  var invoke_iiiii=env.invoke_iiiii;
+  var invoke_iii=env.invoke_iii;
+  var _isalnum=env._isalnum;
+  var _fabs=env._fabs;
+  var _frexp=env._frexp;
+  var _exp=env._exp;
+  var _fread=env._fread;
+  var __reallyNegative=env.__reallyNegative;
+  var _longjmp=env._longjmp;
+  var __addDays=env.__addDays;
+  var _fsync=env._fsync;
+  var _signal=env._signal;
+  var _rename=env._rename;
+  var _sbrk=env._sbrk;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _sinh=env._sinh;
+  var _sysconf=env._sysconf;
+  var _close=env._close;
+  var _ferror=env._ferror;
+  var _clock=env._clock;
+  var _cos=env._cos;
+  var _tanh=env._tanh;
+  var _unlink=env._unlink;
+  var _write=env._write;
+  var __isLeapYear=env.__isLeapYear;
+  var _ftell=env._ftell;
+  var _isupper=env._isupper;
+  var _gmtime_r=env._gmtime_r;
+  var _islower=env._islower;
+  var _tmpnam=env._tmpnam;
+  var _tmpfile=env._tmpfile;
+  var _send=env._send;
+  var _abort=env._abort;
+  var _setvbuf=env._setvbuf;
+  var _atan2=env._atan2;
+  var _setlocale=env._setlocale;
+  var _isgraph=env._isgraph;
+  var _modf=env._modf;
+  var _strerror_r=env._strerror_r;
+  var _fscanf=env._fscanf;
+  var ___setErrNo=env.___setErrNo;
+  var _isalpha=env._isalpha;
+  var _srand=env._srand;
+  var _mktime=env._mktime;
+  var _putchar=env._putchar;
+  var _gmtime=env._gmtime;
+  var _localeconv=env._localeconv;
+  var _sprintf=env._sprintf;
+  var _localtime=env._localtime;
+  var _read=env._read;
+  var _fwrite=env._fwrite;
+  var _time=env._time;
+  var _fprintf=env._fprintf;
+  var _exit=env._exit;
+  var _freopen=env._freopen;
+  var _llvm_pow_f64=env._llvm_pow_f64;
+  var _fgetc=env._fgetc;
+  var _fmod=env._fmod;
+  var _lseek=env._lseek;
+  var _rmdir=env._rmdir;
+  var _asin=env._asin;
+  var _floor=env._floor;
+  var _pwrite=env._pwrite;
+  var _localtime_r=env._localtime_r;
+  var _tzset=env._tzset;
+  var _open=env._open;
+  var _remove=env._remove;
+  var _snprintf=env._snprintf;
+  var __scanString=env.__scanString;
+  var _strftime=env._strftime;
+  var _fseek=env._fseek;
+  var _iscntrl=env._iscntrl;
+  var _isxdigit=env._isxdigit;
+  var _fclose=env._fclose;
+  var _log=env._log;
+  var _recv=env._recv;
+  var _tan=env._tan;
+  var _copysign=env._copysign;
+  var __getFloat=env.__getFloat;
+  var _fputc=env._fputc;
+  var _ispunct=env._ispunct;
+  var _ceil=env._ceil;
+  var _isspace=env._isspace;
+  var _fopen=env._fopen;
+  var _sin=env._sin;
+  var _acos=env._acos;
+  var _cosh=env._cosh;
+  var ___buildEnvironment=env.___buildEnvironment;
+  var _difftime=env._difftime;
+  var _ungetc=env._ungetc;
+  var _system=env._system;
+  var _fflush=env._fflush;
+  var _log10=env._log10;
+  var _fileno=env._fileno;
+  var __exit=env.__exit;
+  var __arraySum=env.__arraySum;
+  var _fgets=env._fgets;
+  var _atan=env._atan;
+  var _pread=env._pread;
+  var _mkport=env._mkport;
+  var _toupper=env._toupper;
+  var _feof=env._feof;
+  var ___errno_location=env.___errno_location;
+  var _clearerr=env._clearerr;
+  var _getenv=env._getenv;
+  var _strerror=env._strerror;
+  var _emscripten_longjmp=env._emscripten_longjmp;
+  var __formatString=env.__formatString;
+  var _fputs=env._fputs;
+  var _sqrt=env._sqrt;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[3228] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 12952 + (i5 << 2) | 0;
+    i5 = 12952 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[3228] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[12920 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 12952 + (i7 << 2) | 0;
+     i7 = 12952 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[3228] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[12920 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[12932 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 12952 + (i9 << 2) | 0;
+      i7 = HEAP32[3228] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 12952 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[3228] = i7 | i8;
+       i28 = 12952 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[12920 >> 2] = i4;
+     HEAP32[12932 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[12916 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[13216 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[12928 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 13216 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[12920 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[12932 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 12952 + (i9 << 2) | 0;
+       i7 = HEAP32[3228] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 12952 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[3228] = i7 | i8;
+        i25 = 12952 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[12920 >> 2] = i2;
+      HEAP32[12932 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[12916 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[13216 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[13216 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[12920 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[12928 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 13216 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 12952 + (i6 << 2) | 0;
+         i5 = HEAP32[3228] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 12952 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[3228] = i5 | i4;
+          i21 = 12952 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 13216 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[12916 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[12916 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[12928 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[12920 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[12932 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[12932 >> 2] = i2 + i12;
+   HEAP32[12920 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[12920 >> 2] = 0;
+   HEAP32[12932 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[12924 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[12924 >> 2] = i31;
+  i32 = HEAP32[12936 >> 2] | 0;
+  HEAP32[12936 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[3346] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[13392 >> 2] = i18;
+    HEAP32[13388 >> 2] = i18;
+    HEAP32[13396 >> 2] = -1;
+    HEAP32[13400 >> 2] = -1;
+    HEAP32[13404 >> 2] = 0;
+    HEAP32[13356 >> 2] = 0;
+    HEAP32[3346] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[13392 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[13352 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[13344 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[13356 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[12936 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 13360 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[12924 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[13388 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[13344 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[13352 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[13392 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[13356 >> 2] = HEAP32[13356 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[13344 >> 2] | 0) + i14 | 0;
+  HEAP32[13344 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[13348 >> 2] | 0) >>> 0) {
+   HEAP32[13348 >> 2] = i15;
+  }
+  i15 = HEAP32[12936 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 13360 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[12924 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[12936 >> 2] = i15 + i3;
+     HEAP32[12924 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[12940 >> 2] = HEAP32[13400 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+     HEAP32[12928 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 13360 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[12936 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[12932 >> 2] | 0)) {
+        i32 = (HEAP32[12920 >> 2] | 0) + i10 | 0;
+        HEAP32[12920 >> 2] = i32;
+        HEAP32[12932 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 13216 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 12952 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[3228] = HEAP32[3228] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 12952 + (i10 << 2) | 0;
+        i9 = HEAP32[3228] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 12952 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[3228] = i9 | i5;
+         i3 = 12952 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 13216 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[12916 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[12916 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L445 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L445;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[12928 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[12924 >> 2] | 0) + i10 | 0;
+       HEAP32[12924 >> 2] = i32;
+       HEAP32[12936 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 13360 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[12936 >> 2] = i17 + i4;
+    HEAP32[12924 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[12940 >> 2] = HEAP32[13400 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[13360 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[13364 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[13368 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[13372 >> 2];
+    HEAP32[13360 >> 2] = i17;
+    HEAP32[13364 >> 2] = i14;
+    HEAP32[13372 >> 2] = 0;
+    HEAP32[13368 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 12952 + (i4 << 2) | 0;
+      i5 = HEAP32[3228] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 12952 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[3228] = i5 | i3;
+       i7 = 12952 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 13216 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[12916 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[12916 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[12928 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[12928 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[12928 >> 2] = i17;
+    }
+    HEAP32[13360 >> 2] = i17;
+    HEAP32[13364 >> 2] = i14;
+    HEAP32[13372 >> 2] = 0;
+    HEAP32[12948 >> 2] = HEAP32[3346];
+    HEAP32[12944 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 12952 + (i32 << 2) | 0;
+     HEAP32[12952 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[12952 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[12936 >> 2] = i17 + i2;
+    HEAP32[12924 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[12940 >> 2] = HEAP32[13400 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[12924 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[12924 >> 2] = i31;
+   i32 = HEAP32[12936 >> 2] | 0;
+   HEAP32[12936 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _llex(i2, i3) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i12 = i1;
+ i4 = i2 + 60 | 0;
+ HEAP32[(HEAP32[i4 >> 2] | 0) + 4 >> 2] = 0;
+ i5 = i2 + 56 | 0;
+ L1 : while (1) {
+  i13 = HEAP32[i2 >> 2] | 0;
+  L3 : while (1) {
+   switch (i13 | 0) {
+   case 11:
+   case 9:
+   case 12:
+   case 32:
+    {
+     break;
+    }
+   case 91:
+    {
+     i9 = 25;
+     break L1;
+    }
+   case 62:
+    {
+     i9 = 45;
+     break L1;
+    }
+   case 46:
+    {
+     i9 = 161;
+     break L1;
+    }
+   case 13:
+   case 10:
+    {
+     i9 = 4;
+     break L3;
+    }
+   case 45:
+    {
+     break L3;
+    }
+   case 61:
+    {
+     i9 = 29;
+     break L1;
+    }
+   case 39:
+   case 34:
+    {
+     i9 = 69;
+     break L1;
+    }
+   case 126:
+    {
+     i9 = 53;
+     break L1;
+    }
+   case 60:
+    {
+     i9 = 37;
+     break L1;
+    }
+   case 58:
+    {
+     i9 = 61;
+     break L1;
+    }
+   case 57:
+   case 56:
+   case 55:
+   case 54:
+   case 53:
+   case 52:
+   case 51:
+   case 50:
+   case 49:
+   case 48:
+    {
+     i20 = i13;
+     break L1;
+    }
+   case -1:
+    {
+     i2 = 286;
+     i9 = 306;
+     break L1;
+    }
+   default:
+    {
+     i9 = 283;
+     break L1;
+    }
+   }
+   i13 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i13 >> 2] | 0;
+   HEAP32[i13 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i13 = _luaZ_fill(i13) | 0;
+   } else {
+    i27 = i13 + 4 | 0;
+    i13 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i13 + 1;
+    i13 = HEAPU8[i13] | 0;
+   }
+   HEAP32[i2 >> 2] = i13;
+  }
+  if ((i9 | 0) == 4) {
+   i9 = 0;
+   _inclinenumber(i2);
+   continue;
+  }
+  i13 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i13 = _luaZ_fill(i13) | 0;
+  } else {
+   i27 = i13 + 4 | 0;
+   i13 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i13 + 1;
+   i13 = HEAPU8[i13] | 0;
+  }
+  HEAP32[i2 >> 2] = i13;
+  if ((i13 | 0) != 45) {
+   i2 = 45;
+   i9 = 306;
+   break;
+  }
+  i13 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i13 = _luaZ_fill(i13) | 0;
+  } else {
+   i27 = i13 + 4 | 0;
+   i13 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i13 + 1;
+   i13 = HEAPU8[i13] | 0;
+  }
+  HEAP32[i2 >> 2] = i13;
+  do {
+   if ((i13 | 0) == 91) {
+    i13 = _skip_sep(i2) | 0;
+    HEAP32[(HEAP32[i4 >> 2] | 0) + 4 >> 2] = 0;
+    if ((i13 | 0) > -1) {
+     _read_long_string(i2, 0, i13);
+     HEAP32[(HEAP32[i4 >> 2] | 0) + 4 >> 2] = 0;
+     continue L1;
+    } else {
+     i13 = HEAP32[i2 >> 2] | 0;
+     break;
+    }
+   }
+  } while (0);
+  while (1) {
+   if ((i13 | 0) == -1 | (i13 | 0) == 13 | (i13 | 0) == 10) {
+    continue L1;
+   }
+   i13 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i13 >> 2] | 0;
+   HEAP32[i13 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i13 = _luaZ_fill(i13) | 0;
+   } else {
+    i27 = i13 + 4 | 0;
+    i13 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i13 + 1;
+    i13 = HEAPU8[i13] | 0;
+   }
+   HEAP32[i2 >> 2] = i13;
+  }
+ }
+ if ((i9 | 0) == 25) {
+  i9 = _skip_sep(i2) | 0;
+  if ((i9 | 0) > -1) {
+   _read_long_string(i2, i3, i9);
+   i27 = 289;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  if ((i9 | 0) == -1) {
+   i27 = 91;
+   STACKTOP = i1;
+   return i27 | 0;
+  } else {
+   _lexerror(i2, 12272, 289);
+  }
+ } else if ((i9 | 0) == 29) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 61) {
+   i27 = 61;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 281;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 37) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 61) {
+   i27 = 60;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 283;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 45) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 61) {
+   i27 = 62;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 282;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 53) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 61) {
+   i27 = 126;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 284;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 61) {
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  if ((i3 | 0) != 58) {
+   i27 = 58;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i3 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i27 = i3 + 4 | 0;
+   i3 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i27 = 285;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 69) {
+  i14 = HEAP32[i4 >> 2] | 0;
+  i7 = i14 + 4 | 0;
+  i15 = HEAP32[i7 >> 2] | 0;
+  i8 = i14 + 8 | 0;
+  i6 = HEAP32[i8 >> 2] | 0;
+  do {
+   if ((i15 + 1 | 0) >>> 0 > i6 >>> 0) {
+    if (i6 >>> 0 > 2147483645) {
+     _lexerror(i2, 12368, 0);
+    }
+    i16 = i6 << 1;
+    i15 = HEAP32[i2 + 52 >> 2] | 0;
+    if ((i16 | 0) == -2) {
+     _luaM_toobig(i15);
+    } else {
+     i24 = _luaM_realloc_(i15, HEAP32[i14 >> 2] | 0, i6, i16) | 0;
+     HEAP32[i14 >> 2] = i24;
+     HEAP32[i8 >> 2] = i16;
+     i23 = HEAP32[i7 >> 2] | 0;
+     break;
+    }
+   } else {
+    i23 = i15;
+    i24 = HEAP32[i14 >> 2] | 0;
+   }
+  } while (0);
+  i6 = i13 & 255;
+  HEAP32[i7 >> 2] = i23 + 1;
+  HEAP8[i24 + i23 | 0] = i6;
+  i7 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i14 = _luaZ_fill(i7) | 0;
+  } else {
+   i27 = i7 + 4 | 0;
+   i14 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i14 + 1;
+   i14 = HEAPU8[i14] | 0;
+  }
+  HEAP32[i2 >> 2] = i14;
+  L139 : do {
+   if ((i14 | 0) != (i13 | 0)) {
+    i7 = i2 + 52 | 0;
+    L141 : while (1) {
+     L143 : do {
+      if ((i14 | 0) == 92) {
+       i8 = HEAP32[i5 >> 2] | 0;
+       i27 = HEAP32[i8 >> 2] | 0;
+       HEAP32[i8 >> 2] = i27 + -1;
+       if ((i27 | 0) == 0) {
+        i8 = _luaZ_fill(i8) | 0;
+       } else {
+        i27 = i8 + 4 | 0;
+        i8 = HEAP32[i27 >> 2] | 0;
+        HEAP32[i27 >> 2] = i8 + 1;
+        i8 = HEAPU8[i8] | 0;
+       }
+       HEAP32[i2 >> 2] = i8;
+       switch (i8 | 0) {
+       case 13:
+       case 10:
+        {
+         _inclinenumber(i2);
+         i8 = 10;
+         break;
+        }
+       case 39:
+       case 34:
+       case 92:
+        {
+         i9 = 124;
+         break;
+        }
+       case 122:
+        {
+         i8 = HEAP32[i5 >> 2] | 0;
+         i27 = HEAP32[i8 >> 2] | 0;
+         HEAP32[i8 >> 2] = i27 + -1;
+         if ((i27 | 0) == 0) {
+          i14 = _luaZ_fill(i8) | 0;
+         } else {
+          i27 = i8 + 4 | 0;
+          i14 = HEAP32[i27 >> 2] | 0;
+          HEAP32[i27 >> 2] = i14 + 1;
+          i14 = HEAPU8[i14] | 0;
+         }
+         HEAP32[i2 >> 2] = i14;
+         if ((HEAP8[i14 + 10913 | 0] & 8) == 0) {
+          break L143;
+         }
+         while (1) {
+          if ((i14 | 0) == 13 | (i14 | 0) == 10) {
+           _inclinenumber(i2);
+           i14 = HEAP32[i2 >> 2] | 0;
+          } else {
+           i8 = HEAP32[i5 >> 2] | 0;
+           i27 = HEAP32[i8 >> 2] | 0;
+           HEAP32[i8 >> 2] = i27 + -1;
+           if ((i27 | 0) == 0) {
+            i14 = _luaZ_fill(i8) | 0;
+           } else {
+            i27 = i8 + 4 | 0;
+            i14 = HEAP32[i27 >> 2] | 0;
+            HEAP32[i27 >> 2] = i14 + 1;
+            i14 = HEAPU8[i14] | 0;
+           }
+           HEAP32[i2 >> 2] = i14;
+          }
+          if ((HEAP8[i14 + 10913 | 0] & 8) == 0) {
+           break L143;
+          }
+         }
+        }
+       case 118:
+        {
+         i8 = 11;
+         i9 = 124;
+         break;
+        }
+       case 120:
+        {
+         HEAP32[i12 >> 2] = 120;
+         i14 = 1;
+         i8 = 0;
+         while (1) {
+          i9 = HEAP32[i5 >> 2] | 0;
+          i27 = HEAP32[i9 >> 2] | 0;
+          HEAP32[i9 >> 2] = i27 + -1;
+          if ((i27 | 0) == 0) {
+           i9 = _luaZ_fill(i9) | 0;
+          } else {
+           i27 = i9 + 4 | 0;
+           i9 = HEAP32[i27 >> 2] | 0;
+           HEAP32[i27 >> 2] = i9 + 1;
+           i9 = HEAPU8[i9] | 0;
+          }
+          HEAP32[i2 >> 2] = i9;
+          HEAP32[i12 + (i14 << 2) >> 2] = i9;
+          if ((HEAP8[i9 + 10913 | 0] & 16) == 0) {
+           i9 = 100;
+           break L141;
+          }
+          i8 = (_luaO_hexavalue(i9) | 0) + (i8 << 4) | 0;
+          i14 = i14 + 1 | 0;
+          if ((i14 | 0) >= 3) {
+           i9 = 124;
+           break;
+          }
+         }
+         break;
+        }
+       case -1:
+        {
+         i14 = -1;
+         break L143;
+        }
+       case 98:
+        {
+         i8 = 8;
+         i9 = 124;
+         break;
+        }
+       case 102:
+        {
+         i8 = 12;
+         i9 = 124;
+         break;
+        }
+       case 110:
+        {
+         i8 = 10;
+         i9 = 124;
+         break;
+        }
+       case 114:
+        {
+         i8 = 13;
+         i9 = 124;
+         break;
+        }
+       case 116:
+        {
+         i8 = 9;
+         i9 = 124;
+         break;
+        }
+       case 97:
+        {
+         i8 = 7;
+         i9 = 124;
+         break;
+        }
+       default:
+        {
+         if ((HEAP8[i8 + 10913 | 0] & 2) == 0) {
+          i9 = 116;
+          break L141;
+         } else {
+          i15 = i8;
+          i14 = 0;
+          i8 = 0;
+         }
+         do {
+          if ((HEAP8[i15 + 10913 | 0] & 2) == 0) {
+           break;
+          }
+          HEAP32[i12 + (i14 << 2) >> 2] = i15;
+          i8 = i15 + -48 + (i8 * 10 | 0) | 0;
+          i15 = HEAP32[i5 >> 2] | 0;
+          i27 = HEAP32[i15 >> 2] | 0;
+          HEAP32[i15 >> 2] = i27 + -1;
+          if ((i27 | 0) == 0) {
+           i15 = _luaZ_fill(i15) | 0;
+          } else {
+           i27 = i15 + 4 | 0;
+           i15 = HEAP32[i27 >> 2] | 0;
+           HEAP32[i27 >> 2] = i15 + 1;
+           i15 = HEAPU8[i15] | 0;
+          }
+          HEAP32[i2 >> 2] = i15;
+          i14 = i14 + 1 | 0;
+         } while ((i14 | 0) < 3);
+         if ((i8 | 0) > 255) {
+          i9 = 123;
+          break L141;
+         }
+        }
+       }
+       if ((i9 | 0) == 124) {
+        i9 = 0;
+        i14 = HEAP32[i5 >> 2] | 0;
+        i27 = HEAP32[i14 >> 2] | 0;
+        HEAP32[i14 >> 2] = i27 + -1;
+        if ((i27 | 0) == 0) {
+         i14 = _luaZ_fill(i14) | 0;
+        } else {
+         i27 = i14 + 4 | 0;
+         i14 = HEAP32[i27 >> 2] | 0;
+         HEAP32[i27 >> 2] = i14 + 1;
+         i14 = HEAPU8[i14] | 0;
+        }
+        HEAP32[i2 >> 2] = i14;
+       }
+       i15 = HEAP32[i4 >> 2] | 0;
+       i14 = i15 + 4 | 0;
+       i18 = HEAP32[i14 >> 2] | 0;
+       i16 = i15 + 8 | 0;
+       i17 = HEAP32[i16 >> 2] | 0;
+       if ((i18 + 1 | 0) >>> 0 > i17 >>> 0) {
+        if (i17 >>> 0 > 2147483645) {
+         i9 = 131;
+         break L141;
+        }
+        i18 = i17 << 1;
+        i19 = HEAP32[i7 >> 2] | 0;
+        if ((i18 | 0) == -2) {
+         i9 = 133;
+         break L141;
+        }
+        i27 = _luaM_realloc_(i19, HEAP32[i15 >> 2] | 0, i17, i18) | 0;
+        HEAP32[i15 >> 2] = i27;
+        HEAP32[i16 >> 2] = i18;
+        i18 = HEAP32[i14 >> 2] | 0;
+        i15 = i27;
+       } else {
+        i15 = HEAP32[i15 >> 2] | 0;
+       }
+       HEAP32[i14 >> 2] = i18 + 1;
+       HEAP8[i15 + i18 | 0] = i8;
+       i14 = HEAP32[i2 >> 2] | 0;
+      } else if ((i14 | 0) == -1) {
+       i9 = 82;
+       break L141;
+      } else if ((i14 | 0) == 13 | (i14 | 0) == 10) {
+       i9 = 83;
+       break L141;
+      } else {
+       i15 = HEAP32[i4 >> 2] | 0;
+       i8 = i15 + 4 | 0;
+       i18 = HEAP32[i8 >> 2] | 0;
+       i17 = i15 + 8 | 0;
+       i16 = HEAP32[i17 >> 2] | 0;
+       if ((i18 + 1 | 0) >>> 0 > i16 >>> 0) {
+        if (i16 >>> 0 > 2147483645) {
+         i9 = 139;
+         break L141;
+        }
+        i19 = i16 << 1;
+        i18 = HEAP32[i7 >> 2] | 0;
+        if ((i19 | 0) == -2) {
+         i9 = 141;
+         break L141;
+        }
+        i27 = _luaM_realloc_(i18, HEAP32[i15 >> 2] | 0, i16, i19) | 0;
+        HEAP32[i15 >> 2] = i27;
+        HEAP32[i17 >> 2] = i19;
+        i18 = HEAP32[i8 >> 2] | 0;
+        i15 = i27;
+       } else {
+        i15 = HEAP32[i15 >> 2] | 0;
+       }
+       HEAP32[i8 >> 2] = i18 + 1;
+       HEAP8[i15 + i18 | 0] = i14;
+       i8 = HEAP32[i5 >> 2] | 0;
+       i27 = HEAP32[i8 >> 2] | 0;
+       HEAP32[i8 >> 2] = i27 + -1;
+       if ((i27 | 0) == 0) {
+        i14 = _luaZ_fill(i8) | 0;
+       } else {
+        i27 = i8 + 4 | 0;
+        i14 = HEAP32[i27 >> 2] | 0;
+        HEAP32[i27 >> 2] = i14 + 1;
+        i14 = HEAPU8[i14] | 0;
+       }
+       HEAP32[i2 >> 2] = i14;
+      }
+     } while (0);
+     if ((i14 | 0) == (i13 | 0)) {
+      break L139;
+     }
+    }
+    if ((i9 | 0) == 82) {
+     _lexerror(i2, 12400, 286);
+    } else if ((i9 | 0) == 83) {
+     _lexerror(i2, 12400, 289);
+    } else if ((i9 | 0) == 100) {
+     _escerror(i2, i12, i14 + 1 | 0, 12480);
+    } else if ((i9 | 0) == 116) {
+     _escerror(i2, i2, 1, 12424);
+    } else if ((i9 | 0) == 123) {
+     _escerror(i2, i12, i14, 12448);
+    } else if ((i9 | 0) == 131) {
+     _lexerror(i2, 12368, 0);
+    } else if ((i9 | 0) == 133) {
+     _luaM_toobig(i19);
+    } else if ((i9 | 0) == 139) {
+     _lexerror(i2, 12368, 0);
+    } else if ((i9 | 0) == 141) {
+     _luaM_toobig(i18);
+    }
+   }
+  } while (0);
+  i7 = HEAP32[i4 >> 2] | 0;
+  i8 = i7 + 4 | 0;
+  i13 = HEAP32[i8 >> 2] | 0;
+  i12 = i7 + 8 | 0;
+  i9 = HEAP32[i12 >> 2] | 0;
+  do {
+   if ((i13 + 1 | 0) >>> 0 > i9 >>> 0) {
+    if (i9 >>> 0 > 2147483645) {
+     _lexerror(i2, 12368, 0);
+    }
+    i14 = i9 << 1;
+    i13 = HEAP32[i2 + 52 >> 2] | 0;
+    if ((i14 | 0) == -2) {
+     _luaM_toobig(i13);
+    } else {
+     i11 = _luaM_realloc_(i13, HEAP32[i7 >> 2] | 0, i9, i14) | 0;
+     HEAP32[i7 >> 2] = i11;
+     HEAP32[i12 >> 2] = i14;
+     i10 = HEAP32[i8 >> 2] | 0;
+     break;
+    }
+   } else {
+    i10 = i13;
+    i11 = HEAP32[i7 >> 2] | 0;
+   }
+  } while (0);
+  HEAP32[i8 >> 2] = i10 + 1;
+  HEAP8[i11 + i10 | 0] = i6;
+  i5 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i5 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i5 = _luaZ_fill(i5) | 0;
+  } else {
+   i27 = i5 + 4 | 0;
+   i5 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i5 + 1;
+   i5 = HEAPU8[i5] | 0;
+  }
+  HEAP32[i2 >> 2] = i5;
+  i5 = HEAP32[i4 >> 2] | 0;
+  i4 = HEAP32[i2 + 52 >> 2] | 0;
+  i5 = _luaS_newlstr(i4, (HEAP32[i5 >> 2] | 0) + 1 | 0, (HEAP32[i5 + 4 >> 2] | 0) + -2 | 0) | 0;
+  i6 = i4 + 8 | 0;
+  i7 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i7 + 16;
+  HEAP32[i7 >> 2] = i5;
+  HEAP32[i7 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 64;
+  i7 = _luaH_set(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 4 >> 2] | 0, (HEAP32[i6 >> 2] | 0) + -16 | 0) | 0;
+  i2 = i7 + 8 | 0;
+  if ((HEAP32[i2 >> 2] | 0) == 0 ? (HEAP32[i7 >> 2] = 1, HEAP32[i2 >> 2] = 1, (HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) : 0) {
+   _luaC_step(i4);
+  }
+  HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + -16;
+  HEAP32[i3 >> 2] = i5;
+  i27 = 289;
+  STACKTOP = i1;
+  return i27 | 0;
+ } else if ((i9 | 0) == 161) {
+  i10 = HEAP32[i4 >> 2] | 0;
+  i9 = i10 + 4 | 0;
+  i13 = HEAP32[i9 >> 2] | 0;
+  i12 = i10 + 8 | 0;
+  i11 = HEAP32[i12 >> 2] | 0;
+  do {
+   if ((i13 + 1 | 0) >>> 0 > i11 >>> 0) {
+    if (i11 >>> 0 > 2147483645) {
+     _lexerror(i2, 12368, 0);
+    }
+    i13 = i11 << 1;
+    i20 = HEAP32[i2 + 52 >> 2] | 0;
+    if ((i13 | 0) == -2) {
+     _luaM_toobig(i20);
+    } else {
+     i25 = _luaM_realloc_(i20, HEAP32[i10 >> 2] | 0, i11, i13) | 0;
+     HEAP32[i10 >> 2] = i25;
+     HEAP32[i12 >> 2] = i13;
+     i26 = HEAP32[i9 >> 2] | 0;
+     break;
+    }
+   } else {
+    i26 = i13;
+    i25 = HEAP32[i10 >> 2] | 0;
+   }
+  } while (0);
+  HEAP32[i9 >> 2] = i26 + 1;
+  HEAP8[i25 + i26 | 0] = 46;
+  i9 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i9 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i20 = _luaZ_fill(i9) | 0;
+  } else {
+   i27 = i9 + 4 | 0;
+   i20 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i20 + 1;
+   i20 = HEAPU8[i20] | 0;
+  }
+  HEAP32[i2 >> 2] = i20;
+  if ((i20 | 0) != 0 ? (_memchr(12304, i20, 2) | 0) != 0 : 0) {
+   i6 = HEAP32[i4 >> 2] | 0;
+   i3 = i6 + 4 | 0;
+   i9 = HEAP32[i3 >> 2] | 0;
+   i8 = i6 + 8 | 0;
+   i7 = HEAP32[i8 >> 2] | 0;
+   do {
+    if ((i9 + 1 | 0) >>> 0 > i7 >>> 0) {
+     if (i7 >>> 0 > 2147483645) {
+      _lexerror(i2, 12368, 0);
+     }
+     i9 = i7 << 1;
+     i10 = HEAP32[i2 + 52 >> 2] | 0;
+     if ((i9 | 0) == -2) {
+      _luaM_toobig(i10);
+     } else {
+      i21 = _luaM_realloc_(i10, HEAP32[i6 >> 2] | 0, i7, i9) | 0;
+      HEAP32[i6 >> 2] = i21;
+      HEAP32[i8 >> 2] = i9;
+      i22 = HEAP32[i3 >> 2] | 0;
+      break;
+     }
+    } else {
+     i22 = i9;
+     i21 = HEAP32[i6 >> 2] | 0;
+    }
+   } while (0);
+   HEAP32[i3 >> 2] = i22 + 1;
+   HEAP8[i21 + i22 | 0] = i20;
+   i3 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i3 >> 2] | 0;
+   HEAP32[i3 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i3 = _luaZ_fill(i3) | 0;
+   } else {
+    i27 = i3 + 4 | 0;
+    i3 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i3 + 1;
+    i3 = HEAPU8[i3] | 0;
+   }
+   HEAP32[i2 >> 2] = i3;
+   if ((i3 | 0) == 0) {
+    i27 = 279;
+    STACKTOP = i1;
+    return i27 | 0;
+   }
+   if ((_memchr(12304, i3, 2) | 0) == 0) {
+    i27 = 279;
+    STACKTOP = i1;
+    return i27 | 0;
+   }
+   i6 = HEAP32[i4 >> 2] | 0;
+   i7 = i6 + 4 | 0;
+   i9 = HEAP32[i7 >> 2] | 0;
+   i8 = i6 + 8 | 0;
+   i4 = HEAP32[i8 >> 2] | 0;
+   do {
+    if ((i9 + 1 | 0) >>> 0 > i4 >>> 0) {
+     if (i4 >>> 0 > 2147483645) {
+      _lexerror(i2, 12368, 0);
+     }
+     i10 = i4 << 1;
+     i9 = HEAP32[i2 + 52 >> 2] | 0;
+     if ((i10 | 0) == -2) {
+      _luaM_toobig(i9);
+     } else {
+      i18 = _luaM_realloc_(i9, HEAP32[i6 >> 2] | 0, i4, i10) | 0;
+      HEAP32[i6 >> 2] = i18;
+      HEAP32[i8 >> 2] = i10;
+      i19 = HEAP32[i7 >> 2] | 0;
+      break;
+     }
+    } else {
+     i19 = i9;
+     i18 = HEAP32[i6 >> 2] | 0;
+    }
+   } while (0);
+   HEAP32[i7 >> 2] = i19 + 1;
+   HEAP8[i18 + i19 | 0] = i3;
+   i3 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i3 >> 2] | 0;
+   HEAP32[i3 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i3 = _luaZ_fill(i3) | 0;
+   } else {
+    i27 = i3 + 4 | 0;
+    i3 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i3 + 1;
+    i3 = HEAPU8[i3] | 0;
+   }
+   HEAP32[i2 >> 2] = i3;
+   i27 = 280;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  if ((HEAP8[i20 + 10913 | 0] & 2) == 0) {
+   i27 = 46;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+ } else if ((i9 | 0) == 283) {
+  if ((HEAP8[i13 + 10913 | 0] & 1) == 0) {
+   i3 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i3 >> 2] | 0;
+   HEAP32[i3 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i3 = _luaZ_fill(i3) | 0;
+   } else {
+    i27 = i3 + 4 | 0;
+    i3 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i3 + 1;
+    i3 = HEAPU8[i3] | 0;
+   }
+   HEAP32[i2 >> 2] = i3;
+   i27 = i13;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i10 = i2 + 52 | 0;
+  while (1) {
+   i11 = HEAP32[i4 >> 2] | 0;
+   i9 = i11 + 4 | 0;
+   i12 = HEAP32[i9 >> 2] | 0;
+   i19 = i11 + 8 | 0;
+   i18 = HEAP32[i19 >> 2] | 0;
+   if ((i12 + 1 | 0) >>> 0 > i18 >>> 0) {
+    if (i18 >>> 0 > 2147483645) {
+     i9 = 288;
+     break;
+    }
+    i21 = i18 << 1;
+    i12 = HEAP32[i10 >> 2] | 0;
+    if ((i21 | 0) == -2) {
+     i9 = 290;
+     break;
+    }
+    i27 = _luaM_realloc_(i12, HEAP32[i11 >> 2] | 0, i18, i21) | 0;
+    HEAP32[i11 >> 2] = i27;
+    HEAP32[i19 >> 2] = i21;
+    i12 = HEAP32[i9 >> 2] | 0;
+    i11 = i27;
+   } else {
+    i11 = HEAP32[i11 >> 2] | 0;
+   }
+   HEAP32[i9 >> 2] = i12 + 1;
+   HEAP8[i11 + i12 | 0] = i13;
+   i9 = HEAP32[i5 >> 2] | 0;
+   i27 = HEAP32[i9 >> 2] | 0;
+   HEAP32[i9 >> 2] = i27 + -1;
+   if ((i27 | 0) == 0) {
+    i13 = _luaZ_fill(i9) | 0;
+   } else {
+    i27 = i9 + 4 | 0;
+    i13 = HEAP32[i27 >> 2] | 0;
+    HEAP32[i27 >> 2] = i13 + 1;
+    i13 = HEAPU8[i13] | 0;
+   }
+   HEAP32[i2 >> 2] = i13;
+   if ((HEAP8[i13 + 10913 | 0] & 3) == 0) {
+    i9 = 296;
+    break;
+   }
+  }
+  if ((i9 | 0) == 288) {
+   _lexerror(i2, 12368, 0);
+  } else if ((i9 | 0) == 290) {
+   _luaM_toobig(i12);
+  } else if ((i9 | 0) == 296) {
+   i6 = HEAP32[i4 >> 2] | 0;
+   i4 = HEAP32[i10 >> 2] | 0;
+   i6 = _luaS_newlstr(i4, HEAP32[i6 >> 2] | 0, HEAP32[i6 + 4 >> 2] | 0) | 0;
+   i7 = i4 + 8 | 0;
+   i8 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i8 + 16;
+   HEAP32[i8 >> 2] = i6;
+   i5 = i6 + 4 | 0;
+   HEAP32[i8 + 8 >> 2] = HEAPU8[i5] | 64;
+   i8 = _luaH_set(i4, HEAP32[(HEAP32[i2 + 48 >> 2] | 0) + 4 >> 2] | 0, (HEAP32[i7 >> 2] | 0) + -16 | 0) | 0;
+   i2 = i8 + 8 | 0;
+   if ((HEAP32[i2 >> 2] | 0) == 0 ? (HEAP32[i8 >> 2] = 1, HEAP32[i2 >> 2] = 1, (HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) : 0) {
+    _luaC_step(i4);
+   }
+   HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + -16;
+   HEAP32[i3 >> 2] = i6;
+   if ((HEAP8[i5] | 0) != 4) {
+    i27 = 288;
+    STACKTOP = i1;
+    return i27 | 0;
+   }
+   i2 = HEAP8[i6 + 6 | 0] | 0;
+   if (i2 << 24 >> 24 == 0) {
+    i27 = 288;
+    STACKTOP = i1;
+    return i27 | 0;
+   }
+   i27 = i2 & 255 | 256;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+ } else if ((i9 | 0) == 306) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ i9 = HEAP32[i4 >> 2] | 0;
+ i12 = i9 + 4 | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ i11 = i9 + 8 | 0;
+ i10 = HEAP32[i11 >> 2] | 0;
+ do {
+  if ((i13 + 1 | 0) >>> 0 > i10 >>> 0) {
+   if (i10 >>> 0 > 2147483645) {
+    _lexerror(i2, 12368, 0);
+   }
+   i18 = i10 << 1;
+   i13 = HEAP32[i2 + 52 >> 2] | 0;
+   if ((i18 | 0) == -2) {
+    _luaM_toobig(i13);
+   } else {
+    i16 = _luaM_realloc_(i13, HEAP32[i9 >> 2] | 0, i10, i18) | 0;
+    HEAP32[i9 >> 2] = i16;
+    HEAP32[i11 >> 2] = i18;
+    i17 = HEAP32[i12 >> 2] | 0;
+    break;
+   }
+  } else {
+   i17 = i13;
+   i16 = HEAP32[i9 >> 2] | 0;
+  }
+ } while (0);
+ HEAP32[i12 >> 2] = i17 + 1;
+ HEAP8[i16 + i17 | 0] = i20;
+ i9 = HEAP32[i5 >> 2] | 0;
+ i27 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = i27 + -1;
+ if ((i27 | 0) == 0) {
+  i9 = _luaZ_fill(i9) | 0;
+ } else {
+  i27 = i9 + 4 | 0;
+  i9 = HEAP32[i27 >> 2] | 0;
+  HEAP32[i27 >> 2] = i9 + 1;
+  i9 = HEAPU8[i9] | 0;
+ }
+ HEAP32[i2 >> 2] = i9;
+ if ((i20 | 0) == 48) {
+  if ((i9 | 0) != 0) {
+   if ((_memchr(12320, i9, 3) | 0) == 0) {
+    i15 = i9;
+    i9 = 12312;
+   } else {
+    i10 = HEAP32[i4 >> 2] | 0;
+    i13 = i10 + 4 | 0;
+    i16 = HEAP32[i13 >> 2] | 0;
+    i11 = i10 + 8 | 0;
+    i12 = HEAP32[i11 >> 2] | 0;
+    do {
+     if ((i16 + 1 | 0) >>> 0 > i12 >>> 0) {
+      if (i12 >>> 0 > 2147483645) {
+       _lexerror(i2, 12368, 0);
+      }
+      i17 = i12 << 1;
+      i16 = HEAP32[i2 + 52 >> 2] | 0;
+      if ((i17 | 0) == -2) {
+       _luaM_toobig(i16);
+      } else {
+       i15 = _luaM_realloc_(i16, HEAP32[i10 >> 2] | 0, i12, i17) | 0;
+       HEAP32[i10 >> 2] = i15;
+       HEAP32[i11 >> 2] = i17;
+       i14 = HEAP32[i13 >> 2] | 0;
+       break;
+      }
+     } else {
+      i14 = i16;
+      i15 = HEAP32[i10 >> 2] | 0;
+     }
+    } while (0);
+    HEAP32[i13 >> 2] = i14 + 1;
+    HEAP8[i15 + i14 | 0] = i9;
+    i9 = HEAP32[i5 >> 2] | 0;
+    i27 = HEAP32[i9 >> 2] | 0;
+    HEAP32[i9 >> 2] = i27 + -1;
+    if ((i27 | 0) == 0) {
+     i15 = _luaZ_fill(i9) | 0;
+    } else {
+     i27 = i9 + 4 | 0;
+     i15 = HEAP32[i27 >> 2] | 0;
+     HEAP32[i27 >> 2] = i15 + 1;
+     i15 = HEAPU8[i15] | 0;
+    }
+    HEAP32[i2 >> 2] = i15;
+    i9 = 12328;
+   }
+  } else {
+   i15 = 0;
+   i9 = 12312;
+  }
+ } else {
+  i15 = i9;
+  i9 = 12312;
+ }
+ i10 = i2 + 52 | 0;
+ while (1) {
+  if ((i15 | 0) != 0) {
+   if ((_memchr(i9, i15, 3) | 0) != 0) {
+    i12 = HEAP32[i4 >> 2] | 0;
+    i11 = i12 + 4 | 0;
+    i16 = HEAP32[i11 >> 2] | 0;
+    i14 = i12 + 8 | 0;
+    i13 = HEAP32[i14 >> 2] | 0;
+    if ((i16 + 1 | 0) >>> 0 > i13 >>> 0) {
+     if (i13 >>> 0 > 2147483645) {
+      i9 = 227;
+      break;
+     }
+     i17 = i13 << 1;
+     i16 = HEAP32[i10 >> 2] | 0;
+     if ((i17 | 0) == -2) {
+      i9 = 229;
+      break;
+     }
+     i27 = _luaM_realloc_(i16, HEAP32[i12 >> 2] | 0, i13, i17) | 0;
+     HEAP32[i12 >> 2] = i27;
+     HEAP32[i14 >> 2] = i17;
+     i16 = HEAP32[i11 >> 2] | 0;
+     i12 = i27;
+    } else {
+     i12 = HEAP32[i12 >> 2] | 0;
+    }
+    HEAP32[i11 >> 2] = i16 + 1;
+    HEAP8[i12 + i16 | 0] = i15;
+    i11 = HEAP32[i5 >> 2] | 0;
+    i27 = HEAP32[i11 >> 2] | 0;
+    HEAP32[i11 >> 2] = i27 + -1;
+    if ((i27 | 0) == 0) {
+     i15 = _luaZ_fill(i11) | 0;
+    } else {
+     i27 = i11 + 4 | 0;
+     i15 = HEAP32[i27 >> 2] | 0;
+     HEAP32[i27 >> 2] = i15 + 1;
+     i15 = HEAPU8[i15] | 0;
+    }
+    HEAP32[i2 >> 2] = i15;
+    if ((i15 | 0) != 0) {
+     if ((_memchr(12336, i15, 3) | 0) != 0) {
+      i12 = HEAP32[i4 >> 2] | 0;
+      i11 = i12 + 4 | 0;
+      i16 = HEAP32[i11 >> 2] | 0;
+      i14 = i12 + 8 | 0;
+      i13 = HEAP32[i14 >> 2] | 0;
+      if ((i16 + 1 | 0) >>> 0 > i13 >>> 0) {
+       if (i13 >>> 0 > 2147483645) {
+        i9 = 239;
+        break;
+       }
+       i17 = i13 << 1;
+       i16 = HEAP32[i10 >> 2] | 0;
+       if ((i17 | 0) == -2) {
+        i9 = 241;
+        break;
+       }
+       i27 = _luaM_realloc_(i16, HEAP32[i12 >> 2] | 0, i13, i17) | 0;
+       HEAP32[i12 >> 2] = i27;
+       HEAP32[i14 >> 2] = i17;
+       i16 = HEAP32[i11 >> 2] | 0;
+       i12 = i27;
+      } else {
+       i12 = HEAP32[i12 >> 2] | 0;
+      }
+      HEAP32[i11 >> 2] = i16 + 1;
+      HEAP8[i12 + i16 | 0] = i15;
+      i11 = HEAP32[i5 >> 2] | 0;
+      i27 = HEAP32[i11 >> 2] | 0;
+      HEAP32[i11 >> 2] = i27 + -1;
+      if ((i27 | 0) == 0) {
+       i15 = _luaZ_fill(i11) | 0;
+      } else {
+       i27 = i11 + 4 | 0;
+       i15 = HEAP32[i27 >> 2] | 0;
+       HEAP32[i27 >> 2] = i15 + 1;
+       i15 = HEAPU8[i15] | 0;
+      }
+      HEAP32[i2 >> 2] = i15;
+     }
+    } else {
+     i15 = 0;
+    }
+   }
+  } else {
+   i15 = 0;
+  }
+  i12 = HEAP32[i4 >> 2] | 0;
+  i11 = i12 + 4 | 0;
+  i17 = HEAP32[i11 >> 2] | 0;
+  i14 = i12 + 8 | 0;
+  i13 = HEAP32[i14 >> 2] | 0;
+  i16 = (i17 + 1 | 0) >>> 0 > i13 >>> 0;
+  if (!((HEAP8[i15 + 10913 | 0] & 16) != 0 | (i15 | 0) == 46)) {
+   i9 = 259;
+   break;
+  }
+  if (i16) {
+   if (i13 >>> 0 > 2147483645) {
+    i9 = 251;
+    break;
+   }
+   i17 = i13 << 1;
+   i16 = HEAP32[i10 >> 2] | 0;
+   if ((i17 | 0) == -2) {
+    i9 = 253;
+    break;
+   }
+   i27 = _luaM_realloc_(i16, HEAP32[i12 >> 2] | 0, i13, i17) | 0;
+   HEAP32[i12 >> 2] = i27;
+   HEAP32[i14 >> 2] = i17;
+   i17 = HEAP32[i11 >> 2] | 0;
+   i12 = i27;
+  } else {
+   i12 = HEAP32[i12 >> 2] | 0;
+  }
+  HEAP32[i11 >> 2] = i17 + 1;
+  HEAP8[i12 + i17 | 0] = i15;
+  i11 = HEAP32[i5 >> 2] | 0;
+  i27 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i27 + -1;
+  if ((i27 | 0) == 0) {
+   i15 = _luaZ_fill(i11) | 0;
+  } else {
+   i27 = i11 + 4 | 0;
+   i15 = HEAP32[i27 >> 2] | 0;
+   HEAP32[i27 >> 2] = i15 + 1;
+   i15 = HEAPU8[i15] | 0;
+  }
+  HEAP32[i2 >> 2] = i15;
+ }
+ if ((i9 | 0) == 227) {
+  _lexerror(i2, 12368, 0);
+ } else if ((i9 | 0) == 229) {
+  _luaM_toobig(i16);
+ } else if ((i9 | 0) == 239) {
+  _lexerror(i2, 12368, 0);
+ } else if ((i9 | 0) == 241) {
+  _luaM_toobig(i16);
+ } else if ((i9 | 0) == 251) {
+  _lexerror(i2, 12368, 0);
+ } else if ((i9 | 0) == 253) {
+  _luaM_toobig(i16);
+ } else if ((i9 | 0) == 259) {
+  do {
+   if (i16) {
+    if (i13 >>> 0 > 2147483645) {
+     _lexerror(i2, 12368, 0);
+    }
+    i5 = i13 << 1;
+    i9 = HEAP32[i10 >> 2] | 0;
+    if ((i5 | 0) == -2) {
+     _luaM_toobig(i9);
+    } else {
+     i7 = _luaM_realloc_(i9, HEAP32[i12 >> 2] | 0, i13, i5) | 0;
+     HEAP32[i12 >> 2] = i7;
+     HEAP32[i14 >> 2] = i5;
+     i8 = HEAP32[i11 >> 2] | 0;
+     break;
+    }
+   } else {
+    i8 = i17;
+    i7 = HEAP32[i12 >> 2] | 0;
+   }
+  } while (0);
+  HEAP32[i11 >> 2] = i8 + 1;
+  HEAP8[i7 + i8 | 0] = 0;
+  i5 = i2 + 76 | 0;
+  i7 = HEAP8[i5] | 0;
+  i10 = HEAP32[i4 >> 2] | 0;
+  i8 = HEAP32[i10 >> 2] | 0;
+  i10 = HEAP32[i10 + 4 >> 2] | 0;
+  if ((i10 | 0) == 0) {
+   i7 = -1;
+  } else {
+   do {
+    i10 = i10 + -1 | 0;
+    i9 = i8 + i10 | 0;
+    if ((HEAP8[i9] | 0) == 46) {
+     HEAP8[i9] = i7;
+    }
+   } while ((i10 | 0) != 0);
+   i7 = HEAP32[i4 >> 2] | 0;
+   i8 = HEAP32[i7 >> 2] | 0;
+   i7 = (HEAP32[i7 + 4 >> 2] | 0) + -1 | 0;
+  }
+  if ((_luaO_str2d(i8, i7, i3) | 0) != 0) {
+   i27 = 287;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i9 = HEAP8[i5] | 0;
+  i8 = HEAP8[HEAP32[(_localeconv() | 0) >> 2] | 0] | 0;
+  HEAP8[i5] = i8;
+  i10 = HEAP32[i4 >> 2] | 0;
+  i7 = HEAP32[i10 >> 2] | 0;
+  i10 = HEAP32[i10 + 4 >> 2] | 0;
+  if ((i10 | 0) == 0) {
+   i8 = -1;
+  } else {
+   do {
+    i10 = i10 + -1 | 0;
+    i11 = i7 + i10 | 0;
+    if ((HEAP8[i11] | 0) == i9 << 24 >> 24) {
+     HEAP8[i11] = i8;
+    }
+   } while ((i10 | 0) != 0);
+   i8 = HEAP32[i4 >> 2] | 0;
+   i7 = HEAP32[i8 >> 2] | 0;
+   i8 = (HEAP32[i8 + 4 >> 2] | 0) + -1 | 0;
+  }
+  if ((_luaO_str2d(i7, i8, i3) | 0) != 0) {
+   i27 = 287;
+   STACKTOP = i1;
+   return i27 | 0;
+  }
+  i1 = HEAP8[i5] | 0;
+  i4 = HEAP32[i4 >> 2] | 0;
+  i3 = HEAP32[i4 >> 2] | 0;
+  i4 = HEAP32[i4 + 4 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   _lexerror(i2, 12344, 287);
+  } else {
+   i6 = i4;
+  }
+  do {
+   i6 = i6 + -1 | 0;
+   i4 = i3 + i6 | 0;
+   if ((HEAP8[i4] | 0) == i1 << 24 >> 24) {
+    HEAP8[i4] = 46;
+   }
+  } while ((i6 | 0) != 0);
+  _lexerror(i2, 12344, 287);
+ }
+ return 0;
+}
+function _luaV_execute(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, d37 = 0.0, d38 = 0.0, d39 = 0.0;
+ i12 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i13 = i12 + 24 | 0;
+ i10 = i12 + 16 | 0;
+ i9 = i12 + 8 | 0;
+ i8 = i12;
+ i3 = i1 + 16 | 0;
+ i4 = i1 + 40 | 0;
+ i6 = i1 + 12 | 0;
+ i5 = i1 + 8 | 0;
+ i11 = i1 + 24 | 0;
+ i17 = i1 + 48 | 0;
+ i2 = i1 + 20 | 0;
+ i16 = i1 + 6 | 0;
+ i7 = i1 + 44 | 0;
+ i19 = HEAP32[i3 >> 2] | 0;
+ L1 : while (1) {
+  i22 = HEAP32[HEAP32[i19 >> 2] >> 2] | 0;
+  i18 = i22 + 12 | 0;
+  i23 = HEAP32[(HEAP32[i18 >> 2] | 0) + 8 >> 2] | 0;
+  i20 = i19 + 24 | 0;
+  i21 = i19 + 28 | 0;
+  i22 = i22 + 16 | 0;
+  i24 = i19 + 4 | 0;
+  i25 = HEAP32[i20 >> 2] | 0;
+  L3 : while (1) {
+   i28 = HEAP32[i21 >> 2] | 0;
+   HEAP32[i21 >> 2] = i28 + 4;
+   i28 = HEAP32[i28 >> 2] | 0;
+   i27 = HEAP8[i4] | 0;
+   do {
+    if (!((i27 & 12) == 0)) {
+     i26 = (HEAP32[i17 >> 2] | 0) + -1 | 0;
+     HEAP32[i17 >> 2] = i26;
+     i26 = (i26 | 0) == 0;
+     if (!i26 ? (i27 & 4) == 0 : 0) {
+      break;
+     }
+     i25 = HEAP32[i3 >> 2] | 0;
+     i29 = i27 & 255;
+     if ((i29 & 8 | 0) == 0 | i26 ^ 1) {
+      i27 = 0;
+     } else {
+      HEAP32[i17 >> 2] = HEAP32[i7 >> 2];
+      i27 = 1;
+     }
+     i26 = i25 + 18 | 0;
+     i30 = HEAPU8[i26] | 0;
+     if ((i30 & 128 | 0) == 0) {
+      if (i27) {
+       _luaD_hook(i1, 3, -1);
+      }
+      do {
+       if ((i29 & 4 | 0) == 0) {
+        i29 = i25 + 28 | 0;
+       } else {
+        i34 = HEAP32[(HEAP32[HEAP32[i25 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+        i29 = i25 + 28 | 0;
+        i32 = HEAP32[i29 >> 2] | 0;
+        i35 = HEAP32[i34 + 12 >> 2] | 0;
+        i33 = (i32 - i35 >> 2) + -1 | 0;
+        i34 = HEAP32[i34 + 20 >> 2] | 0;
+        i31 = (i34 | 0) == 0;
+        if (i31) {
+         i30 = 0;
+        } else {
+         i30 = HEAP32[i34 + (i33 << 2) >> 2] | 0;
+        }
+        if ((i33 | 0) != 0 ? (i14 = HEAP32[i2 >> 2] | 0, i32 >>> 0 > i14 >>> 0) : 0) {
+         if (i31) {
+          i31 = 0;
+         } else {
+          i31 = HEAP32[i34 + ((i14 - i35 >> 2) + -1 << 2) >> 2] | 0;
+         }
+         if ((i30 | 0) == (i31 | 0)) {
+          break;
+         }
+        }
+        _luaD_hook(i1, 2, i30);
+       }
+      } while (0);
+      HEAP32[i2 >> 2] = HEAP32[i29 >> 2];
+      if ((HEAP8[i16] | 0) == 1) {
+       i15 = 23;
+       break L1;
+      }
+     } else {
+      HEAP8[i26] = i30 & 127;
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+    }
+   } while (0);
+   i26 = i28 >>> 6 & 255;
+   i27 = i25 + (i26 << 4) | 0;
+   switch (i28 & 63 | 0) {
+   case 9:
+    {
+     i28 = HEAP32[i22 + (i28 >>> 23 << 2) >> 2] | 0;
+     i35 = HEAP32[i28 + 8 >> 2] | 0;
+     i33 = i27;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i36 = i35;
+     HEAP32[i36 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i36 + 4 >> 2] = i34;
+     i36 = i25 + (i26 << 4) + 8 | 0;
+     HEAP32[i35 + 8 >> 2] = HEAP32[i36 >> 2];
+     if ((HEAP32[i36 >> 2] & 64 | 0) == 0) {
+      continue L3;
+     }
+     i26 = HEAP32[i27 >> 2] | 0;
+     if ((HEAP8[i26 + 5 | 0] & 3) == 0) {
+      continue L3;
+     }
+     if ((HEAP8[i28 + 5 | 0] & 4) == 0) {
+      continue L3;
+     }
+     _luaC_barrier_(i1, i28, i26);
+     continue L3;
+    }
+   case 10:
+    {
+     i26 = i28 >>> 23;
+     if ((i26 & 256 | 0) == 0) {
+      i26 = i25 + (i26 << 4) | 0;
+     } else {
+      i26 = i23 + ((i26 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     _luaV_settable(i1, i27, i26, i25);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 17:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      d37 = +HEAPF64[i29 >> 3];
+      d38 = +HEAPF64[i28 >> 3];
+      HEAPF64[i27 >> 3] = d37 - d38 * +Math_floor(+(d37 / d38));
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 10);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 23:
+    {
+     if ((i26 | 0) != 0) {
+      _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i26 + -1 << 4) | 0);
+     }
+     HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + ((i28 >>> 14) + -131071 << 2);
+     continue L3;
+    }
+   case 24:
+    {
+     i27 = i28 >>> 23;
+     if ((i27 & 256 | 0) == 0) {
+      i27 = i25 + (i27 << 4) | 0;
+     } else {
+      i27 = i23 + ((i27 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i27 + 8 >> 2] | 0) == (HEAP32[i25 + 8 >> 2] | 0)) {
+      i27 = (_luaV_equalobj_(i1, i27, i25) | 0) != 0;
+     } else {
+      i27 = 0;
+     }
+     i25 = HEAP32[i21 >> 2] | 0;
+     if ((i27 & 1 | 0) == (i26 | 0)) {
+      i26 = HEAP32[i25 >> 2] | 0;
+      i27 = i26 >>> 6 & 255;
+      if ((i27 | 0) != 0) {
+       _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i27 + -1 << 4) | 0);
+       i25 = HEAP32[i21 >> 2] | 0;
+      }
+      i25 = i25 + ((i26 >>> 14) + -131070 << 2) | 0;
+     } else {
+      i25 = i25 + 4 | 0;
+     }
+     HEAP32[i21 >> 2] = i25;
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 18:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +Math_pow(+(+HEAPF64[i29 >> 3]), +(+HEAPF64[i28 >> 3]));
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 11);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 1:
+    {
+     i36 = i28 >>> 14;
+     i33 = i23 + (i36 << 4) | 0;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i27;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i23 + (i36 << 4) + 8 >> 2];
+     continue L3;
+    }
+   case 0:
+    {
+     i36 = i28 >>> 23;
+     i33 = i25 + (i36 << 4) | 0;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i27;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i25 + (i36 << 4) + 8 >> 2];
+     continue L3;
+    }
+   case 2:
+    {
+     i36 = HEAP32[i21 >> 2] | 0;
+     HEAP32[i21 >> 2] = i36 + 4;
+     i36 = (HEAP32[i36 >> 2] | 0) >>> 6;
+     i33 = i23 + (i36 << 4) | 0;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i27;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i23 + (i36 << 4) + 8 >> 2];
+     continue L3;
+    }
+   case 5:
+    {
+     i36 = HEAP32[(HEAP32[i22 + (i28 >>> 23 << 2) >> 2] | 0) + 8 >> 2] | 0;
+     i33 = i36;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i27;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i36 + 8 >> 2];
+     continue L3;
+    }
+   case 3:
+    {
+     HEAP32[i27 >> 2] = i28 >>> 23;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = 1;
+     if ((i28 & 8372224 | 0) == 0) {
+      continue L3;
+     }
+     HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + 4;
+     continue L3;
+    }
+   case 7:
+    {
+     i26 = i28 >>> 14;
+     if ((i26 & 256 | 0) == 0) {
+      i26 = i25 + ((i26 & 511) << 4) | 0;
+     } else {
+      i26 = i23 + ((i26 & 255) << 4) | 0;
+     }
+     _luaV_gettable(i1, i25 + (i28 >>> 23 << 4) | 0, i26, i27);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 12:
+    {
+     i36 = i28 >>> 23;
+     i29 = i25 + (i36 << 4) | 0;
+     i26 = i26 + 1 | 0;
+     i33 = i29;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i35 = i25 + (i26 << 4) | 0;
+     HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i35 + 4 >> 2] = i34;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i25 + (i36 << 4) + 8 >> 2];
+     i26 = i28 >>> 14;
+     if ((i26 & 256 | 0) == 0) {
+      i25 = i25 + ((i26 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i26 & 255) << 4) | 0;
+     }
+     _luaV_gettable(i1, i29, i25, i27);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 13:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +HEAPF64[i29 >> 3] + +HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 6);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 14:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +HEAPF64[i29 >> 3] - +HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 7);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 6:
+    {
+     i26 = i28 >>> 14;
+     if ((i26 & 256 | 0) == 0) {
+      i25 = i25 + ((i26 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i26 & 255) << 4) | 0;
+     }
+     _luaV_gettable(i1, HEAP32[(HEAP32[i22 + (i28 >>> 23 << 2) >> 2] | 0) + 8 >> 2] | 0, i25, i27);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 4:
+    {
+     i26 = i28 >>> 23;
+     while (1) {
+      HEAP32[i27 + 8 >> 2] = 0;
+      if ((i26 | 0) == 0) {
+       continue L3;
+      } else {
+       i26 = i26 + -1 | 0;
+       i27 = i27 + 16 | 0;
+      }
+     }
+    }
+   case 8:
+    {
+     i27 = i28 >>> 23;
+     if ((i27 & 256 | 0) == 0) {
+      i27 = i25 + (i27 << 4) | 0;
+     } else {
+      i27 = i23 + ((i27 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     _luaV_settable(i1, HEAP32[(HEAP32[i22 + (i26 << 2) >> 2] | 0) + 8 >> 2] | 0, i27, i25);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 11:
+    {
+     i29 = i28 >>> 23;
+     i28 = i28 >>> 14 & 511;
+     i30 = _luaH_new(i1) | 0;
+     HEAP32[i27 >> 2] = i30;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = 69;
+     if ((i28 | i29 | 0) != 0) {
+      i36 = _luaO_fb2int(i29) | 0;
+      _luaH_resize(i1, i30, i36, _luaO_fb2int(i28) | 0);
+     }
+     if ((HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+      HEAP32[i5 >> 2] = i25 + (i26 + 1 << 4);
+      _luaC_step(i1);
+      HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 19:
+    {
+     i36 = i28 >>> 23;
+     i28 = i25 + (i36 << 4) | 0;
+     if ((HEAP32[i25 + (i36 << 4) + 8 >> 2] | 0) == 3) {
+      HEAPF64[i27 >> 3] = -+HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     } else {
+      _luaV_arith(i1, i27, i28, i28, 12);
+      i25 = HEAP32[i20 >> 2] | 0;
+      continue L3;
+     }
+    }
+   case 15:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +HEAPF64[i29 >> 3] * +HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 8);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 16:
+    {
+     i29 = i28 >>> 23;
+     if ((i29 & 256 | 0) == 0) {
+      i29 = i25 + (i29 << 4) | 0;
+     } else {
+      i29 = i23 + ((i29 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i28 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i28 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     if ((HEAP32[i29 + 8 >> 2] | 0) == 3 ? (HEAP32[i28 + 8 >> 2] | 0) == 3 : 0) {
+      HEAPF64[i27 >> 3] = +HEAPF64[i29 >> 3] / +HEAPF64[i28 >> 3];
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+      continue L3;
+     }
+     _luaV_arith(i1, i27, i29, i28, 9);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 20:
+    {
+     i29 = i28 >>> 23;
+     i28 = HEAP32[i25 + (i29 << 4) + 8 >> 2] | 0;
+     if ((i28 | 0) != 0) {
+      if ((i28 | 0) == 1) {
+       i28 = (HEAP32[i25 + (i29 << 4) >> 2] | 0) == 0;
+      } else {
+       i28 = 0;
+      }
+     } else {
+      i28 = 1;
+     }
+     HEAP32[i27 >> 2] = i28 & 1;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = 1;
+     continue L3;
+    }
+   case 21:
+    {
+     _luaV_objlen(i1, i27, i25 + (i28 >>> 23 << 4) | 0);
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 22:
+    {
+     i27 = i28 >>> 23;
+     i28 = i28 >>> 14 & 511;
+     HEAP32[i5 >> 2] = i25 + (i28 + 1 << 4);
+     _luaV_concat(i1, 1 - i27 + i28 | 0);
+     i25 = HEAP32[i20 >> 2] | 0;
+     i28 = i25 + (i27 << 4) | 0;
+     i34 = i28;
+     i35 = HEAP32[i34 + 4 >> 2] | 0;
+     i36 = i25 + (i26 << 4) | 0;
+     HEAP32[i36 >> 2] = HEAP32[i34 >> 2];
+     HEAP32[i36 + 4 >> 2] = i35;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = HEAP32[i25 + (i27 << 4) + 8 >> 2];
+     if ((HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+      if (!(i26 >>> 0 < i27 >>> 0)) {
+       i28 = i25 + (i26 + 1 << 4) | 0;
+      }
+      HEAP32[i5 >> 2] = i28;
+      _luaC_step(i1);
+      HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     continue L3;
+    }
+   case 25:
+    {
+     i27 = i28 >>> 23;
+     if ((i27 & 256 | 0) == 0) {
+      i27 = i25 + (i27 << 4) | 0;
+     } else {
+      i27 = i23 + ((i27 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     i36 = (_luaV_lessthan(i1, i27, i25) | 0) == (i26 | 0);
+     i26 = HEAP32[i21 >> 2] | 0;
+     if (i36) {
+      i25 = HEAP32[i26 >> 2] | 0;
+      i27 = i25 >>> 6 & 255;
+      if ((i27 | 0) != 0) {
+       _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i27 + -1 << 4) | 0);
+       i26 = HEAP32[i21 >> 2] | 0;
+      }
+      i25 = i26 + ((i25 >>> 14) + -131070 << 2) | 0;
+     } else {
+      i25 = i26 + 4 | 0;
+     }
+     HEAP32[i21 >> 2] = i25;
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 27:
+    {
+     i29 = HEAP32[i25 + (i26 << 4) + 8 >> 2] | 0;
+     i26 = (i29 | 0) == 0;
+     if ((i28 & 8372224 | 0) == 0) {
+      if (!i26) {
+       if (!((i29 | 0) == 1 ? (HEAP32[i27 >> 2] | 0) == 0 : 0)) {
+        i15 = 192;
+       }
+      }
+     } else {
+      if (!i26) {
+       if ((i29 | 0) == 1 ? (HEAP32[i27 >> 2] | 0) == 0 : 0) {
+        i15 = 192;
+       }
+      } else {
+       i15 = 192;
+      }
+     }
+     if ((i15 | 0) == 192) {
+      i15 = 0;
+      HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + 4;
+      continue L3;
+     }
+     i27 = HEAP32[i21 >> 2] | 0;
+     i26 = HEAP32[i27 >> 2] | 0;
+     i28 = i26 >>> 6 & 255;
+     if ((i28 | 0) != 0) {
+      _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i28 + -1 << 4) | 0);
+      i27 = HEAP32[i21 >> 2] | 0;
+     }
+     HEAP32[i21 >> 2] = i27 + ((i26 >>> 14) + -131070 << 2);
+     continue L3;
+    }
+   case 26:
+    {
+     i27 = i28 >>> 23;
+     if ((i27 & 256 | 0) == 0) {
+      i27 = i25 + (i27 << 4) | 0;
+     } else {
+      i27 = i23 + ((i27 & 255) << 4) | 0;
+     }
+     i28 = i28 >>> 14;
+     if ((i28 & 256 | 0) == 0) {
+      i25 = i25 + ((i28 & 511) << 4) | 0;
+     } else {
+      i25 = i23 + ((i28 & 255) << 4) | 0;
+     }
+     i36 = (_luaV_lessequal(i1, i27, i25) | 0) == (i26 | 0);
+     i26 = HEAP32[i21 >> 2] | 0;
+     if (i36) {
+      i25 = HEAP32[i26 >> 2] | 0;
+      i27 = i25 >>> 6 & 255;
+      if ((i27 | 0) != 0) {
+       _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i27 + -1 << 4) | 0);
+       i26 = HEAP32[i21 >> 2] | 0;
+      }
+      i25 = i26 + ((i25 >>> 14) + -131070 << 2) | 0;
+     } else {
+      i25 = i26 + 4 | 0;
+     }
+     HEAP32[i21 >> 2] = i25;
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 28:
+    {
+     i30 = i28 >>> 23;
+     i29 = i25 + (i30 << 4) | 0;
+     i30 = HEAP32[i25 + (i30 << 4) + 8 >> 2] | 0;
+     i31 = (i30 | 0) == 0;
+     if ((i28 & 8372224 | 0) == 0) {
+      if (!i31) {
+       if (!((i30 | 0) == 1 ? (HEAP32[i29 >> 2] | 0) == 0 : 0)) {
+        i15 = 203;
+       }
+      }
+     } else {
+      if (!i31) {
+       if ((i30 | 0) == 1 ? (HEAP32[i29 >> 2] | 0) == 0 : 0) {
+        i15 = 203;
+       }
+      } else {
+       i15 = 203;
+      }
+     }
+     if ((i15 | 0) == 203) {
+      i15 = 0;
+      HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + 4;
+      continue L3;
+     }
+     i36 = i29;
+     i28 = HEAP32[i36 + 4 >> 2] | 0;
+     HEAP32[i27 >> 2] = HEAP32[i36 >> 2];
+     HEAP32[i27 + 4 >> 2] = i28;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = i30;
+     i27 = HEAP32[i21 >> 2] | 0;
+     i26 = HEAP32[i27 >> 2] | 0;
+     i28 = i26 >>> 6 & 255;
+     if ((i28 | 0) != 0) {
+      _luaF_close(i1, (HEAP32[i20 >> 2] | 0) + (i28 + -1 << 4) | 0);
+      i27 = HEAP32[i21 >> 2] | 0;
+     }
+     HEAP32[i21 >> 2] = i27 + ((i26 >>> 14) + -131070 << 2);
+     continue L3;
+    }
+   case 30:
+    {
+     i28 = i28 >>> 23;
+     if ((i28 | 0) != 0) {
+      HEAP32[i5 >> 2] = i25 + (i26 + i28 << 4);
+     }
+     if ((_luaD_precall(i1, i27, -1) | 0) == 0) {
+      i15 = 218;
+      break L3;
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 29:
+    {
+     i29 = i28 >>> 23;
+     i28 = i28 >>> 14 & 511;
+     if ((i29 | 0) != 0) {
+      HEAP32[i5 >> 2] = i25 + (i26 + i29 << 4);
+     }
+     if ((_luaD_precall(i1, i27, i28 + -1 | 0) | 0) == 0) {
+      i15 = 213;
+      break L3;
+     }
+     if ((i28 | 0) != 0) {
+      HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 32:
+    {
+     d39 = +HEAPF64[i25 + (i26 + 2 << 4) >> 3];
+     d38 = d39 + +HEAPF64[i27 >> 3];
+     d37 = +HEAPF64[i25 + (i26 + 1 << 4) >> 3];
+     if (d39 > 0.0) {
+      if (!(d38 <= d37)) {
+       continue L3;
+      }
+     } else {
+      if (!(d37 <= d38)) {
+       continue L3;
+      }
+     }
+     HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + ((i28 >>> 14) + -131071 << 2);
+     HEAPF64[i27 >> 3] = d38;
+     HEAP32[i25 + (i26 << 4) + 8 >> 2] = 3;
+     i36 = i26 + 3 | 0;
+     HEAPF64[i25 + (i36 << 4) >> 3] = d38;
+     HEAP32[i25 + (i36 << 4) + 8 >> 2] = 3;
+     continue L3;
+    }
+   case 33:
+    {
+     i32 = i26 + 1 | 0;
+     i30 = i25 + (i32 << 4) | 0;
+     i31 = i26 + 2 | 0;
+     i29 = i25 + (i31 << 4) | 0;
+     i26 = i25 + (i26 << 4) + 8 | 0;
+     i33 = HEAP32[i26 >> 2] | 0;
+     if ((i33 | 0) != 3) {
+      if ((i33 & 15 | 0) != 4) {
+       i15 = 239;
+       break L1;
+      }
+      i36 = HEAP32[i27 >> 2] | 0;
+      if ((_luaO_str2d(i36 + 16 | 0, HEAP32[i36 + 12 >> 2] | 0, i8) | 0) == 0) {
+       i15 = 239;
+       break L1;
+      }
+      HEAPF64[i27 >> 3] = +HEAPF64[i8 >> 3];
+      HEAP32[i26 >> 2] = 3;
+      if ((i27 | 0) == 0) {
+       i15 = 239;
+       break L1;
+      }
+     }
+     i33 = i25 + (i32 << 4) + 8 | 0;
+     i32 = HEAP32[i33 >> 2] | 0;
+     if ((i32 | 0) != 3) {
+      if ((i32 & 15 | 0) != 4) {
+       i15 = 244;
+       break L1;
+      }
+      i36 = HEAP32[i30 >> 2] | 0;
+      if ((_luaO_str2d(i36 + 16 | 0, HEAP32[i36 + 12 >> 2] | 0, i9) | 0) == 0) {
+       i15 = 244;
+       break L1;
+      }
+      HEAPF64[i30 >> 3] = +HEAPF64[i9 >> 3];
+      HEAP32[i33 >> 2] = 3;
+     }
+     i31 = i25 + (i31 << 4) + 8 | 0;
+     i30 = HEAP32[i31 >> 2] | 0;
+     if ((i30 | 0) != 3) {
+      if ((i30 & 15 | 0) != 4) {
+       i15 = 249;
+       break L1;
+      }
+      i36 = HEAP32[i29 >> 2] | 0;
+      if ((_luaO_str2d(i36 + 16 | 0, HEAP32[i36 + 12 >> 2] | 0, i10) | 0) == 0) {
+       i15 = 249;
+       break L1;
+      }
+      HEAPF64[i29 >> 3] = +HEAPF64[i10 >> 3];
+      HEAP32[i31 >> 2] = 3;
+     }
+     HEAPF64[i27 >> 3] = +HEAPF64[i27 >> 3] - +HEAPF64[i29 >> 3];
+     HEAP32[i26 >> 2] = 3;
+     HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + ((i28 >>> 14) + -131071 << 2);
+     continue L3;
+    }
+   case 31:
+    {
+     i15 = 223;
+     break L3;
+    }
+   case 34:
+    {
+     i35 = i26 + 3 | 0;
+     i36 = i25 + (i35 << 4) | 0;
+     i33 = i26 + 2 | 0;
+     i34 = i26 + 5 | 0;
+     i32 = i25 + (i33 << 4) | 0;
+     i31 = HEAP32[i32 + 4 >> 2] | 0;
+     i30 = i25 + (i34 << 4) | 0;
+     HEAP32[i30 >> 2] = HEAP32[i32 >> 2];
+     HEAP32[i30 + 4 >> 2] = i31;
+     HEAP32[i25 + (i34 << 4) + 8 >> 2] = HEAP32[i25 + (i33 << 4) + 8 >> 2];
+     i34 = i26 + 1 | 0;
+     i33 = i26 + 4 | 0;
+     i30 = i25 + (i34 << 4) | 0;
+     i31 = HEAP32[i30 + 4 >> 2] | 0;
+     i32 = i25 + (i33 << 4) | 0;
+     HEAP32[i32 >> 2] = HEAP32[i30 >> 2];
+     HEAP32[i32 + 4 >> 2] = i31;
+     HEAP32[i25 + (i33 << 4) + 8 >> 2] = HEAP32[i25 + (i34 << 4) + 8 >> 2];
+     i33 = i27;
+     i34 = HEAP32[i33 + 4 >> 2] | 0;
+     i27 = i36;
+     HEAP32[i27 >> 2] = HEAP32[i33 >> 2];
+     HEAP32[i27 + 4 >> 2] = i34;
+     HEAP32[i25 + (i35 << 4) + 8 >> 2] = HEAP32[i25 + (i26 << 4) + 8 >> 2];
+     HEAP32[i5 >> 2] = i25 + (i26 + 6 << 4);
+     _luaD_call(i1, i36, i28 >>> 14 & 511, 1);
+     i36 = HEAP32[i20 >> 2] | 0;
+     HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     i27 = HEAP32[i21 >> 2] | 0;
+     HEAP32[i21 >> 2] = i27 + 4;
+     i27 = HEAP32[i27 >> 2] | 0;
+     i25 = i36;
+     i28 = i27;
+     i27 = i36 + ((i27 >>> 6 & 255) << 4) | 0;
+     break;
+    }
+   case 35:
+    {
+     break;
+    }
+   case 36:
+    {
+     i29 = i28 >>> 23;
+     i28 = i28 >>> 14 & 511;
+     if ((i29 | 0) == 0) {
+      i29 = ((HEAP32[i5 >> 2] | 0) - i27 >> 4) + -1 | 0;
+     }
+     if ((i28 | 0) == 0) {
+      i28 = HEAP32[i21 >> 2] | 0;
+      HEAP32[i21 >> 2] = i28 + 4;
+      i28 = (HEAP32[i28 >> 2] | 0) >>> 6;
+     }
+     i27 = HEAP32[i27 >> 2] | 0;
+     i30 = i29 + -50 + (i28 * 50 | 0) | 0;
+     if ((i30 | 0) > (HEAP32[i27 + 28 >> 2] | 0)) {
+      _luaH_resizearray(i1, i27, i30);
+     }
+     if ((i29 | 0) > 0) {
+      i28 = i27 + 5 | 0;
+      while (1) {
+       i36 = i29 + i26 | 0;
+       i32 = i25 + (i36 << 4) | 0;
+       i31 = i30 + -1 | 0;
+       _luaH_setint(i1, i27, i30, i32);
+       if (((HEAP32[i25 + (i36 << 4) + 8 >> 2] & 64 | 0) != 0 ? !((HEAP8[(HEAP32[i32 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) ? !((HEAP8[i28] & 4) == 0) : 0) {
+        _luaC_barrierback_(i1, i27);
+       }
+       i29 = i29 + -1 | 0;
+       if ((i29 | 0) > 0) {
+        i30 = i31;
+       } else {
+        break;
+       }
+      }
+     }
+     HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     continue L3;
+    }
+   case 37:
+    {
+     i29 = HEAP32[(HEAP32[(HEAP32[i18 >> 2] | 0) + 16 >> 2] | 0) + (i28 >>> 14 << 2) >> 2] | 0;
+     i28 = i29 + 32 | 0;
+     i33 = HEAP32[i28 >> 2] | 0;
+     i30 = HEAP32[i29 + 40 >> 2] | 0;
+     i31 = HEAP32[i29 + 28 >> 2] | 0;
+     L323 : do {
+      if ((i33 | 0) == 0) {
+       i15 = 276;
+      } else {
+       if ((i30 | 0) > 0) {
+        i34 = i33 + 16 | 0;
+        i32 = 0;
+        while (1) {
+         i35 = HEAPU8[i31 + (i32 << 3) + 5 | 0] | 0;
+         if ((HEAP8[i31 + (i32 << 3) + 4 | 0] | 0) == 0) {
+          i36 = HEAP32[(HEAP32[i22 + (i35 << 2) >> 2] | 0) + 8 >> 2] | 0;
+         } else {
+          i36 = i25 + (i35 << 4) | 0;
+         }
+         i35 = i32 + 1 | 0;
+         if ((HEAP32[(HEAP32[i34 + (i32 << 2) >> 2] | 0) + 8 >> 2] | 0) != (i36 | 0)) {
+          i15 = 276;
+          break L323;
+         }
+         if ((i35 | 0) < (i30 | 0)) {
+          i32 = i35;
+         } else {
+          break;
+         }
+        }
+       }
+       HEAP32[i27 >> 2] = i33;
+       HEAP32[i25 + (i26 << 4) + 8 >> 2] = 70;
+      }
+     } while (0);
+     if ((i15 | 0) == 276) {
+      i15 = 0;
+      i32 = _luaF_newLclosure(i1, i30) | 0;
+      HEAP32[i32 + 12 >> 2] = i29;
+      HEAP32[i27 >> 2] = i32;
+      HEAP32[i25 + (i26 << 4) + 8 >> 2] = 70;
+      if ((i30 | 0) > 0) {
+       i27 = i32 + 16 | 0;
+       i34 = 0;
+       do {
+        i33 = HEAPU8[i31 + (i34 << 3) + 5 | 0] | 0;
+        if ((HEAP8[i31 + (i34 << 3) + 4 | 0] | 0) == 0) {
+         HEAP32[i27 + (i34 << 2) >> 2] = HEAP32[i22 + (i33 << 2) >> 2];
+        } else {
+         HEAP32[i27 + (i34 << 2) >> 2] = _luaF_findupval(i1, i25 + (i33 << 4) | 0) | 0;
+        }
+        i34 = i34 + 1 | 0;
+       } while ((i34 | 0) != (i30 | 0));
+      }
+      if (!((HEAP8[i29 + 5 | 0] & 4) == 0)) {
+       _luaC_barrierproto_(i1, i29, i32);
+      }
+      HEAP32[i28 >> 2] = i32;
+     }
+     if ((HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+      HEAP32[i5 >> 2] = i25 + (i26 + 1 << 4);
+      _luaC_step(i1);
+      HEAP32[i5 >> 2] = HEAP32[i24 >> 2];
+     }
+     i25 = HEAP32[i20 >> 2] | 0;
+     continue L3;
+    }
+   case 38:
+    {
+     i36 = i28 >>> 23;
+     i29 = i36 + -1 | 0;
+     i30 = (i25 - (HEAP32[i19 >> 2] | 0) >> 4) - (HEAPU8[(HEAP32[i18 >> 2] | 0) + 76 | 0] | 0) | 0;
+     i28 = i30 + -1 | 0;
+     if ((i36 | 0) == 0) {
+      if (((HEAP32[i11 >> 2] | 0) - (HEAP32[i5 >> 2] | 0) >> 4 | 0) <= (i28 | 0)) {
+       _luaD_growstack(i1, i28);
+      }
+      i27 = HEAP32[i20 >> 2] | 0;
+      HEAP32[i5 >> 2] = i27 + (i28 + i26 << 4);
+      i29 = i28;
+      i25 = i27;
+      i27 = i27 + (i26 << 4) | 0;
+     }
+     if ((i29 | 0) <= 0) {
+      continue L3;
+     }
+     i26 = 1 - i30 | 0;
+     i30 = 0;
+     while (1) {
+      if ((i30 | 0) < (i28 | 0)) {
+       i36 = i30 + i26 | 0;
+       i33 = i25 + (i36 << 4) | 0;
+       i34 = HEAP32[i33 + 4 >> 2] | 0;
+       i35 = i27 + (i30 << 4) | 0;
+       HEAP32[i35 >> 2] = HEAP32[i33 >> 2];
+       HEAP32[i35 + 4 >> 2] = i34;
+       HEAP32[i27 + (i30 << 4) + 8 >> 2] = HEAP32[i25 + (i36 << 4) + 8 >> 2];
+      } else {
+       HEAP32[i27 + (i30 << 4) + 8 >> 2] = 0;
+      }
+      i30 = i30 + 1 | 0;
+      if ((i30 | 0) == (i29 | 0)) {
+       continue L3;
+      }
+     }
+    }
+   default:
+    {
+     continue L3;
+    }
+   }
+   i26 = HEAP32[i27 + 24 >> 2] | 0;
+   if ((i26 | 0) == 0) {
+    continue;
+   }
+   i34 = i27 + 16 | 0;
+   i35 = HEAP32[i34 + 4 >> 2] | 0;
+   i36 = i27;
+   HEAP32[i36 >> 2] = HEAP32[i34 >> 2];
+   HEAP32[i36 + 4 >> 2] = i35;
+   HEAP32[i27 + 8 >> 2] = i26;
+   HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + ((i28 >>> 14) + -131071 << 2);
+  }
+  if ((i15 | 0) == 213) {
+   i15 = 0;
+   i19 = HEAP32[i3 >> 2] | 0;
+   i36 = i19 + 18 | 0;
+   HEAP8[i36] = HEAPU8[i36] | 4;
+   continue;
+  } else if ((i15 | 0) == 218) {
+   i15 = 0;
+   i22 = HEAP32[i3 >> 2] | 0;
+   i19 = HEAP32[i22 + 8 >> 2] | 0;
+   i23 = HEAP32[i22 >> 2] | 0;
+   i24 = HEAP32[i19 >> 2] | 0;
+   i20 = i22 + 24 | 0;
+   i21 = (HEAP32[i20 >> 2] | 0) + (HEAPU8[(HEAP32[(HEAP32[i23 >> 2] | 0) + 12 >> 2] | 0) + 76 | 0] << 4) | 0;
+   if ((HEAP32[(HEAP32[i18 >> 2] | 0) + 56 >> 2] | 0) > 0) {
+    _luaF_close(i1, HEAP32[i19 + 24 >> 2] | 0);
+   }
+   if (i23 >>> 0 < i21 >>> 0) {
+    i25 = i23;
+    i18 = 0;
+    do {
+     i34 = i25;
+     i35 = HEAP32[i34 + 4 >> 2] | 0;
+     i36 = i24 + (i18 << 4) | 0;
+     HEAP32[i36 >> 2] = HEAP32[i34 >> 2];
+     HEAP32[i36 + 4 >> 2] = i35;
+     HEAP32[i24 + (i18 << 4) + 8 >> 2] = HEAP32[i23 + (i18 << 4) + 8 >> 2];
+     i18 = i18 + 1 | 0;
+     i25 = i23 + (i18 << 4) | 0;
+    } while (i25 >>> 0 < i21 >>> 0);
+   }
+   i36 = i23;
+   HEAP32[i19 + 24 >> 2] = i24 + ((HEAP32[i20 >> 2] | 0) - i36 >> 4 << 4);
+   i36 = i24 + ((HEAP32[i5 >> 2] | 0) - i36 >> 4 << 4) | 0;
+   HEAP32[i5 >> 2] = i36;
+   HEAP32[i19 + 4 >> 2] = i36;
+   HEAP32[i19 + 28 >> 2] = HEAP32[i22 + 28 >> 2];
+   i36 = i19 + 18 | 0;
+   HEAP8[i36] = HEAPU8[i36] | 64;
+   HEAP32[i3 >> 2] = i19;
+   continue;
+  } else if ((i15 | 0) == 223) {
+   i15 = 0;
+   i20 = i28 >>> 23;
+   if ((i20 | 0) != 0) {
+    HEAP32[i5 >> 2] = i25 + (i20 + -1 + i26 << 4);
+   }
+   if ((HEAP32[(HEAP32[i18 >> 2] | 0) + 56 >> 2] | 0) > 0) {
+    _luaF_close(i1, i25);
+   }
+   i18 = _luaD_poscall(i1, i27) | 0;
+   if ((HEAP8[i19 + 18 | 0] & 4) == 0) {
+    i15 = 228;
+    break;
+   }
+   i19 = HEAP32[i3 >> 2] | 0;
+   if ((i18 | 0) == 0) {
+    continue;
+   }
+   HEAP32[i5 >> 2] = HEAP32[i19 + 4 >> 2];
+   continue;
+  }
+ }
+ if ((i15 | 0) == 23) {
+  if (!i27) {
+   i36 = HEAP32[i29 >> 2] | 0;
+   i36 = i36 + -4 | 0;
+   HEAP32[i29 >> 2] = i36;
+   i36 = HEAP8[i26] | 0;
+   i36 = i36 & 255;
+   i36 = i36 | 128;
+   i36 = i36 & 255;
+   HEAP8[i26] = i36;
+   i36 = HEAP32[i5 >> 2] | 0;
+   i36 = i36 + -16 | 0;
+   HEAP32[i25 >> 2] = i36;
+   _luaD_throw(i1, 1);
+  }
+  HEAP32[i17 >> 2] = 1;
+  i36 = HEAP32[i29 >> 2] | 0;
+  i36 = i36 + -4 | 0;
+  HEAP32[i29 >> 2] = i36;
+  i36 = HEAP8[i26] | 0;
+  i36 = i36 & 255;
+  i36 = i36 | 128;
+  i36 = i36 & 255;
+  HEAP8[i26] = i36;
+  i36 = HEAP32[i5 >> 2] | 0;
+  i36 = i36 + -16 | 0;
+  HEAP32[i25 >> 2] = i36;
+  _luaD_throw(i1, 1);
+ } else if ((i15 | 0) == 228) {
+  STACKTOP = i12;
+  return;
+ } else if ((i15 | 0) == 239) {
+  _luaG_runerror(i1, 9040, i13);
+ } else if ((i15 | 0) == 244) {
+  _luaG_runerror(i1, 9080, i13);
+ } else if ((i15 | 0) == 249) {
+  _luaG_runerror(i1, 9112, i13);
+ }
+}
+function ___floatscan(i8, i2, i11) {
+ i8 = i8 | 0;
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i12 = 0, i13 = 0, d14 = 0.0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, d28 = 0.0, i29 = 0, d30 = 0.0, d31 = 0.0, d32 = 0.0, d33 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 512 | 0;
+ i5 = i1;
+ if ((i2 | 0) == 1) {
+  i2 = 53;
+  i3 = -1074;
+ } else if ((i2 | 0) == 2) {
+  i2 = 53;
+  i3 = -1074;
+ } else if ((i2 | 0) == 0) {
+  i2 = 24;
+  i3 = -149;
+ } else {
+  d31 = 0.0;
+  STACKTOP = i1;
+  return +d31;
+ }
+ i9 = i8 + 4 | 0;
+ i10 = i8 + 100 | 0;
+ do {
+  i4 = HEAP32[i9 >> 2] | 0;
+  if (i4 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+   HEAP32[i9 >> 2] = i4 + 1;
+   i21 = HEAPU8[i4] | 0;
+  } else {
+   i21 = ___shgetc(i8) | 0;
+  }
+ } while ((_isspace(i21 | 0) | 0) != 0);
+ do {
+  if ((i21 | 0) == 43 | (i21 | 0) == 45) {
+   i4 = 1 - (((i21 | 0) == 45) << 1) | 0;
+   i7 = HEAP32[i9 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+    HEAP32[i9 >> 2] = i7 + 1;
+    i21 = HEAPU8[i7] | 0;
+    break;
+   } else {
+    i21 = ___shgetc(i8) | 0;
+    break;
+   }
+  } else {
+   i4 = 1;
+  }
+ } while (0);
+ i7 = 0;
+ do {
+  if ((i21 | 32 | 0) != (HEAP8[13408 + i7 | 0] | 0)) {
+   break;
+  }
+  do {
+   if (i7 >>> 0 < 7) {
+    i12 = HEAP32[i9 >> 2] | 0;
+    if (i12 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+     HEAP32[i9 >> 2] = i12 + 1;
+     i21 = HEAPU8[i12] | 0;
+     break;
+    } else {
+     i21 = ___shgetc(i8) | 0;
+     break;
+    }
+   }
+  } while (0);
+  i7 = i7 + 1 | 0;
+ } while (i7 >>> 0 < 8);
+ do {
+  if ((i7 | 0) == 3) {
+   i13 = 23;
+  } else if ((i7 | 0) != 8) {
+   i12 = (i11 | 0) == 0;
+   if (!(i7 >>> 0 < 4 | i12)) {
+    if ((i7 | 0) == 8) {
+     break;
+    } else {
+     i13 = 23;
+     break;
+    }
+   }
+   L34 : do {
+    if ((i7 | 0) == 0) {
+     i7 = 0;
+     do {
+      if ((i21 | 32 | 0) != (HEAP8[13424 + i7 | 0] | 0)) {
+       break L34;
+      }
+      do {
+       if (i7 >>> 0 < 2) {
+        i15 = HEAP32[i9 >> 2] | 0;
+        if (i15 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+         HEAP32[i9 >> 2] = i15 + 1;
+         i21 = HEAPU8[i15] | 0;
+         break;
+        } else {
+         i21 = ___shgetc(i8) | 0;
+         break;
+        }
+       }
+      } while (0);
+      i7 = i7 + 1 | 0;
+     } while (i7 >>> 0 < 3);
+    }
+   } while (0);
+   if ((i7 | 0) == 0) {
+    do {
+     if ((i21 | 0) == 48) {
+      i7 = HEAP32[i9 >> 2] | 0;
+      if (i7 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+       HEAP32[i9 >> 2] = i7 + 1;
+       i7 = HEAPU8[i7] | 0;
+      } else {
+       i7 = ___shgetc(i8) | 0;
+      }
+      if ((i7 | 32 | 0) != 120) {
+       if ((HEAP32[i10 >> 2] | 0) == 0) {
+        i21 = 48;
+        break;
+       }
+       HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+       i21 = 48;
+       break;
+      }
+      i5 = HEAP32[i9 >> 2] | 0;
+      if (i5 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+       HEAP32[i9 >> 2] = i5 + 1;
+       i21 = HEAPU8[i5] | 0;
+       i19 = 0;
+      } else {
+       i21 = ___shgetc(i8) | 0;
+       i19 = 0;
+      }
+      while (1) {
+       if ((i21 | 0) == 46) {
+        i13 = 70;
+        break;
+       } else if ((i21 | 0) != 48) {
+        i5 = 0;
+        i7 = 0;
+        i15 = 0;
+        i16 = 0;
+        i18 = 0;
+        i20 = 0;
+        d28 = 1.0;
+        i17 = 0;
+        d14 = 0.0;
+        break;
+       }
+       i5 = HEAP32[i9 >> 2] | 0;
+       if (i5 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+        HEAP32[i9 >> 2] = i5 + 1;
+        i21 = HEAPU8[i5] | 0;
+        i19 = 1;
+        continue;
+       } else {
+        i21 = ___shgetc(i8) | 0;
+        i19 = 1;
+        continue;
+       }
+      }
+      L66 : do {
+       if ((i13 | 0) == 70) {
+        i5 = HEAP32[i9 >> 2] | 0;
+        if (i5 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+         HEAP32[i9 >> 2] = i5 + 1;
+         i21 = HEAPU8[i5] | 0;
+        } else {
+         i21 = ___shgetc(i8) | 0;
+        }
+        if ((i21 | 0) == 48) {
+         i15 = -1;
+         i16 = -1;
+         while (1) {
+          i5 = HEAP32[i9 >> 2] | 0;
+          if (i5 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+           HEAP32[i9 >> 2] = i5 + 1;
+           i21 = HEAPU8[i5] | 0;
+          } else {
+           i21 = ___shgetc(i8) | 0;
+          }
+          if ((i21 | 0) != 48) {
+           i5 = 0;
+           i7 = 0;
+           i19 = 1;
+           i18 = 1;
+           i20 = 0;
+           d28 = 1.0;
+           i17 = 0;
+           d14 = 0.0;
+           break L66;
+          }
+          i29 = _i64Add(i15 | 0, i16 | 0, -1, -1) | 0;
+          i15 = i29;
+          i16 = tempRet0;
+         }
+        } else {
+         i5 = 0;
+         i7 = 0;
+         i15 = 0;
+         i16 = 0;
+         i18 = 1;
+         i20 = 0;
+         d28 = 1.0;
+         i17 = 0;
+         d14 = 0.0;
+        }
+       }
+      } while (0);
+      L79 : while (1) {
+       i24 = i21 + -48 | 0;
+       do {
+        if (!(i24 >>> 0 < 10)) {
+         i23 = i21 | 32;
+         i22 = (i21 | 0) == 46;
+         if (!((i23 + -97 | 0) >>> 0 < 6 | i22)) {
+          break L79;
+         }
+         if (i22) {
+          if ((i18 | 0) == 0) {
+           i15 = i7;
+           i16 = i5;
+           i18 = 1;
+           break;
+          } else {
+           i21 = 46;
+           break L79;
+          }
+         } else {
+          i24 = (i21 | 0) > 57 ? i23 + -87 | 0 : i24;
+          i13 = 84;
+          break;
+         }
+        } else {
+         i13 = 84;
+        }
+       } while (0);
+       if ((i13 | 0) == 84) {
+        i13 = 0;
+        do {
+         if (!((i5 | 0) < 0 | (i5 | 0) == 0 & i7 >>> 0 < 8)) {
+          if ((i5 | 0) < 0 | (i5 | 0) == 0 & i7 >>> 0 < 14) {
+           d31 = d28 * .0625;
+           d30 = d31;
+           d14 = d14 + d31 * +(i24 | 0);
+           break;
+          }
+          if ((i24 | 0) != 0 & (i20 | 0) == 0) {
+           i20 = 1;
+           d30 = d28;
+           d14 = d14 + d28 * .5;
+          } else {
+           d30 = d28;
+          }
+         } else {
+          d30 = d28;
+          i17 = i24 + (i17 << 4) | 0;
+         }
+        } while (0);
+        i7 = _i64Add(i7 | 0, i5 | 0, 1, 0) | 0;
+        i5 = tempRet0;
+        i19 = 1;
+        d28 = d30;
+       }
+       i21 = HEAP32[i9 >> 2] | 0;
+       if (i21 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+        HEAP32[i9 >> 2] = i21 + 1;
+        i21 = HEAPU8[i21] | 0;
+        continue;
+       } else {
+        i21 = ___shgetc(i8) | 0;
+        continue;
+       }
+      }
+      if ((i19 | 0) == 0) {
+       i2 = (HEAP32[i10 >> 2] | 0) == 0;
+       if (!i2) {
+        HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+       }
+       if (!i12) {
+        if (!i2 ? (i6 = HEAP32[i9 >> 2] | 0, HEAP32[i9 >> 2] = i6 + -1, (i18 | 0) != 0) : 0) {
+         HEAP32[i9 >> 2] = i6 + -2;
+        }
+       } else {
+        ___shlim(i8, 0);
+       }
+       d31 = +(i4 | 0) * 0.0;
+       STACKTOP = i1;
+       return +d31;
+      }
+      i13 = (i18 | 0) == 0;
+      i6 = i13 ? i7 : i15;
+      i13 = i13 ? i5 : i16;
+      if ((i5 | 0) < 0 | (i5 | 0) == 0 & i7 >>> 0 < 8) {
+       do {
+        i17 = i17 << 4;
+        i7 = _i64Add(i7 | 0, i5 | 0, 1, 0) | 0;
+        i5 = tempRet0;
+       } while ((i5 | 0) < 0 | (i5 | 0) == 0 & i7 >>> 0 < 8);
+      }
+      do {
+       if ((i21 | 32 | 0) == 112) {
+        i7 = _scanexp(i8, i11) | 0;
+        i5 = tempRet0;
+        if ((i7 | 0) == 0 & (i5 | 0) == -2147483648) {
+         if (i12) {
+          ___shlim(i8, 0);
+          d31 = 0.0;
+          STACKTOP = i1;
+          return +d31;
+         } else {
+          if ((HEAP32[i10 >> 2] | 0) == 0) {
+           i7 = 0;
+           i5 = 0;
+           break;
+          }
+          HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+          i7 = 0;
+          i5 = 0;
+          break;
+         }
+        }
+       } else {
+        if ((HEAP32[i10 >> 2] | 0) == 0) {
+         i7 = 0;
+         i5 = 0;
+        } else {
+         HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+         i7 = 0;
+         i5 = 0;
+        }
+       }
+      } while (0);
+      i6 = _bitshift64Shl(i6 | 0, i13 | 0, 2) | 0;
+      i6 = _i64Add(i6 | 0, tempRet0 | 0, -32, -1) | 0;
+      i5 = _i64Add(i6 | 0, tempRet0 | 0, i7 | 0, i5 | 0) | 0;
+      i6 = tempRet0;
+      if ((i17 | 0) == 0) {
+       d31 = +(i4 | 0) * 0.0;
+       STACKTOP = i1;
+       return +d31;
+      }
+      if ((i6 | 0) > 0 | (i6 | 0) == 0 & i5 >>> 0 > (0 - i3 | 0) >>> 0) {
+       HEAP32[(___errno_location() | 0) >> 2] = 34;
+       d31 = +(i4 | 0) * 1.7976931348623157e+308 * 1.7976931348623157e+308;
+       STACKTOP = i1;
+       return +d31;
+      }
+      i29 = i3 + -106 | 0;
+      i27 = ((i29 | 0) < 0) << 31 >> 31;
+      if ((i6 | 0) < (i27 | 0) | (i6 | 0) == (i27 | 0) & i5 >>> 0 < i29 >>> 0) {
+       HEAP32[(___errno_location() | 0) >> 2] = 34;
+       d31 = +(i4 | 0) * 2.2250738585072014e-308 * 2.2250738585072014e-308;
+       STACKTOP = i1;
+       return +d31;
+      }
+      if ((i17 | 0) > -1) {
+       do {
+        i17 = i17 << 1;
+        if (!(d14 >= .5)) {
+         d28 = d14;
+        } else {
+         d28 = d14 + -1.0;
+         i17 = i17 | 1;
+        }
+        d14 = d14 + d28;
+        i5 = _i64Add(i5 | 0, i6 | 0, -1, -1) | 0;
+        i6 = tempRet0;
+       } while ((i17 | 0) > -1);
+      }
+      i3 = _i64Subtract(32, 0, i3 | 0, ((i3 | 0) < 0) << 31 >> 31 | 0) | 0;
+      i3 = _i64Add(i5 | 0, i6 | 0, i3 | 0, tempRet0 | 0) | 0;
+      i29 = tempRet0;
+      if (0 > (i29 | 0) | 0 == (i29 | 0) & i2 >>> 0 > i3 >>> 0) {
+       i2 = (i3 | 0) < 0 ? 0 : i3;
+      }
+      if ((i2 | 0) < 53) {
+       d28 = +(i4 | 0);
+       d30 = +_copysign(+(+_scalbn(1.0, 84 - i2 | 0)), +d28);
+       if ((i2 | 0) < 32 & d14 != 0.0) {
+        i29 = i17 & 1;
+        i17 = (i29 ^ 1) + i17 | 0;
+        d14 = (i29 | 0) == 0 ? 0.0 : d14;
+       }
+      } else {
+       d28 = +(i4 | 0);
+       d30 = 0.0;
+      }
+      d14 = d28 * d14 + (d30 + d28 * +(i17 >>> 0)) - d30;
+      if (!(d14 != 0.0)) {
+       HEAP32[(___errno_location() | 0) >> 2] = 34;
+      }
+      d31 = +_scalbnl(d14, i5);
+      STACKTOP = i1;
+      return +d31;
+     }
+    } while (0);
+    i7 = i3 + i2 | 0;
+    i6 = 0 - i7 | 0;
+    i20 = 0;
+    while (1) {
+     if ((i21 | 0) == 46) {
+      i13 = 139;
+      break;
+     } else if ((i21 | 0) != 48) {
+      i25 = 0;
+      i22 = 0;
+      i19 = 0;
+      break;
+     }
+     i15 = HEAP32[i9 >> 2] | 0;
+     if (i15 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+      HEAP32[i9 >> 2] = i15 + 1;
+      i21 = HEAPU8[i15] | 0;
+      i20 = 1;
+      continue;
+     } else {
+      i21 = ___shgetc(i8) | 0;
+      i20 = 1;
+      continue;
+     }
+    }
+    L168 : do {
+     if ((i13 | 0) == 139) {
+      i15 = HEAP32[i9 >> 2] | 0;
+      if (i15 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+       HEAP32[i9 >> 2] = i15 + 1;
+       i21 = HEAPU8[i15] | 0;
+      } else {
+       i21 = ___shgetc(i8) | 0;
+      }
+      if ((i21 | 0) == 48) {
+       i25 = -1;
+       i22 = -1;
+       while (1) {
+        i15 = HEAP32[i9 >> 2] | 0;
+        if (i15 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+         HEAP32[i9 >> 2] = i15 + 1;
+         i21 = HEAPU8[i15] | 0;
+        } else {
+         i21 = ___shgetc(i8) | 0;
+        }
+        if ((i21 | 0) != 48) {
+         i20 = 1;
+         i19 = 1;
+         break L168;
+        }
+        i29 = _i64Add(i25 | 0, i22 | 0, -1, -1) | 0;
+        i25 = i29;
+        i22 = tempRet0;
+       }
+      } else {
+       i25 = 0;
+       i22 = 0;
+       i19 = 1;
+      }
+     }
+    } while (0);
+    HEAP32[i5 >> 2] = 0;
+    i26 = i21 + -48 | 0;
+    i27 = (i21 | 0) == 46;
+    L182 : do {
+     if (i26 >>> 0 < 10 | i27) {
+      i15 = i5 + 496 | 0;
+      i24 = 0;
+      i23 = 0;
+      i18 = 0;
+      i17 = 0;
+      i16 = 0;
+      while (1) {
+       do {
+        if (i27) {
+         if ((i19 | 0) == 0) {
+          i25 = i24;
+          i22 = i23;
+          i19 = 1;
+         } else {
+          break L182;
+         }
+        } else {
+         i27 = _i64Add(i24 | 0, i23 | 0, 1, 0) | 0;
+         i23 = tempRet0;
+         i29 = (i21 | 0) != 48;
+         if ((i17 | 0) >= 125) {
+          if (!i29) {
+           i24 = i27;
+           break;
+          }
+          HEAP32[i15 >> 2] = HEAP32[i15 >> 2] | 1;
+          i24 = i27;
+          break;
+         }
+         i20 = i5 + (i17 << 2) | 0;
+         if ((i18 | 0) != 0) {
+          i26 = i21 + -48 + ((HEAP32[i20 >> 2] | 0) * 10 | 0) | 0;
+         }
+         HEAP32[i20 >> 2] = i26;
+         i18 = i18 + 1 | 0;
+         i21 = (i18 | 0) == 9;
+         i24 = i27;
+         i20 = 1;
+         i18 = i21 ? 0 : i18;
+         i17 = (i21 & 1) + i17 | 0;
+         i16 = i29 ? i27 : i16;
+        }
+       } while (0);
+       i21 = HEAP32[i9 >> 2] | 0;
+       if (i21 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+        HEAP32[i9 >> 2] = i21 + 1;
+        i21 = HEAPU8[i21] | 0;
+       } else {
+        i21 = ___shgetc(i8) | 0;
+       }
+       i26 = i21 + -48 | 0;
+       i27 = (i21 | 0) == 46;
+       if (!(i26 >>> 0 < 10 | i27)) {
+        i13 = 162;
+        break;
+       }
+      }
+     } else {
+      i24 = 0;
+      i23 = 0;
+      i18 = 0;
+      i17 = 0;
+      i16 = 0;
+      i13 = 162;
+     }
+    } while (0);
+    if ((i13 | 0) == 162) {
+     i13 = (i19 | 0) == 0;
+     i25 = i13 ? i24 : i25;
+     i22 = i13 ? i23 : i22;
+    }
+    i13 = (i20 | 0) != 0;
+    if (i13 ? (i21 | 32 | 0) == 101 : 0) {
+     i15 = _scanexp(i8, i11) | 0;
+     i11 = tempRet0;
+     do {
+      if ((i15 | 0) == 0 & (i11 | 0) == -2147483648) {
+       if (i12) {
+        ___shlim(i8, 0);
+        d31 = 0.0;
+        STACKTOP = i1;
+        return +d31;
+       } else {
+        if ((HEAP32[i10 >> 2] | 0) == 0) {
+         i15 = 0;
+         i11 = 0;
+         break;
+        }
+        HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+        i15 = 0;
+        i11 = 0;
+        break;
+       }
+      }
+     } while (0);
+     i9 = _i64Add(i15 | 0, i11 | 0, i25 | 0, i22 | 0) | 0;
+     i22 = tempRet0;
+    } else {
+     if ((i21 | 0) > -1 ? (HEAP32[i10 >> 2] | 0) != 0 : 0) {
+      HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+      i9 = i25;
+     } else {
+      i9 = i25;
+     }
+    }
+    if (!i13) {
+     HEAP32[(___errno_location() | 0) >> 2] = 22;
+     ___shlim(i8, 0);
+     d31 = 0.0;
+     STACKTOP = i1;
+     return +d31;
+    }
+    i8 = HEAP32[i5 >> 2] | 0;
+    if ((i8 | 0) == 0) {
+     d31 = +(i4 | 0) * 0.0;
+     STACKTOP = i1;
+     return +d31;
+    }
+    do {
+     if ((i9 | 0) == (i24 | 0) & (i22 | 0) == (i23 | 0) & ((i23 | 0) < 0 | (i23 | 0) == 0 & i24 >>> 0 < 10)) {
+      if (!(i2 >>> 0 > 30) ? (i8 >>> i2 | 0) != 0 : 0) {
+       break;
+      }
+      d31 = +(i4 | 0) * +(i8 >>> 0);
+      STACKTOP = i1;
+      return +d31;
+     }
+    } while (0);
+    i29 = (i3 | 0) / -2 | 0;
+    i27 = ((i29 | 0) < 0) << 31 >> 31;
+    if ((i22 | 0) > (i27 | 0) | (i22 | 0) == (i27 | 0) & i9 >>> 0 > i29 >>> 0) {
+     HEAP32[(___errno_location() | 0) >> 2] = 34;
+     d31 = +(i4 | 0) * 1.7976931348623157e+308 * 1.7976931348623157e+308;
+     STACKTOP = i1;
+     return +d31;
+    }
+    i29 = i3 + -106 | 0;
+    i27 = ((i29 | 0) < 0) << 31 >> 31;
+    if ((i22 | 0) < (i27 | 0) | (i22 | 0) == (i27 | 0) & i9 >>> 0 < i29 >>> 0) {
+     HEAP32[(___errno_location() | 0) >> 2] = 34;
+     d31 = +(i4 | 0) * 2.2250738585072014e-308 * 2.2250738585072014e-308;
+     STACKTOP = i1;
+     return +d31;
+    }
+    if ((i18 | 0) != 0) {
+     if ((i18 | 0) < 9) {
+      i8 = i5 + (i17 << 2) | 0;
+      i10 = HEAP32[i8 >> 2] | 0;
+      do {
+       i10 = i10 * 10 | 0;
+       i18 = i18 + 1 | 0;
+      } while ((i18 | 0) != 9);
+      HEAP32[i8 >> 2] = i10;
+     }
+     i17 = i17 + 1 | 0;
+    }
+    do {
+     if ((i16 | 0) < 9 ? (i16 | 0) <= (i9 | 0) & (i9 | 0) < 18 : 0) {
+      if ((i9 | 0) == 9) {
+       d31 = +(i4 | 0) * +((HEAP32[i5 >> 2] | 0) >>> 0);
+       STACKTOP = i1;
+       return +d31;
+      }
+      if ((i9 | 0) < 9) {
+       d31 = +(i4 | 0) * +((HEAP32[i5 >> 2] | 0) >>> 0) / +(HEAP32[13440 + (8 - i9 << 2) >> 2] | 0);
+       STACKTOP = i1;
+       return +d31;
+      }
+      i10 = i2 + 27 + (Math_imul(i9, -3) | 0) | 0;
+      i8 = HEAP32[i5 >> 2] | 0;
+      if ((i10 | 0) <= 30 ? (i8 >>> i10 | 0) != 0 : 0) {
+       break;
+      }
+      d31 = +(i4 | 0) * +(i8 >>> 0) * +(HEAP32[13440 + (i9 + -10 << 2) >> 2] | 0);
+      STACKTOP = i1;
+      return +d31;
+     }
+    } while (0);
+    i8 = (i9 | 0) % 9 | 0;
+    if ((i8 | 0) == 0) {
+     i8 = 0;
+     i10 = 0;
+    } else {
+     i11 = (i9 | 0) > -1 ? i8 : i8 + 9 | 0;
+     i12 = HEAP32[13440 + (8 - i11 << 2) >> 2] | 0;
+     if ((i17 | 0) != 0) {
+      i10 = 1e9 / (i12 | 0) | 0;
+      i8 = 0;
+      i16 = 0;
+      i15 = 0;
+      while (1) {
+       i27 = i5 + (i15 << 2) | 0;
+       i13 = HEAP32[i27 >> 2] | 0;
+       i29 = ((i13 >>> 0) / (i12 >>> 0) | 0) + i16 | 0;
+       HEAP32[i27 >> 2] = i29;
+       i16 = Math_imul((i13 >>> 0) % (i12 >>> 0) | 0, i10) | 0;
+       i13 = i15 + 1 | 0;
+       if ((i15 | 0) == (i8 | 0) & (i29 | 0) == 0) {
+        i8 = i13 & 127;
+        i9 = i9 + -9 | 0;
+       }
+       if ((i13 | 0) == (i17 | 0)) {
+        break;
+       } else {
+        i15 = i13;
+       }
+      }
+      if ((i16 | 0) != 0) {
+       HEAP32[i5 + (i17 << 2) >> 2] = i16;
+       i17 = i17 + 1 | 0;
+      }
+     } else {
+      i8 = 0;
+      i17 = 0;
+     }
+     i10 = 0;
+     i9 = 9 - i11 + i9 | 0;
+    }
+    L280 : while (1) {
+     i11 = i5 + (i8 << 2) | 0;
+     if ((i9 | 0) < 18) {
+      do {
+       i13 = 0;
+       i11 = i17 + 127 | 0;
+       while (1) {
+        i11 = i11 & 127;
+        i12 = i5 + (i11 << 2) | 0;
+        i15 = _bitshift64Shl(HEAP32[i12 >> 2] | 0, 0, 29) | 0;
+        i15 = _i64Add(i15 | 0, tempRet0 | 0, i13 | 0, 0) | 0;
+        i13 = tempRet0;
+        if (i13 >>> 0 > 0 | (i13 | 0) == 0 & i15 >>> 0 > 1e9) {
+         i29 = ___udivdi3(i15 | 0, i13 | 0, 1e9, 0) | 0;
+         i15 = ___uremdi3(i15 | 0, i13 | 0, 1e9, 0) | 0;
+         i13 = i29;
+        } else {
+         i13 = 0;
+        }
+        HEAP32[i12 >> 2] = i15;
+        i12 = (i11 | 0) == (i8 | 0);
+        if (!((i11 | 0) != (i17 + 127 & 127 | 0) | i12)) {
+         i17 = (i15 | 0) == 0 ? i11 : i17;
+        }
+        if (i12) {
+         break;
+        } else {
+         i11 = i11 + -1 | 0;
+        }
+       }
+       i10 = i10 + -29 | 0;
+      } while ((i13 | 0) == 0);
+     } else {
+      if ((i9 | 0) != 18) {
+       break;
+      }
+      do {
+       if (!((HEAP32[i11 >> 2] | 0) >>> 0 < 9007199)) {
+        i9 = 18;
+        break L280;
+       }
+       i13 = 0;
+       i12 = i17 + 127 | 0;
+       while (1) {
+        i12 = i12 & 127;
+        i15 = i5 + (i12 << 2) | 0;
+        i16 = _bitshift64Shl(HEAP32[i15 >> 2] | 0, 0, 29) | 0;
+        i16 = _i64Add(i16 | 0, tempRet0 | 0, i13 | 0, 0) | 0;
+        i13 = tempRet0;
+        if (i13 >>> 0 > 0 | (i13 | 0) == 0 & i16 >>> 0 > 1e9) {
+         i29 = ___udivdi3(i16 | 0, i13 | 0, 1e9, 0) | 0;
+         i16 = ___uremdi3(i16 | 0, i13 | 0, 1e9, 0) | 0;
+         i13 = i29;
+        } else {
+         i13 = 0;
+        }
+        HEAP32[i15 >> 2] = i16;
+        i15 = (i12 | 0) == (i8 | 0);
+        if (!((i12 | 0) != (i17 + 127 & 127 | 0) | i15)) {
+         i17 = (i16 | 0) == 0 ? i12 : i17;
+        }
+        if (i15) {
+         break;
+        } else {
+         i12 = i12 + -1 | 0;
+        }
+       }
+       i10 = i10 + -29 | 0;
+      } while ((i13 | 0) == 0);
+     }
+     i8 = i8 + 127 & 127;
+     if ((i8 | 0) == (i17 | 0)) {
+      i29 = i17 + 127 & 127;
+      i17 = i5 + ((i17 + 126 & 127) << 2) | 0;
+      HEAP32[i17 >> 2] = HEAP32[i17 >> 2] | HEAP32[i5 + (i29 << 2) >> 2];
+      i17 = i29;
+     }
+     HEAP32[i5 + (i8 << 2) >> 2] = i13;
+     i9 = i9 + 9 | 0;
+    }
+    L311 : while (1) {
+     i11 = i17 + 1 & 127;
+     i12 = i5 + ((i17 + 127 & 127) << 2) | 0;
+     while (1) {
+      i15 = (i9 | 0) == 18;
+      i13 = (i9 | 0) > 27 ? 9 : 1;
+      while (1) {
+       i16 = 0;
+       while (1) {
+        i18 = i16 + i8 & 127;
+        if ((i18 | 0) == (i17 | 0)) {
+         i16 = 2;
+         break;
+        }
+        i18 = HEAP32[i5 + (i18 << 2) >> 2] | 0;
+        i19 = HEAP32[13432 + (i16 << 2) >> 2] | 0;
+        if (i18 >>> 0 < i19 >>> 0) {
+         i16 = 2;
+         break;
+        }
+        i20 = i16 + 1 | 0;
+        if (i18 >>> 0 > i19 >>> 0) {
+         break;
+        }
+        if ((i20 | 0) < 2) {
+         i16 = i20;
+        } else {
+         i16 = i20;
+         break;
+        }
+       }
+       if ((i16 | 0) == 2 & i15) {
+        break L311;
+       }
+       i10 = i13 + i10 | 0;
+       if ((i8 | 0) == (i17 | 0)) {
+        i8 = i17;
+       } else {
+        break;
+       }
+      }
+      i15 = (1 << i13) + -1 | 0;
+      i19 = 1e9 >>> i13;
+      i18 = i8;
+      i16 = 0;
+      do {
+       i27 = i5 + (i8 << 2) | 0;
+       i29 = HEAP32[i27 >> 2] | 0;
+       i20 = (i29 >>> i13) + i16 | 0;
+       HEAP32[i27 >> 2] = i20;
+       i16 = Math_imul(i29 & i15, i19) | 0;
+       i20 = (i8 | 0) == (i18 | 0) & (i20 | 0) == 0;
+       i8 = i8 + 1 & 127;
+       i9 = i20 ? i9 + -9 | 0 : i9;
+       i18 = i20 ? i8 : i18;
+      } while ((i8 | 0) != (i17 | 0));
+      if ((i16 | 0) == 0) {
+       i8 = i18;
+       continue;
+      }
+      if ((i11 | 0) != (i18 | 0)) {
+       break;
+      }
+      HEAP32[i12 >> 2] = HEAP32[i12 >> 2] | 1;
+      i8 = i18;
+     }
+     HEAP32[i5 + (i17 << 2) >> 2] = i16;
+     i8 = i18;
+     i17 = i11;
+    }
+    i9 = i8 & 127;
+    if ((i9 | 0) == (i17 | 0)) {
+     HEAP32[i5 + (i11 + -1 << 2) >> 2] = 0;
+     i17 = i11;
+    }
+    d28 = +((HEAP32[i5 + (i9 << 2) >> 2] | 0) >>> 0);
+    i9 = i8 + 1 & 127;
+    if ((i9 | 0) == (i17 | 0)) {
+     i17 = i17 + 1 & 127;
+     HEAP32[i5 + (i17 + -1 << 2) >> 2] = 0;
+    }
+    d14 = +(i4 | 0);
+    d30 = d14 * (d28 * 1.0e9 + +((HEAP32[i5 + (i9 << 2) >> 2] | 0) >>> 0));
+    i4 = i10 + 53 | 0;
+    i3 = i4 - i3 | 0;
+    if ((i3 | 0) < (i2 | 0)) {
+     i2 = (i3 | 0) < 0 ? 0 : i3;
+     i9 = 1;
+    } else {
+     i9 = 0;
+    }
+    if ((i2 | 0) < 53) {
+     d33 = +_copysign(+(+_scalbn(1.0, 105 - i2 | 0)), +d30);
+     d32 = +_fmod(+d30, +(+_scalbn(1.0, 53 - i2 | 0)));
+     d28 = d33;
+     d31 = d32;
+     d30 = d33 + (d30 - d32);
+    } else {
+     d28 = 0.0;
+     d31 = 0.0;
+    }
+    i11 = i8 + 2 & 127;
+    if ((i11 | 0) != (i17 | 0)) {
+     i5 = HEAP32[i5 + (i11 << 2) >> 2] | 0;
+     do {
+      if (!(i5 >>> 0 < 5e8)) {
+       if (i5 >>> 0 > 5e8) {
+        d31 = d14 * .75 + d31;
+        break;
+       }
+       if ((i8 + 3 & 127 | 0) == (i17 | 0)) {
+        d31 = d14 * .5 + d31;
+        break;
+       } else {
+        d31 = d14 * .75 + d31;
+        break;
+       }
+      } else {
+       if ((i5 | 0) == 0 ? (i8 + 3 & 127 | 0) == (i17 | 0) : 0) {
+        break;
+       }
+       d31 = d14 * .25 + d31;
+      }
+     } while (0);
+     if ((53 - i2 | 0) > 1 ? !(+_fmod(+d31, 1.0) != 0.0) : 0) {
+      d31 = d31 + 1.0;
+     }
+    }
+    d14 = d30 + d31 - d28;
+    do {
+     if ((i4 & 2147483647 | 0) > (-2 - i7 | 0)) {
+      if (+Math_abs(+d14) >= 9007199254740992.0) {
+       i9 = (i9 | 0) != 0 & (i2 | 0) == (i3 | 0) ? 0 : i9;
+       i10 = i10 + 1 | 0;
+       d14 = d14 * .5;
+      }
+      if ((i10 + 50 | 0) <= (i6 | 0) ? !((i9 | 0) != 0 & d31 != 0.0) : 0) {
+       break;
+      }
+      HEAP32[(___errno_location() | 0) >> 2] = 34;
+     }
+    } while (0);
+    d33 = +_scalbnl(d14, i10);
+    STACKTOP = i1;
+    return +d33;
+   } else if ((i7 | 0) == 3) {
+    i2 = HEAP32[i9 >> 2] | 0;
+    if (i2 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+     HEAP32[i9 >> 2] = i2 + 1;
+     i2 = HEAPU8[i2] | 0;
+    } else {
+     i2 = ___shgetc(i8) | 0;
+    }
+    if ((i2 | 0) == 40) {
+     i2 = 1;
+    } else {
+     if ((HEAP32[i10 >> 2] | 0) == 0) {
+      d33 = nan;
+      STACKTOP = i1;
+      return +d33;
+     }
+     HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+     d33 = nan;
+     STACKTOP = i1;
+     return +d33;
+    }
+    while (1) {
+     i3 = HEAP32[i9 >> 2] | 0;
+     if (i3 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0) {
+      HEAP32[i9 >> 2] = i3 + 1;
+      i3 = HEAPU8[i3] | 0;
+     } else {
+      i3 = ___shgetc(i8) | 0;
+     }
+     if (!((i3 + -48 | 0) >>> 0 < 10 | (i3 + -65 | 0) >>> 0 < 26) ? !((i3 + -97 | 0) >>> 0 < 26 | (i3 | 0) == 95) : 0) {
+      break;
+     }
+     i2 = i2 + 1 | 0;
+    }
+    if ((i3 | 0) == 41) {
+     d33 = nan;
+     STACKTOP = i1;
+     return +d33;
+    }
+    i3 = (HEAP32[i10 >> 2] | 0) == 0;
+    if (!i3) {
+     HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+    }
+    if (i12) {
+     HEAP32[(___errno_location() | 0) >> 2] = 22;
+     ___shlim(i8, 0);
+     d33 = 0.0;
+     STACKTOP = i1;
+     return +d33;
+    }
+    if ((i2 | 0) == 0 | i3) {
+     d33 = nan;
+     STACKTOP = i1;
+     return +d33;
+    }
+    while (1) {
+     i2 = i2 + -1 | 0;
+     HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+     if ((i2 | 0) == 0) {
+      d14 = nan;
+      break;
+     }
+    }
+    STACKTOP = i1;
+    return +d14;
+   } else {
+    if ((HEAP32[i10 >> 2] | 0) != 0) {
+     HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+    }
+    HEAP32[(___errno_location() | 0) >> 2] = 22;
+    ___shlim(i8, 0);
+    d33 = 0.0;
+    STACKTOP = i1;
+    return +d33;
+   }
+  }
+ } while (0);
+ if ((i13 | 0) == 23) {
+  i2 = (HEAP32[i10 >> 2] | 0) == 0;
+  if (!i2) {
+   HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+  }
+  if (!(i7 >>> 0 < 4 | (i11 | 0) == 0 | i2)) {
+   do {
+    HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + -1;
+    i7 = i7 + -1 | 0;
+   } while (i7 >>> 0 > 3);
+  }
+ }
+ d33 = +(i4 | 0) * inf;
+ STACKTOP = i1;
+ return +d33;
+}
+function _statement(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 160 | 0;
+ i8 = i2 + 120 | 0;
+ i24 = i2 + 96 | 0;
+ i15 = i2 + 72 | 0;
+ i25 = i2 + 48 | 0;
+ i20 = i2 + 24 | 0;
+ i21 = i2;
+ i19 = i4 + 4 | 0;
+ i6 = HEAP32[i19 >> 2] | 0;
+ i3 = i4 + 48 | 0;
+ i9 = HEAP32[i3 >> 2] | 0;
+ i1 = i4 + 52 | 0;
+ i26 = (HEAP32[i1 >> 2] | 0) + 38 | 0;
+ i27 = (HEAP16[i26 >> 1] | 0) + 1 << 16 >> 16;
+ HEAP16[i26 >> 1] = i27;
+ if ((i27 & 65535) > 200) {
+  i27 = i9 + 12 | 0;
+  i26 = HEAP32[(HEAP32[i27 >> 2] | 0) + 52 >> 2] | 0;
+  i5 = HEAP32[(HEAP32[i9 >> 2] | 0) + 64 >> 2] | 0;
+  if ((i5 | 0) == 0) {
+   i29 = 6552;
+   HEAP32[i8 >> 2] = 6360;
+   i28 = i8 + 4 | 0;
+   HEAP32[i28 >> 2] = 200;
+   i28 = i8 + 8 | 0;
+   HEAP32[i28 >> 2] = i29;
+   i28 = _luaO_pushfstring(i26, 6592, i8) | 0;
+   i29 = HEAP32[i27 >> 2] | 0;
+   _luaX_syntaxerror(i29, i28);
+  }
+  HEAP32[i8 >> 2] = i5;
+  i28 = _luaO_pushfstring(i26, 6568, i8) | 0;
+  HEAP32[i8 >> 2] = 6360;
+  i29 = i8 + 4 | 0;
+  HEAP32[i29 >> 2] = 200;
+  i29 = i8 + 8 | 0;
+  HEAP32[i29 >> 2] = i28;
+  i29 = _luaO_pushfstring(i26, 6592, i8) | 0;
+  i28 = HEAP32[i27 >> 2] | 0;
+  _luaX_syntaxerror(i28, i29);
+ }
+ i5 = i4 + 16 | 0;
+ L8 : do {
+  switch (HEAP32[i5 >> 2] | 0) {
+  case 59:
+   {
+    _luaX_next(i4);
+    break;
+   }
+  case 267:
+   {
+    HEAP32[i21 >> 2] = -1;
+    _test_then_block(i4, i21);
+    while (1) {
+     i8 = HEAP32[i5 >> 2] | 0;
+     if ((i8 | 0) == 260) {
+      i7 = 10;
+      break;
+     } else if ((i8 | 0) != 261) {
+      break;
+     }
+     _test_then_block(i4, i21);
+    }
+    if ((i7 | 0) == 10) {
+     _luaX_next(i4);
+     i7 = HEAP32[i3 >> 2] | 0;
+     HEAP8[i20 + 10 | 0] = 0;
+     HEAP8[i20 + 8 | 0] = HEAP8[i7 + 46 | 0] | 0;
+     i29 = HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 64 >> 2] | 0;
+     HEAP16[i20 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+     HEAP16[i20 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+     HEAP8[i20 + 9 | 0] = 0;
+     i29 = i7 + 16 | 0;
+     HEAP32[i20 >> 2] = HEAP32[i29 >> 2];
+     HEAP32[i29 >> 2] = i20;
+     L16 : do {
+      i8 = HEAP32[i5 >> 2] | 0;
+      switch (i8 | 0) {
+      case 277:
+      case 286:
+      case 262:
+      case 261:
+      case 260:
+       {
+        break L16;
+       }
+      default:
+       {}
+      }
+      _statement(i4);
+     } while ((i8 | 0) != 274);
+     _leaveblock(i7);
+    }
+    _check_match(i4, 262, 267, i6);
+    _luaK_patchtohere(i9, HEAP32[i21 >> 2] | 0);
+    break;
+   }
+  case 259:
+   {
+    _luaX_next(i4);
+    i7 = HEAP32[i3 >> 2] | 0;
+    HEAP8[i20 + 10 | 0] = 0;
+    HEAP8[i20 + 8 | 0] = HEAP8[i7 + 46 | 0] | 0;
+    i29 = HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i20 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i20 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i20 + 9 | 0] = 0;
+    i29 = i7 + 16 | 0;
+    HEAP32[i20 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i20;
+    L22 : do {
+     i8 = HEAP32[i5 >> 2] | 0;
+     switch (i8 | 0) {
+     case 277:
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       break L22;
+      }
+     default:
+      {}
+     }
+     _statement(i4);
+    } while ((i8 | 0) != 274);
+    _leaveblock(i7);
+    _check_match(i4, 262, 259, i6);
+    break;
+   }
+  case 269:
+   {
+    _luaX_next(i4);
+    i6 = HEAP32[i5 >> 2] | 0;
+    if ((i6 | 0) == 265) {
+     _luaX_next(i4);
+     i7 = HEAP32[i3 >> 2] | 0;
+     if ((HEAP32[i5 >> 2] | 0) == 288) {
+      i29 = HEAP32[i4 + 24 >> 2] | 0;
+      _luaX_next(i4);
+      _new_localvar(i4, i29);
+      i29 = HEAP32[i3 >> 2] | 0;
+      i27 = i29 + 46 | 0;
+      i28 = (HEAPU8[i27] | 0) + 1 | 0;
+      HEAP8[i27] = i28;
+      HEAP32[(HEAP32[(HEAP32[i29 >> 2] | 0) + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i29 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((i28 & 255) + -1 + (HEAP32[i29 + 40 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i29 + 20 >> 2];
+      _body(i4, i25, 0, HEAP32[i19 >> 2] | 0);
+      HEAP32[(HEAP32[(HEAP32[i7 >> 2] | 0) + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((HEAP32[i7 + 40 >> 2] | 0) + (HEAP32[i25 + 8 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i7 + 20 >> 2];
+      break L8;
+     } else {
+      _error_expected(i4, 288);
+     }
+    }
+    if ((i6 | 0) != 288) {
+     _error_expected(i4, 288);
+    }
+    i7 = i4 + 24 | 0;
+    i6 = 1;
+    while (1) {
+     i8 = HEAP32[i7 >> 2] | 0;
+     _luaX_next(i4);
+     _new_localvar(i4, i8);
+     i8 = HEAP32[i5 >> 2] | 0;
+     if ((i8 | 0) == 61) {
+      i7 = 81;
+      break;
+     } else if ((i8 | 0) != 44) {
+      i7 = 83;
+      break;
+     }
+     _luaX_next(i4);
+     if ((HEAP32[i5 >> 2] | 0) == 288) {
+      i6 = i6 + 1 | 0;
+     } else {
+      i7 = 78;
+      break;
+     }
+    }
+    do {
+     if ((i7 | 0) == 78) {
+      _error_expected(i4, 288);
+     } else if ((i7 | 0) == 81) {
+      _luaX_next(i4);
+      _subexpr(i4, i15, 0) | 0;
+      if ((HEAP32[i5 >> 2] | 0) == 44) {
+       i8 = 1;
+       do {
+        _luaX_next(i4);
+        _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i15);
+        _subexpr(i4, i15, 0) | 0;
+        i8 = i8 + 1 | 0;
+       } while ((HEAP32[i5 >> 2] | 0) == 44);
+      } else {
+       i8 = 1;
+      }
+      i5 = HEAP32[i15 >> 2] | 0;
+      i4 = HEAP32[i3 >> 2] | 0;
+      i8 = i6 - i8 | 0;
+      if ((i5 | 0) == 0) {
+       i17 = i8;
+       i18 = i4;
+       i7 = 88;
+       break;
+      } else if (!((i5 | 0) == 13 | (i5 | 0) == 12)) {
+       _luaK_exp2nextreg(i4, i15);
+       i17 = i8;
+       i18 = i4;
+       i7 = 88;
+       break;
+      }
+      i5 = i8 + 1 | 0;
+      i5 = (i5 | 0) < 0 ? 0 : i5;
+      _luaK_setreturns(i4, i15, i5);
+      if ((i5 | 0) > 1) {
+       _luaK_reserveregs(i4, i5 + -1 | 0);
+      }
+     } else if ((i7 | 0) == 83) {
+      HEAP32[i15 >> 2] = 0;
+      i17 = i6;
+      i18 = HEAP32[i3 >> 2] | 0;
+      i7 = 88;
+     }
+    } while (0);
+    if ((i7 | 0) == 88 ? (i17 | 0) > 0 : 0) {
+     i29 = HEAPU8[i18 + 48 | 0] | 0;
+     _luaK_reserveregs(i18, i17);
+     _luaK_nil(i18, i29, i17);
+    }
+    i5 = HEAP32[i3 >> 2] | 0;
+    i4 = i5 + 46 | 0;
+    i7 = (HEAPU8[i4] | 0) + i6 | 0;
+    HEAP8[i4] = i7;
+    if ((i6 | 0) != 0 ? (i11 = i5 + 20 | 0, i14 = i5 + 40 | 0, i12 = HEAP32[(HEAP32[i5 >> 2] | 0) + 24 >> 2] | 0, i13 = HEAP32[HEAP32[(HEAP32[i5 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0, HEAP32[i12 + ((HEAP16[i13 + ((i7 & 255) - i6 + (HEAP32[i14 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i11 >> 2], i16 = i6 + -1 | 0, (i16 | 0) != 0) : 0) {
+     do {
+      HEAP32[i12 + ((HEAP16[i13 + ((HEAPU8[i4] | 0) - i16 + (HEAP32[i14 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i11 >> 2];
+      i16 = i16 + -1 | 0;
+     } while ((i16 | 0) != 0);
+    }
+    break;
+   }
+  case 264:
+   {
+    HEAP8[i24 + 10 | 0] = 1;
+    HEAP8[i24 + 8 | 0] = HEAP8[i9 + 46 | 0] | 0;
+    i29 = HEAP32[(HEAP32[i9 + 12 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i24 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i24 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i24 + 9 | 0] = 0;
+    i29 = i9 + 16 | 0;
+    HEAP32[i24 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i24;
+    _luaX_next(i4);
+    if ((HEAP32[i5 >> 2] | 0) != 288) {
+     _error_expected(i4, 288);
+    }
+    i14 = i4 + 24 | 0;
+    i13 = HEAP32[i14 >> 2] | 0;
+    _luaX_next(i4);
+    i11 = HEAP32[i5 >> 2] | 0;
+    if ((i11 | 0) == 268 | (i11 | 0) == 44) {
+     i12 = HEAP32[i3 >> 2] | 0;
+     i11 = HEAPU8[i12 + 48 | 0] | 0;
+     _new_localvar(i4, _luaX_newstring(i4, 6744, 15) | 0);
+     _new_localvar(i4, _luaX_newstring(i4, 6760, 11) | 0);
+     _new_localvar(i4, _luaX_newstring(i4, 6776, 13) | 0);
+     _new_localvar(i4, i13);
+     i13 = HEAP32[i5 >> 2] | 0;
+     do {
+      if ((i13 | 0) == 44) {
+       i15 = 4;
+       while (1) {
+        _luaX_next(i4);
+        if ((HEAP32[i5 >> 2] | 0) != 288) {
+         i7 = 40;
+         break;
+        }
+        i13 = HEAP32[i14 >> 2] | 0;
+        _luaX_next(i4);
+        _new_localvar(i4, i13);
+        i13 = HEAP32[i5 >> 2] | 0;
+        if ((i13 | 0) == 44) {
+         i15 = i15 + 1 | 0;
+        } else {
+         i7 = 42;
+         break;
+        }
+       }
+       if ((i7 | 0) == 40) {
+        _error_expected(i4, 288);
+       } else if ((i7 | 0) == 42) {
+        i22 = i13;
+        i10 = i15 + -2 | 0;
+        break;
+       }
+      } else {
+       i22 = i13;
+       i10 = 1;
+      }
+     } while (0);
+     if ((i22 | 0) != 268) {
+      _error_expected(i4, 268);
+     }
+     _luaX_next(i4);
+     i13 = HEAP32[i19 >> 2] | 0;
+     _subexpr(i4, i8, 0) | 0;
+     if ((HEAP32[i5 >> 2] | 0) == 44) {
+      i14 = 1;
+      do {
+       _luaX_next(i4);
+       _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i8);
+       _subexpr(i4, i8, 0) | 0;
+       i14 = i14 + 1 | 0;
+      } while ((HEAP32[i5 >> 2] | 0) == 44);
+     } else {
+      i14 = 1;
+     }
+     i5 = HEAP32[i3 >> 2] | 0;
+     i14 = 3 - i14 | 0;
+     i15 = HEAP32[i8 >> 2] | 0;
+     if ((i15 | 0) == 0) {
+      i7 = 51;
+     } else if ((i15 | 0) == 13 | (i15 | 0) == 12) {
+      i15 = i14 + 1 | 0;
+      i15 = (i15 | 0) < 0 ? 0 : i15;
+      _luaK_setreturns(i5, i8, i15);
+      if ((i15 | 0) > 1) {
+       _luaK_reserveregs(i5, i15 + -1 | 0);
+      }
+     } else {
+      _luaK_exp2nextreg(i5, i8);
+      i7 = 51;
+     }
+     if ((i7 | 0) == 51 ? (i14 | 0) > 0 : 0) {
+      i29 = HEAPU8[i5 + 48 | 0] | 0;
+      _luaK_reserveregs(i5, i14);
+      _luaK_nil(i5, i29, i14);
+     }
+     _luaK_checkstack(i12, 3);
+     _forbody(i4, i11, i13, i10, 0);
+    } else if ((i11 | 0) == 61) {
+     i11 = HEAP32[i3 >> 2] | 0;
+     i7 = i11 + 48 | 0;
+     i10 = HEAPU8[i7] | 0;
+     _new_localvar(i4, _luaX_newstring(i4, 6792, 11) | 0);
+     _new_localvar(i4, _luaX_newstring(i4, 6808, 11) | 0);
+     _new_localvar(i4, _luaX_newstring(i4, 6824, 10) | 0);
+     _new_localvar(i4, i13);
+     if ((HEAP32[i5 >> 2] | 0) != 61) {
+      _error_expected(i4, 61);
+     }
+     _luaX_next(i4);
+     _subexpr(i4, i8, 0) | 0;
+     _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i8);
+     if ((HEAP32[i5 >> 2] | 0) != 44) {
+      _error_expected(i4, 44);
+     }
+     _luaX_next(i4);
+     _subexpr(i4, i8, 0) | 0;
+     _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i8);
+     if ((HEAP32[i5 >> 2] | 0) == 44) {
+      _luaX_next(i4);
+      _subexpr(i4, i8, 0) | 0;
+      _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i8);
+     } else {
+      i29 = HEAPU8[i7] | 0;
+      _luaK_codek(i11, i29, _luaK_numberK(i11, 1.0) | 0) | 0;
+      _luaK_reserveregs(i11, 1);
+     }
+     _forbody(i4, i10, i6, 1, 1);
+    } else {
+     _luaX_syntaxerror(i4, 6720);
+    }
+    _check_match(i4, 262, 264, i6);
+    _leaveblock(i9);
+    break;
+   }
+  case 265:
+   {
+    _luaX_next(i4);
+    if ((HEAP32[i5 >> 2] | 0) != 288) {
+     _error_expected(i4, 288);
+    }
+    i8 = HEAP32[i4 + 24 >> 2] | 0;
+    _luaX_next(i4);
+    i9 = HEAP32[i3 >> 2] | 0;
+    if ((_singlevaraux(i9, i8, i20, 1) | 0) == 0) {
+     _singlevaraux(i9, HEAP32[i4 + 72 >> 2] | 0, i20, 1) | 0;
+     i29 = _luaK_stringK(HEAP32[i3 >> 2] | 0, i8) | 0;
+     HEAP32[i25 + 16 >> 2] = -1;
+     HEAP32[i25 + 20 >> 2] = -1;
+     HEAP32[i25 >> 2] = 4;
+     HEAP32[i25 + 8 >> 2] = i29;
+     _luaK_indexed(i9, i20, i25);
+    }
+    while (1) {
+     i8 = HEAP32[i5 >> 2] | 0;
+     if ((i8 | 0) == 58) {
+      i7 = 70;
+      break;
+     } else if ((i8 | 0) != 46) {
+      i5 = 0;
+      break;
+     }
+     _fieldsel(i4, i20);
+    }
+    if ((i7 | 0) == 70) {
+     _fieldsel(i4, i20);
+     i5 = 1;
+    }
+    _body(i4, i21, i5, i6);
+    _luaK_storevar(HEAP32[i3 >> 2] | 0, i20, i21);
+    _luaK_fixline(HEAP32[i3 >> 2] | 0, i6);
+    break;
+   }
+  case 278:
+   {
+    _luaX_next(i4);
+    i7 = _luaK_getlabel(i9) | 0;
+    _subexpr(i4, i20, 0) | 0;
+    if ((HEAP32[i20 >> 2] | 0) == 1) {
+     HEAP32[i20 >> 2] = 3;
+    }
+    _luaK_goiftrue(HEAP32[i3 >> 2] | 0, i20);
+    i8 = HEAP32[i20 + 20 >> 2] | 0;
+    HEAP8[i21 + 10 | 0] = 1;
+    HEAP8[i21 + 8 | 0] = HEAP8[i9 + 46 | 0] | 0;
+    i29 = HEAP32[(HEAP32[i9 + 12 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i21 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i21 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i21 + 9 | 0] = 0;
+    i29 = i9 + 16 | 0;
+    HEAP32[i21 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i21;
+    if ((HEAP32[i5 >> 2] | 0) != 259) {
+     _error_expected(i4, 259);
+    }
+    _luaX_next(i4);
+    i10 = HEAP32[i3 >> 2] | 0;
+    HEAP8[i20 + 10 | 0] = 0;
+    HEAP8[i20 + 8 | 0] = HEAP8[i10 + 46 | 0] | 0;
+    i29 = HEAP32[(HEAP32[i10 + 12 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i20 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i20 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i20 + 9 | 0] = 0;
+    i29 = i10 + 16 | 0;
+    HEAP32[i20 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i20;
+    L119 : do {
+     i11 = HEAP32[i5 >> 2] | 0;
+     switch (i11 | 0) {
+     case 277:
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       break L119;
+      }
+     default:
+      {}
+     }
+     _statement(i4);
+    } while ((i11 | 0) != 274);
+    _leaveblock(i10);
+    _luaK_patchlist(i9, _luaK_jump(i9) | 0, i7);
+    _check_match(i4, 262, 278, i6);
+    _leaveblock(i9);
+    _luaK_patchtohere(i9, i8);
+    break;
+   }
+  case 273:
+   {
+    i7 = _luaK_getlabel(i9) | 0;
+    HEAP8[i24 + 10 | 0] = 1;
+    i28 = i9 + 46 | 0;
+    HEAP8[i24 + 8 | 0] = HEAP8[i28] | 0;
+    i11 = i9 + 12 | 0;
+    i29 = HEAP32[(HEAP32[i11 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i24 + 4 >> 1] = HEAP32[i29 + 28 >> 2];
+    HEAP16[i24 + 6 >> 1] = HEAP32[i29 + 16 >> 2];
+    HEAP8[i24 + 9 | 0] = 0;
+    i29 = i9 + 16 | 0;
+    HEAP32[i24 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i24;
+    HEAP8[i15 + 10 | 0] = 0;
+    i10 = i15 + 8 | 0;
+    HEAP8[i10] = HEAP8[i28] | 0;
+    i11 = HEAP32[(HEAP32[i11 >> 2] | 0) + 64 >> 2] | 0;
+    HEAP16[i15 + 4 >> 1] = HEAP32[i11 + 28 >> 2];
+    HEAP16[i15 + 6 >> 1] = HEAP32[i11 + 16 >> 2];
+    i11 = i15 + 9 | 0;
+    HEAP8[i11] = 0;
+    HEAP32[i15 >> 2] = HEAP32[i29 >> 2];
+    HEAP32[i29 >> 2] = i15;
+    _luaX_next(i4);
+    L124 : do {
+     i12 = HEAP32[i5 >> 2] | 0;
+     switch (i12 | 0) {
+     case 277:
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       break L124;
+      }
+     default:
+      {}
+     }
+     _statement(i4);
+    } while ((i12 | 0) != 274);
+    _check_match(i4, 277, 273, i6);
+    _subexpr(i4, i8, 0) | 0;
+    if ((HEAP32[i8 >> 2] | 0) == 1) {
+     HEAP32[i8 >> 2] = 3;
+    }
+    _luaK_goiftrue(HEAP32[i3 >> 2] | 0, i8);
+    i4 = HEAP32[i8 + 20 >> 2] | 0;
+    if ((HEAP8[i11] | 0) != 0) {
+     _luaK_patchclose(i9, i4, HEAPU8[i10] | 0);
+    }
+    _leaveblock(i9);
+    _luaK_patchlist(i9, i4, i7);
+    _leaveblock(i9);
+    break;
+   }
+  case 285:
+   {
+    _luaX_next(i4);
+    if ((HEAP32[i5 >> 2] | 0) != 288) {
+     _error_expected(i4, 288);
+    }
+    i10 = HEAP32[i4 + 24 >> 2] | 0;
+    _luaX_next(i4);
+    i15 = HEAP32[i3 >> 2] | 0;
+    i9 = i4 + 64 | 0;
+    i14 = HEAP32[i9 >> 2] | 0;
+    i12 = i14 + 24 | 0;
+    i11 = i15 + 16 | 0;
+    i16 = HEAP16[(HEAP32[i11 >> 2] | 0) + 4 >> 1] | 0;
+    i13 = i14 + 28 | 0;
+    L138 : do {
+     if ((i16 | 0) < (HEAP32[i13 >> 2] | 0)) {
+      while (1) {
+       i17 = i16 + 1 | 0;
+       if ((_luaS_eqstr(i10, HEAP32[(HEAP32[i12 >> 2] | 0) + (i16 << 4) >> 2] | 0) | 0) != 0) {
+        break;
+       }
+       if ((i17 | 0) < (HEAP32[i13 >> 2] | 0)) {
+        i16 = i17;
+       } else {
+        break L138;
+       }
+      }
+      i28 = i15 + 12 | 0;
+      i29 = HEAP32[(HEAP32[i28 >> 2] | 0) + 52 >> 2] | 0;
+      i27 = HEAP32[(HEAP32[i12 >> 2] | 0) + (i16 << 4) + 8 >> 2] | 0;
+      HEAP32[i8 >> 2] = i10 + 16;
+      HEAP32[i8 + 4 >> 2] = i27;
+      i29 = _luaO_pushfstring(i29, 6680, i8) | 0;
+      _semerror(HEAP32[i28 >> 2] | 0, i29);
+     }
+    } while (0);
+    if ((HEAP32[i5 >> 2] | 0) != 285) {
+     _error_expected(i4, 285);
+    }
+    _luaX_next(i4);
+    i8 = HEAP32[i15 + 20 >> 2] | 0;
+    i15 = HEAP32[i13 >> 2] | 0;
+    i14 = i14 + 32 | 0;
+    if ((i15 | 0) < (HEAP32[i14 >> 2] | 0)) {
+     i14 = HEAP32[i12 >> 2] | 0;
+    } else {
+     i14 = _luaM_growaux_(HEAP32[i1 >> 2] | 0, HEAP32[i12 >> 2] | 0, i14, 16, 32767, 6312) | 0;
+     HEAP32[i12 >> 2] = i14;
+    }
+    HEAP32[i14 + (i15 << 4) >> 2] = i10;
+    i29 = HEAP32[i12 >> 2] | 0;
+    HEAP32[i29 + (i15 << 4) + 8 >> 2] = i6;
+    HEAP8[i29 + (i15 << 4) + 12 | 0] = HEAP8[(HEAP32[i3 >> 2] | 0) + 46 | 0] | 0;
+    HEAP32[(HEAP32[i12 >> 2] | 0) + (i15 << 4) + 4 >> 2] = i8;
+    HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + 1;
+    L152 : while (1) {
+     switch (HEAP32[i5 >> 2] | 0) {
+     case 285:
+     case 59:
+      {
+       break;
+      }
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       i7 = 108;
+       break L152;
+      }
+     default:
+      {
+       break L152;
+      }
+     }
+     _statement(i4);
+    }
+    if ((i7 | 0) == 108) {
+     HEAP8[(HEAP32[i12 >> 2] | 0) + (i15 << 4) + 12 | 0] = HEAP8[(HEAP32[i11 >> 2] | 0) + 8 | 0] | 0;
+    }
+    i5 = (HEAP32[i12 >> 2] | 0) + (i15 << 4) | 0;
+    i8 = HEAP32[i9 >> 2] | 0;
+    i7 = HEAP16[(HEAP32[(HEAP32[i3 >> 2] | 0) + 16 >> 2] | 0) + 6 >> 1] | 0;
+    i6 = i8 + 16 | 0;
+    if ((i7 | 0) < (HEAP32[i6 >> 2] | 0)) {
+     i8 = i8 + 12 | 0;
+     do {
+      while (1) {
+       if ((_luaS_eqstr(HEAP32[(HEAP32[i8 >> 2] | 0) + (i7 << 4) >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0) == 0) {
+        break;
+       }
+       _closegoto(i4, i7, i5);
+       if ((i7 | 0) >= (HEAP32[i6 >> 2] | 0)) {
+        break L8;
+       }
+      }
+      i7 = i7 + 1 | 0;
+     } while ((i7 | 0) < (HEAP32[i6 >> 2] | 0));
+    }
+    break;
+   }
+  case 274:
+   {
+    _luaX_next(i4);
+    i6 = HEAP32[i3 >> 2] | 0;
+    L166 : do {
+     switch (HEAP32[i5 >> 2] | 0) {
+     case 59:
+     case 277:
+     case 286:
+     case 262:
+     case 261:
+     case 260:
+      {
+       i8 = 0;
+       i7 = 0;
+       break;
+      }
+     default:
+      {
+       _subexpr(i4, i24, 0) | 0;
+       if ((HEAP32[i5 >> 2] | 0) == 44) {
+        i7 = 1;
+        do {
+         _luaX_next(i4);
+         _luaK_exp2nextreg(HEAP32[i3 >> 2] | 0, i24);
+         _subexpr(i4, i24, 0) | 0;
+         i7 = i7 + 1 | 0;
+        } while ((HEAP32[i5 >> 2] | 0) == 44);
+       } else {
+        i7 = 1;
+       }
+       if (!(((HEAP32[i24 >> 2] | 0) + -12 | 0) >>> 0 < 2)) {
+        if ((i7 | 0) == 1) {
+         i8 = _luaK_exp2anyreg(i6, i24) | 0;
+         i7 = 1;
+         break L166;
+        } else {
+         _luaK_exp2nextreg(i6, i24);
+         i8 = HEAPU8[i6 + 46 | 0] | 0;
+         break L166;
+        }
+       } else {
+        _luaK_setreturns(i6, i24, -1);
+        if ((HEAP32[i24 >> 2] | 0) == 12 & (i7 | 0) == 1) {
+         i29 = (HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i24 + 8 >> 2] << 2) | 0;
+         HEAP32[i29 >> 2] = HEAP32[i29 >> 2] & -64 | 30;
+        }
+        i8 = HEAPU8[i6 + 46 | 0] | 0;
+        i7 = -1;
+        break L166;
+       }
+      }
+     }
+    } while (0);
+    _luaK_ret(i6, i8, i7);
+    if ((HEAP32[i5 >> 2] | 0) == 59) {
+     _luaX_next(i4);
+    }
+    break;
+   }
+  case 266:
+  case 258:
+   {
+    i6 = _luaK_jump(i9) | 0;
+    i7 = HEAP32[i19 >> 2] | 0;
+    i29 = (HEAP32[i5 >> 2] | 0) == 266;
+    _luaX_next(i4);
+    do {
+     if (i29) {
+      if ((HEAP32[i5 >> 2] | 0) == 288) {
+       i23 = HEAP32[i4 + 24 >> 2] | 0;
+       _luaX_next(i4);
+       break;
+      } else {
+       _error_expected(i4, 288);
+      }
+     } else {
+      i23 = _luaS_new(HEAP32[i1 >> 2] | 0, 6304) | 0;
+     }
+    } while (0);
+    i10 = HEAP32[i4 + 64 >> 2] | 0;
+    i9 = i10 + 12 | 0;
+    i5 = i10 + 16 | 0;
+    i8 = HEAP32[i5 >> 2] | 0;
+    i10 = i10 + 20 | 0;
+    if ((i8 | 0) < (HEAP32[i10 >> 2] | 0)) {
+     i10 = HEAP32[i9 >> 2] | 0;
+    } else {
+     i10 = _luaM_growaux_(HEAP32[i1 >> 2] | 0, HEAP32[i9 >> 2] | 0, i10, 16, 32767, 6312) | 0;
+     HEAP32[i9 >> 2] = i10;
+    }
+    HEAP32[i10 + (i8 << 4) >> 2] = i23;
+    i29 = HEAP32[i9 >> 2] | 0;
+    HEAP32[i29 + (i8 << 4) + 8 >> 2] = i7;
+    HEAP8[i29 + (i8 << 4) + 12 | 0] = HEAP8[(HEAP32[i3 >> 2] | 0) + 46 | 0] | 0;
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i8 << 4) + 4 >> 2] = i6;
+    HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+    _findlabel(i4, i8) | 0;
+    break;
+   }
+  default:
+   {
+    i6 = i8 + 8 | 0;
+    _suffixedexp(i4, i6);
+    i29 = HEAP32[i5 >> 2] | 0;
+    if ((i29 | 0) == 44 | (i29 | 0) == 61) {
+     HEAP32[i8 >> 2] = 0;
+     _assignment(i4, i8, 1);
+     break L8;
+    }
+    if ((HEAP32[i6 >> 2] | 0) == 12) {
+     i29 = (HEAP32[(HEAP32[i9 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i8 + 16 >> 2] << 2) | 0;
+     HEAP32[i29 >> 2] = HEAP32[i29 >> 2] & -8372225 | 16384;
+     break L8;
+    } else {
+     _luaX_syntaxerror(i4, 6344);
+    }
+   }
+  }
+ } while (0);
+ i29 = HEAP32[i3 >> 2] | 0;
+ HEAP8[i29 + 48 | 0] = HEAP8[i29 + 46 | 0] | 0;
+ i29 = (HEAP32[i1 >> 2] | 0) + 38 | 0;
+ HEAP16[i29 >> 1] = (HEAP16[i29 >> 1] | 0) + -1 << 16 >> 16;
+ STACKTOP = i2;
+ return;
+}
+function _match(i1, i12, i11) {
+ i1 = i1 | 0;
+ i12 = i12 | 0;
+ i11 = i11 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i8 = i2;
+ i32 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i1 >> 2] = i32 + -1;
+ if ((i32 | 0) == 0) {
+  _luaL_error(HEAP32[i1 + 16 >> 2] | 0, 7272, i8) | 0;
+ }
+ i14 = i1 + 12 | 0;
+ i22 = HEAP32[i14 >> 2] | 0;
+ L4 : do {
+  if ((i22 | 0) != (i11 | 0)) {
+   i3 = i1 + 8 | 0;
+   i9 = i1 + 16 | 0;
+   i16 = i1 + 4 | 0;
+   i10 = i1 + 20 | 0;
+   L6 : while (1) {
+    i19 = i12 + 1 | 0;
+    i20 = i12 + -1 | 0;
+    L8 : while (1) {
+     i23 = HEAP8[i11] | 0;
+     i21 = i23 << 24 >> 24;
+     L10 : do {
+      if ((i21 | 0) == 36) {
+       i7 = i11 + 1 | 0;
+       if ((i7 | 0) == (i22 | 0)) {
+        i7 = 23;
+        break L6;
+       } else {
+        i22 = i7;
+        i21 = i7;
+        i7 = 89;
+       }
+      } else if ((i21 | 0) == 37) {
+       i21 = i11 + 1 | 0;
+       i23 = HEAP8[i21] | 0;
+       switch (i23 << 24 >> 24 | 0) {
+       case 57:
+       case 56:
+       case 55:
+       case 54:
+       case 53:
+       case 52:
+       case 51:
+       case 50:
+       case 49:
+       case 48:
+        {
+         i7 = 69;
+         break L8;
+        }
+       case 98:
+        {
+         i7 = 25;
+         break L8;
+        }
+       case 102:
+        {
+         break;
+        }
+       default:
+        {
+         if ((i21 | 0) == (i22 | 0)) {
+          _luaL_error(HEAP32[i9 >> 2] | 0, 7368, i8) | 0;
+         }
+         i22 = i11 + 2 | 0;
+         i7 = 89;
+         break L10;
+        }
+       }
+       i22 = i11 + 2 | 0;
+       if ((HEAP8[i22] | 0) == 91) {
+        i21 = 91;
+       } else {
+        _luaL_error(HEAP32[i9 >> 2] | 0, 7296, i8) | 0;
+        i21 = HEAP8[i22] | 0;
+       }
+       i23 = i11 + 3 | 0;
+       i21 = i21 << 24 >> 24;
+       if ((i21 | 0) == 91) {
+        i21 = (HEAP8[i23] | 0) == 94 ? i11 + 4 | 0 : i23;
+        while (1) {
+         if ((i21 | 0) == (HEAP32[i14 >> 2] | 0)) {
+          _luaL_error(HEAP32[i9 >> 2] | 0, 7408, i8) | 0;
+         }
+         i11 = i21 + 1 | 0;
+         if ((HEAP8[i21] | 0) == 37) {
+          i11 = i11 >>> 0 < (HEAP32[i14 >> 2] | 0) >>> 0 ? i21 + 2 | 0 : i11;
+         }
+         if ((HEAP8[i11] | 0) == 93) {
+          break;
+         } else {
+          i21 = i11;
+         }
+        }
+        i11 = i11 + 1 | 0;
+       } else if ((i21 | 0) == 37) {
+        if ((i23 | 0) == (HEAP32[i14 >> 2] | 0)) {
+         _luaL_error(HEAP32[i9 >> 2] | 0, 7368, i8) | 0;
+        }
+        i11 = i11 + 4 | 0;
+       } else {
+        i11 = i23;
+       }
+       if ((i12 | 0) == (HEAP32[i16 >> 2] | 0)) {
+        i25 = 0;
+       } else {
+        i25 = HEAP8[i20] | 0;
+       }
+       i24 = i25 & 255;
+       i21 = i11 + -1 | 0;
+       i26 = (HEAP8[i23] | 0) == 94;
+       i28 = i26 ? i23 : i22;
+       i27 = i26 & 1;
+       i26 = i27 ^ 1;
+       i30 = i28 + 1 | 0;
+       L41 : do {
+        if (i30 >>> 0 < i21 >>> 0) {
+         while (1) {
+          i32 = HEAP8[i30] | 0;
+          i29 = i28 + 2 | 0;
+          i31 = HEAP8[i29] | 0;
+          do {
+           if (i32 << 24 >> 24 == 37) {
+            if ((_match_class(i24, i31 & 255) | 0) == 0) {
+             i28 = i29;
+            } else {
+             break L41;
+            }
+           } else {
+            if (i31 << 24 >> 24 == 45 ? (i18 = i28 + 3 | 0, i18 >>> 0 < i21 >>> 0) : 0) {
+             if ((i32 & 255) > (i25 & 255)) {
+              i28 = i18;
+              break;
+             }
+             if ((HEAPU8[i18] | 0) < (i25 & 255)) {
+              i28 = i18;
+              break;
+             } else {
+              break L41;
+             }
+            }
+            if (i32 << 24 >> 24 == i25 << 24 >> 24) {
+             break L41;
+            } else {
+             i28 = i30;
+            }
+           }
+          } while (0);
+          i30 = i28 + 1 | 0;
+          if (!(i30 >>> 0 < i21 >>> 0)) {
+           i26 = i27;
+           break;
+          }
+         }
+        } else {
+         i26 = i27;
+        }
+       } while (0);
+       if ((i26 | 0) != 0) {
+        i12 = 0;
+        break L4;
+       }
+       i24 = HEAP8[i12] | 0;
+       i25 = i24 & 255;
+       i27 = (HEAP8[i23] | 0) == 94;
+       i26 = i27 ? i23 : i22;
+       i22 = i27 & 1;
+       i23 = i22 ^ 1;
+       i30 = i26 + 1 | 0;
+       L55 : do {
+        if (i30 >>> 0 < i21 >>> 0) {
+         do {
+          i29 = HEAP8[i30] | 0;
+          i28 = i26 + 2 | 0;
+          i27 = HEAP8[i28] | 0;
+          do {
+           if (i29 << 24 >> 24 == 37) {
+            if ((_match_class(i25, i27 & 255) | 0) == 0) {
+             i26 = i28;
+            } else {
+             i22 = i23;
+             break L55;
+            }
+           } else {
+            if (i27 << 24 >> 24 == 45 ? (i17 = i26 + 3 | 0, i17 >>> 0 < i21 >>> 0) : 0) {
+             if ((i29 & 255) > (i24 & 255)) {
+              i26 = i17;
+              break;
+             }
+             if ((HEAPU8[i17] | 0) < (i24 & 255)) {
+              i26 = i17;
+              break;
+             } else {
+              i22 = i23;
+              break L55;
+             }
+            }
+            if (i29 << 24 >> 24 == i24 << 24 >> 24) {
+             i22 = i23;
+             break L55;
+            } else {
+             i26 = i30;
+            }
+           }
+          } while (0);
+          i30 = i26 + 1 | 0;
+         } while (i30 >>> 0 < i21 >>> 0);
+        }
+       } while (0);
+       if ((i22 | 0) == 0) {
+        i12 = 0;
+        break L4;
+       }
+      } else if ((i21 | 0) == 40) {
+       i7 = 7;
+       break L6;
+      } else if ((i21 | 0) != 41) {
+       i21 = i11 + 1 | 0;
+       if (i23 << 24 >> 24 == 91) {
+        i7 = (HEAP8[i21] | 0) == 94 ? i11 + 2 | 0 : i21;
+        while (1) {
+         if ((i7 | 0) == (i22 | 0)) {
+          _luaL_error(HEAP32[i9 >> 2] | 0, 7408, i8) | 0;
+         }
+         i22 = i7 + 1 | 0;
+         if ((HEAP8[i7] | 0) == 37) {
+          i7 = i22 >>> 0 < (HEAP32[i14 >> 2] | 0) >>> 0 ? i7 + 2 | 0 : i22;
+         } else {
+          i7 = i22;
+         }
+         if ((HEAP8[i7] | 0) == 93) {
+          break;
+         }
+         i22 = HEAP32[i14 >> 2] | 0;
+        }
+        i22 = i7 + 1 | 0;
+        i7 = 89;
+       } else {
+        i22 = i21;
+        i7 = 89;
+       }
+      } else {
+       i7 = 16;
+       break L6;
+      }
+     } while (0);
+     L80 : do {
+      if ((i7 | 0) == 89) {
+       i7 = 0;
+       do {
+        if ((HEAP32[i3 >> 2] | 0) >>> 0 > i12 >>> 0) {
+         i23 = HEAP8[i12] | 0;
+         i24 = i23 & 255;
+         i26 = HEAP8[i11] | 0;
+         i25 = i26 << 24 >> 24;
+         L85 : do {
+          if ((i25 | 0) == 46) {
+           i23 = HEAP8[i22] | 0;
+          } else if ((i25 | 0) == 37) {
+           i25 = _match_class(i24, HEAPU8[i21] | 0) | 0;
+           i7 = 104;
+          } else if ((i25 | 0) == 91) {
+           i7 = i22 + -1 | 0;
+           i25 = (HEAP8[i21] | 0) == 94;
+           i27 = i25 ? i21 : i11;
+           i26 = i25 & 1;
+           i25 = i26 ^ 1;
+           i30 = i27 + 1 | 0;
+           if (i30 >>> 0 < i7 >>> 0) {
+            while (1) {
+             i31 = HEAP8[i30] | 0;
+             i29 = i27 + 2 | 0;
+             i28 = HEAP8[i29] | 0;
+             do {
+              if (i31 << 24 >> 24 == 37) {
+               if ((_match_class(i24, i28 & 255) | 0) == 0) {
+                i27 = i29;
+               } else {
+                i7 = 104;
+                break L85;
+               }
+              } else {
+               if (i28 << 24 >> 24 == 45 ? (i13 = i27 + 3 | 0, i13 >>> 0 < i7 >>> 0) : 0) {
+                if ((i31 & 255) > (i23 & 255)) {
+                 i27 = i13;
+                 break;
+                }
+                if ((HEAPU8[i13] | 0) < (i23 & 255)) {
+                 i27 = i13;
+                 break;
+                } else {
+                 i7 = 104;
+                 break L85;
+                }
+               }
+               if (i31 << 24 >> 24 == i23 << 24 >> 24) {
+                i7 = 104;
+                break L85;
+               } else {
+                i27 = i30;
+               }
+              }
+             } while (0);
+             i30 = i27 + 1 | 0;
+             if (!(i30 >>> 0 < i7 >>> 0)) {
+              i25 = i26;
+              i7 = 104;
+              break;
+             }
+            }
+           } else {
+            i25 = i26;
+            i7 = 104;
+           }
+          } else {
+           i25 = i26 << 24 >> 24 == i23 << 24 >> 24 | 0;
+           i7 = 104;
+          }
+         } while (0);
+         if ((i7 | 0) == 104) {
+          i7 = 0;
+          i23 = HEAP8[i22] | 0;
+          if ((i25 | 0) == 0) {
+           break;
+          }
+         }
+         i23 = i23 << 24 >> 24;
+         if ((i23 | 0) == 45) {
+          i7 = 109;
+          break L6;
+         } else if ((i23 | 0) == 42) {
+          i7 = 112;
+          break L6;
+         } else if ((i23 | 0) == 43) {
+          break L6;
+         } else if ((i23 | 0) != 63) {
+          i12 = i19;
+          i11 = i22;
+          break L8;
+         }
+         i11 = i22 + 1 | 0;
+         i21 = _match(i1, i19, i11) | 0;
+         if ((i21 | 0) == 0) {
+          break L80;
+         } else {
+          i12 = i21;
+          break L4;
+         }
+        } else {
+         i23 = HEAP8[i22] | 0;
+        }
+       } while (0);
+       if (!(i23 << 24 >> 24 == 45 | i23 << 24 >> 24 == 63 | i23 << 24 >> 24 == 42)) {
+        i12 = 0;
+        break L4;
+       }
+       i11 = i22 + 1 | 0;
+      }
+     } while (0);
+     i22 = HEAP32[i14 >> 2] | 0;
+     if ((i11 | 0) == (i22 | 0)) {
+      break L4;
+     }
+    }
+    if ((i7 | 0) == 25) {
+     i7 = 0;
+     i21 = i11 + 2 | 0;
+     if (!((i22 + -1 | 0) >>> 0 > i21 >>> 0)) {
+      _luaL_error(HEAP32[i9 >> 2] | 0, 7440, i8) | 0;
+     }
+     i20 = HEAP8[i12] | 0;
+     if (!(i20 << 24 >> 24 == (HEAP8[i21] | 0))) {
+      i12 = 0;
+      break L4;
+     }
+     i21 = HEAP8[i11 + 3 | 0] | 0;
+     i22 = HEAP32[i3 >> 2] | 0;
+     if (i19 >>> 0 < i22 >>> 0) {
+      i24 = 1;
+     } else {
+      i12 = 0;
+      break L4;
+     }
+     while (1) {
+      i23 = HEAP8[i19] | 0;
+      if (i23 << 24 >> 24 == i21 << 24 >> 24) {
+       i24 = i24 + -1 | 0;
+       if ((i24 | 0) == 0) {
+        break;
+       }
+      } else {
+       i24 = (i23 << 24 >> 24 == i20 << 24 >> 24) + i24 | 0;
+      }
+      i12 = i19 + 1 | 0;
+      if (i12 >>> 0 < i22 >>> 0) {
+       i32 = i19;
+       i19 = i12;
+       i12 = i32;
+      } else {
+       i12 = 0;
+       break L4;
+      }
+     }
+     i12 = i12 + 2 | 0;
+     i11 = i11 + 4 | 0;
+    } else if ((i7 | 0) == 69) {
+     i7 = 0;
+     i20 = i23 & 255;
+     i19 = i20 + -49 | 0;
+     if (((i19 | 0) >= 0 ? (i19 | 0) < (HEAP32[i10 >> 2] | 0) : 0) ? (i15 = HEAP32[i1 + (i19 << 3) + 28 >> 2] | 0, !((i15 | 0) == -1)) : 0) {
+      i20 = i15;
+     } else {
+      i19 = HEAP32[i9 >> 2] | 0;
+      HEAP32[i8 >> 2] = i20 + -48;
+      i20 = _luaL_error(i19, 7336, i8) | 0;
+      i19 = i20;
+      i20 = HEAP32[i1 + (i20 << 3) + 28 >> 2] | 0;
+     }
+     if (((HEAP32[i3 >> 2] | 0) - i12 | 0) >>> 0 < i20 >>> 0) {
+      i12 = 0;
+      break L4;
+     }
+     if ((_memcmp(HEAP32[i1 + (i19 << 3) + 24 >> 2] | 0, i12, i20) | 0) != 0) {
+      i12 = 0;
+      break L4;
+     }
+     i12 = i12 + i20 | 0;
+     if ((i12 | 0) == 0) {
+      i12 = 0;
+      break L4;
+     }
+     i11 = i11 + 2 | 0;
+    }
+    i22 = HEAP32[i14 >> 2] | 0;
+    if ((i11 | 0) == (i22 | 0)) {
+     break L4;
+    }
+   }
+   if ((i7 | 0) == 7) {
+    i3 = i11 + 1 | 0;
+    if ((HEAP8[i3] | 0) == 41) {
+     i3 = HEAP32[i10 >> 2] | 0;
+     if ((i3 | 0) > 31) {
+      _luaL_error(HEAP32[i9 >> 2] | 0, 7200, i8) | 0;
+     }
+     HEAP32[i1 + (i3 << 3) + 24 >> 2] = i12;
+     HEAP32[i1 + (i3 << 3) + 28 >> 2] = -2;
+     HEAP32[i10 >> 2] = i3 + 1;
+     i12 = _match(i1, i12, i11 + 2 | 0) | 0;
+     if ((i12 | 0) != 0) {
+      break;
+     }
+     HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -1;
+     i12 = 0;
+     break;
+    } else {
+     i4 = HEAP32[i10 >> 2] | 0;
+     if ((i4 | 0) > 31) {
+      _luaL_error(HEAP32[i9 >> 2] | 0, 7200, i8) | 0;
+     }
+     HEAP32[i1 + (i4 << 3) + 24 >> 2] = i12;
+     HEAP32[i1 + (i4 << 3) + 28 >> 2] = -1;
+     HEAP32[i10 >> 2] = i4 + 1;
+     i12 = _match(i1, i12, i3) | 0;
+     if ((i12 | 0) != 0) {
+      break;
+     }
+     HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -1;
+     i12 = 0;
+     break;
+    }
+   } else if ((i7 | 0) == 16) {
+    i3 = i11 + 1 | 0;
+    i5 = HEAP32[i10 >> 2] | 0;
+    while (1) {
+     i4 = i5 + -1 | 0;
+     if ((i5 | 0) <= 0) {
+      i7 = 19;
+      break;
+     }
+     if ((HEAP32[i1 + (i4 << 3) + 28 >> 2] | 0) == -1) {
+      break;
+     } else {
+      i5 = i4;
+     }
+    }
+    if ((i7 | 0) == 19) {
+     i4 = _luaL_error(HEAP32[i9 >> 2] | 0, 7488, i8) | 0;
+    }
+    i5 = i1 + (i4 << 3) + 28 | 0;
+    HEAP32[i5 >> 2] = i12 - (HEAP32[i1 + (i4 << 3) + 24 >> 2] | 0);
+    i12 = _match(i1, i12, i3) | 0;
+    if ((i12 | 0) != 0) {
+     break;
+    }
+    HEAP32[i5 >> 2] = -1;
+    i12 = 0;
+    break;
+   } else if ((i7 | 0) == 23) {
+    i12 = (i12 | 0) == (HEAP32[i3 >> 2] | 0) ? i12 : 0;
+    break;
+   } else if ((i7 | 0) == 109) {
+    i4 = i22 + 1 | 0;
+    i8 = _match(i1, i12, i4) | 0;
+    if ((i8 | 0) != 0) {
+     i12 = i8;
+     break;
+    }
+    i8 = i22 + -1 | 0;
+    while (1) {
+     if (!((HEAP32[i3 >> 2] | 0) >>> 0 > i12 >>> 0)) {
+      i12 = 0;
+      break L4;
+     }
+     i9 = HEAP8[i12] | 0;
+     i10 = i9 & 255;
+     i14 = HEAP8[i11] | 0;
+     i13 = i14 << 24 >> 24;
+     L139 : do {
+      if ((i13 | 0) == 91) {
+       i6 = (HEAP8[i21] | 0) == 94;
+       i13 = i6 ? i21 : i11;
+       i6 = i6 & 1;
+       i7 = i6 ^ 1;
+       i14 = i13 + 1 | 0;
+       if (i14 >>> 0 < i8 >>> 0) {
+        while (1) {
+         i17 = HEAP8[i14] | 0;
+         i15 = i13 + 2 | 0;
+         i16 = HEAP8[i15] | 0;
+         do {
+          if (i17 << 24 >> 24 == 37) {
+           if ((_match_class(i10, i16 & 255) | 0) == 0) {
+            i13 = i15;
+           } else {
+            i6 = i7;
+            i7 = 147;
+            break L139;
+           }
+          } else {
+           if (i16 << 24 >> 24 == 45 ? (i5 = i13 + 3 | 0, i5 >>> 0 < i8 >>> 0) : 0) {
+            if ((i17 & 255) > (i9 & 255)) {
+             i13 = i5;
+             break;
+            }
+            if ((HEAPU8[i5] | 0) < (i9 & 255)) {
+             i13 = i5;
+             break;
+            } else {
+             i6 = i7;
+             i7 = 147;
+             break L139;
+            }
+           }
+           if (i17 << 24 >> 24 == i9 << 24 >> 24) {
+            i6 = i7;
+            i7 = 147;
+            break L139;
+           } else {
+            i13 = i14;
+           }
+          }
+         } while (0);
+         i14 = i13 + 1 | 0;
+         if (!(i14 >>> 0 < i8 >>> 0)) {
+          i7 = 147;
+          break;
+         }
+        }
+       } else {
+        i7 = 147;
+       }
+      } else if ((i13 | 0) == 37) {
+       i6 = _match_class(i10, HEAPU8[i21] | 0) | 0;
+       i7 = 147;
+      } else if ((i13 | 0) != 46) {
+       i6 = i14 << 24 >> 24 == i9 << 24 >> 24 | 0;
+       i7 = 147;
+      }
+     } while (0);
+     if ((i7 | 0) == 147 ? (i7 = 0, (i6 | 0) == 0) : 0) {
+      i12 = 0;
+      break L4;
+     }
+     i9 = i12 + 1 | 0;
+     i12 = _match(i1, i9, i4) | 0;
+     if ((i12 | 0) == 0) {
+      i12 = i9;
+     } else {
+      break L4;
+     }
+    }
+   } else if ((i7 | 0) == 112) {
+    i19 = i12;
+   }
+   i10 = HEAP32[i3 >> 2] | 0;
+   if (i10 >>> 0 > i19 >>> 0) {
+    i5 = i22 + -1 | 0;
+    i8 = i19;
+    i6 = 0;
+    do {
+     i8 = HEAP8[i8] | 0;
+     i9 = i8 & 255;
+     i13 = HEAP8[i11] | 0;
+     i12 = i13 << 24 >> 24;
+     L183 : do {
+      if ((i12 | 0) == 37) {
+       i10 = _match_class(i9, HEAPU8[i21] | 0) | 0;
+       i7 = 129;
+      } else if ((i12 | 0) == 91) {
+       i7 = (HEAP8[i21] | 0) == 94;
+       i12 = i7 ? i21 : i11;
+       i10 = i7 & 1;
+       i7 = i10 ^ 1;
+       i13 = i12 + 1 | 0;
+       if (i13 >>> 0 < i5 >>> 0) {
+        while (1) {
+         i14 = HEAP8[i13] | 0;
+         i16 = i12 + 2 | 0;
+         i15 = HEAP8[i16] | 0;
+         do {
+          if (i14 << 24 >> 24 == 37) {
+           if ((_match_class(i9, i15 & 255) | 0) == 0) {
+            i12 = i16;
+           } else {
+            i10 = i7;
+            i7 = 129;
+            break L183;
+           }
+          } else {
+           if (i15 << 24 >> 24 == 45 ? (i4 = i12 + 3 | 0, i4 >>> 0 < i5 >>> 0) : 0) {
+            if ((i14 & 255) > (i8 & 255)) {
+             i12 = i4;
+             break;
+            }
+            if ((HEAPU8[i4] | 0) < (i8 & 255)) {
+             i12 = i4;
+             break;
+            } else {
+             i10 = i7;
+             i7 = 129;
+             break L183;
+            }
+           }
+           if (i14 << 24 >> 24 == i8 << 24 >> 24) {
+            i10 = i7;
+            i7 = 129;
+            break L183;
+           } else {
+            i12 = i13;
+           }
+          }
+         } while (0);
+         i13 = i12 + 1 | 0;
+         if (!(i13 >>> 0 < i5 >>> 0)) {
+          i7 = 129;
+          break;
+         }
+        }
+       } else {
+        i7 = 129;
+       }
+      } else if ((i12 | 0) != 46) {
+       i10 = i13 << 24 >> 24 == i8 << 24 >> 24 | 0;
+       i7 = 129;
+      }
+     } while (0);
+     if ((i7 | 0) == 129) {
+      i7 = 0;
+      if ((i10 | 0) == 0) {
+       break;
+      }
+      i10 = HEAP32[i3 >> 2] | 0;
+     }
+     i6 = i6 + 1 | 0;
+     i8 = i19 + i6 | 0;
+    } while (i10 >>> 0 > i8 >>> 0);
+    if (!((i6 | 0) > -1)) {
+     i12 = 0;
+     break;
+    }
+   } else {
+    i6 = 0;
+   }
+   i3 = i22 + 1 | 0;
+   while (1) {
+    i12 = _match(i1, i19 + i6 | 0, i3) | 0;
+    if ((i12 | 0) != 0) {
+     break L4;
+    }
+    if ((i6 | 0) > 0) {
+     i6 = i6 + -1 | 0;
+    } else {
+     i12 = 0;
+     break;
+    }
+   }
+  }
+ } while (0);
+ HEAP32[i1 >> 2] = (HEAP32[i1 >> 2] | 0) + 1;
+ STACKTOP = i2;
+ return i12 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[12928 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[12932 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[12920 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 12952 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[3228] = HEAP32[3228] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 13216 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[12936 >> 2] | 0)) {
+   i21 = (HEAP32[12924 >> 2] | 0) + i11 | 0;
+   HEAP32[12924 >> 2] = i21;
+   HEAP32[12936 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[12932 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[12932 >> 2] = 0;
+   HEAP32[12920 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[12932 >> 2] | 0)) {
+   i21 = (HEAP32[12920 >> 2] | 0) + i11 | 0;
+   HEAP32[12920 >> 2] = i21;
+   HEAP32[12932 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 13216 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 12952 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[3228] = HEAP32[3228] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[12932 >> 2] | 0)) {
+   HEAP32[12920 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 12952 + (i7 << 2) | 0;
+  i8 = HEAP32[3228] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 12952 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[3228] = i8 | i6;
+   i4 = 12952 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 13216 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[12916 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L204 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L204;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[12928 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[12916 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[12944 >> 2] | 0) + -1 | 0;
+ HEAP32[12944 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 13368 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[12944 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function _dispose_chunk(i6, i7) {
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i1 = STACKTOP;
+ i5 = i6 + i7 | 0;
+ i10 = HEAP32[i6 + 4 >> 2] | 0;
+ do {
+  if ((i10 & 1 | 0) == 0) {
+   i14 = HEAP32[i6 >> 2] | 0;
+   if ((i10 & 3 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i10 = i6 + (0 - i14) | 0;
+   i11 = i14 + i7 | 0;
+   i15 = HEAP32[12928 >> 2] | 0;
+   if (i10 >>> 0 < i15 >>> 0) {
+    _abort();
+   }
+   if ((i10 | 0) == (HEAP32[12932 >> 2] | 0)) {
+    i2 = i6 + (i7 + 4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i10;
+     i12 = i11;
+     break;
+    }
+    HEAP32[12920 >> 2] = i11;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i6 + (4 - i14) >> 2] = i11 | 1;
+    HEAP32[i5 >> 2] = i11;
+    STACKTOP = i1;
+    return;
+   }
+   i17 = i14 >>> 3;
+   if (i14 >>> 0 < 256) {
+    i2 = HEAP32[i6 + (8 - i14) >> 2] | 0;
+    i12 = HEAP32[i6 + (12 - i14) >> 2] | 0;
+    i13 = 12952 + (i17 << 1 << 2) | 0;
+    if ((i2 | 0) != (i13 | 0)) {
+     if (i2 >>> 0 < i15 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i10 | 0)) {
+      _abort();
+     }
+    }
+    if ((i12 | 0) == (i2 | 0)) {
+     HEAP32[3228] = HEAP32[3228] & ~(1 << i17);
+     i2 = i10;
+     i12 = i11;
+     break;
+    }
+    if ((i12 | 0) != (i13 | 0)) {
+     if (i12 >>> 0 < i15 >>> 0) {
+      _abort();
+     }
+     i13 = i12 + 8 | 0;
+     if ((HEAP32[i13 >> 2] | 0) == (i10 | 0)) {
+      i16 = i13;
+     } else {
+      _abort();
+     }
+    } else {
+     i16 = i12 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i12;
+    HEAP32[i16 >> 2] = i2;
+    i2 = i10;
+    i12 = i11;
+    break;
+   }
+   i16 = HEAP32[i6 + (24 - i14) >> 2] | 0;
+   i18 = HEAP32[i6 + (12 - i14) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i10 | 0)) {
+     i19 = 16 - i14 | 0;
+     i18 = i6 + (i19 + 4) | 0;
+     i17 = HEAP32[i18 >> 2] | 0;
+     if ((i17 | 0) == 0) {
+      i18 = i6 + i19 | 0;
+      i17 = HEAP32[i18 >> 2] | 0;
+      if ((i17 | 0) == 0) {
+       i13 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i19 = i17 + 20 | 0;
+      i20 = HEAP32[i19 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i17 = i20;
+       i18 = i19;
+       continue;
+      }
+      i20 = i17 + 16 | 0;
+      i19 = HEAP32[i20 >> 2] | 0;
+      if ((i19 | 0) == 0) {
+       break;
+      } else {
+       i17 = i19;
+       i18 = i20;
+      }
+     }
+     if (i18 >>> 0 < i15 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i18 >> 2] = 0;
+      i13 = i17;
+      break;
+     }
+    } else {
+     i17 = HEAP32[i6 + (8 - i14) >> 2] | 0;
+     if (i17 >>> 0 < i15 >>> 0) {
+      _abort();
+     }
+     i19 = i17 + 12 | 0;
+     if ((HEAP32[i19 >> 2] | 0) != (i10 | 0)) {
+      _abort();
+     }
+     i15 = i18 + 8 | 0;
+     if ((HEAP32[i15 >> 2] | 0) == (i10 | 0)) {
+      HEAP32[i19 >> 2] = i18;
+      HEAP32[i15 >> 2] = i17;
+      i13 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i16 | 0) != 0) {
+    i15 = HEAP32[i6 + (28 - i14) >> 2] | 0;
+    i17 = 13216 + (i15 << 2) | 0;
+    if ((i10 | 0) == (HEAP32[i17 >> 2] | 0)) {
+     HEAP32[i17 >> 2] = i13;
+     if ((i13 | 0) == 0) {
+      HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i15);
+      i2 = i10;
+      i12 = i11;
+      break;
+     }
+    } else {
+     if (i16 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i15 = i16 + 16 | 0;
+     if ((HEAP32[i15 >> 2] | 0) == (i10 | 0)) {
+      HEAP32[i15 >> 2] = i13;
+     } else {
+      HEAP32[i16 + 20 >> 2] = i13;
+     }
+     if ((i13 | 0) == 0) {
+      i2 = i10;
+      i12 = i11;
+      break;
+     }
+    }
+    if (i13 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i13 + 24 >> 2] = i16;
+    i14 = 16 - i14 | 0;
+    i15 = HEAP32[i6 + i14 >> 2] | 0;
+    do {
+     if ((i15 | 0) != 0) {
+      if (i15 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 + 16 >> 2] = i15;
+       HEAP32[i15 + 24 >> 2] = i13;
+       break;
+      }
+     }
+    } while (0);
+    i14 = HEAP32[i6 + (i14 + 4) >> 2] | 0;
+    if ((i14 | 0) != 0) {
+     if (i14 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i13 + 20 >> 2] = i14;
+      HEAP32[i14 + 24 >> 2] = i13;
+      i2 = i10;
+      i12 = i11;
+      break;
+     }
+    } else {
+     i2 = i10;
+     i12 = i11;
+    }
+   } else {
+    i2 = i10;
+    i12 = i11;
+   }
+  } else {
+   i2 = i6;
+   i12 = i7;
+  }
+ } while (0);
+ i10 = HEAP32[12928 >> 2] | 0;
+ if (i5 >>> 0 < i10 >>> 0) {
+  _abort();
+ }
+ i11 = i6 + (i7 + 4) | 0;
+ i13 = HEAP32[i11 >> 2] | 0;
+ if ((i13 & 2 | 0) == 0) {
+  if ((i5 | 0) == (HEAP32[12936 >> 2] | 0)) {
+   i20 = (HEAP32[12924 >> 2] | 0) + i12 | 0;
+   HEAP32[12924 >> 2] = i20;
+   HEAP32[12936 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i20 | 1;
+   if ((i2 | 0) != (HEAP32[12932 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[12932 >> 2] = 0;
+   HEAP32[12920 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i5 | 0) == (HEAP32[12932 >> 2] | 0)) {
+   i20 = (HEAP32[12920 >> 2] | 0) + i12 | 0;
+   HEAP32[12920 >> 2] = i20;
+   HEAP32[12932 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i20 | 1;
+   HEAP32[i2 + i20 >> 2] = i20;
+   STACKTOP = i1;
+   return;
+  }
+  i12 = (i13 & -8) + i12 | 0;
+  i11 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i9 = HEAP32[i6 + (i7 + 24) >> 2] | 0;
+    i11 = HEAP32[i6 + (i7 + 12) >> 2] | 0;
+    do {
+     if ((i11 | 0) == (i5 | 0)) {
+      i13 = i6 + (i7 + 20) | 0;
+      i11 = HEAP32[i13 >> 2] | 0;
+      if ((i11 | 0) == 0) {
+       i13 = i6 + (i7 + 16) | 0;
+       i11 = HEAP32[i13 >> 2] | 0;
+       if ((i11 | 0) == 0) {
+        i8 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i15 = i11 + 20 | 0;
+       i14 = HEAP32[i15 >> 2] | 0;
+       if ((i14 | 0) != 0) {
+        i11 = i14;
+        i13 = i15;
+        continue;
+       }
+       i14 = i11 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i11 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < i10 >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i8 = i11;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i6 + (i7 + 8) >> 2] | 0;
+      if (i13 >>> 0 < i10 >>> 0) {
+       _abort();
+      }
+      i10 = i13 + 12 | 0;
+      if ((HEAP32[i10 >> 2] | 0) != (i5 | 0)) {
+       _abort();
+      }
+      i14 = i11 + 8 | 0;
+      if ((HEAP32[i14 >> 2] | 0) == (i5 | 0)) {
+       HEAP32[i10 >> 2] = i11;
+       HEAP32[i14 >> 2] = i13;
+       i8 = i11;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i9 | 0) != 0) {
+     i10 = HEAP32[i6 + (i7 + 28) >> 2] | 0;
+     i11 = 13216 + (i10 << 2) | 0;
+     if ((i5 | 0) == (HEAP32[i11 >> 2] | 0)) {
+      HEAP32[i11 >> 2] = i8;
+      if ((i8 | 0) == 0) {
+       HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i10);
+       break;
+      }
+     } else {
+      if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i10 = i9 + 16 | 0;
+      if ((HEAP32[i10 >> 2] | 0) == (i5 | 0)) {
+       HEAP32[i10 >> 2] = i8;
+      } else {
+       HEAP32[i9 + 20 >> 2] = i8;
+      }
+      if ((i8 | 0) == 0) {
+       break;
+      }
+     }
+     if (i8 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i8 + 24 >> 2] = i9;
+     i5 = HEAP32[i6 + (i7 + 16) >> 2] | 0;
+     do {
+      if ((i5 | 0) != 0) {
+       if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 + 16 >> 2] = i5;
+        HEAP32[i5 + 24 >> 2] = i8;
+        break;
+       }
+      }
+     } while (0);
+     i5 = HEAP32[i6 + (i7 + 20) >> 2] | 0;
+     if ((i5 | 0) != 0) {
+      if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i8 + 20 >> 2] = i5;
+       HEAP32[i5 + 24 >> 2] = i8;
+       break;
+      }
+     }
+    }
+   } else {
+    i8 = HEAP32[i6 + (i7 + 8) >> 2] | 0;
+    i6 = HEAP32[i6 + (i7 + 12) >> 2] | 0;
+    i7 = 12952 + (i11 << 1 << 2) | 0;
+    if ((i8 | 0) != (i7 | 0)) {
+     if (i8 >>> 0 < i10 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i8 + 12 >> 2] | 0) != (i5 | 0)) {
+      _abort();
+     }
+    }
+    if ((i6 | 0) == (i8 | 0)) {
+     HEAP32[3228] = HEAP32[3228] & ~(1 << i11);
+     break;
+    }
+    if ((i6 | 0) != (i7 | 0)) {
+     if (i6 >>> 0 < i10 >>> 0) {
+      _abort();
+     }
+     i7 = i6 + 8 | 0;
+     if ((HEAP32[i7 >> 2] | 0) == (i5 | 0)) {
+      i9 = i7;
+     } else {
+      _abort();
+     }
+    } else {
+     i9 = i6 + 8 | 0;
+    }
+    HEAP32[i8 + 12 >> 2] = i6;
+    HEAP32[i9 >> 2] = i8;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i12 | 1;
+  HEAP32[i2 + i12 >> 2] = i12;
+  if ((i2 | 0) == (HEAP32[12932 >> 2] | 0)) {
+   HEAP32[12920 >> 2] = i12;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i11 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i12 | 1;
+  HEAP32[i2 + i12 >> 2] = i12;
+ }
+ i6 = i12 >>> 3;
+ if (i12 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i5 = 12952 + (i7 << 2) | 0;
+  i8 = HEAP32[3228] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i7 = 12952 + (i7 + 2 << 2) | 0;
+   i6 = HEAP32[i7 >> 2] | 0;
+   if (i6 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i7;
+    i3 = i6;
+   }
+  } else {
+   HEAP32[3228] = i8 | i6;
+   i4 = 12952 + (i7 + 2 << 2) | 0;
+   i3 = i5;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i3 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i3;
+  HEAP32[i2 + 12 >> 2] = i5;
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i12 >>> 8;
+ if ((i3 | 0) != 0) {
+  if (i12 >>> 0 > 16777215) {
+   i3 = 31;
+  } else {
+   i19 = (i3 + 1048320 | 0) >>> 16 & 8;
+   i20 = i3 << i19;
+   i18 = (i20 + 520192 | 0) >>> 16 & 4;
+   i20 = i20 << i18;
+   i3 = (i20 + 245760 | 0) >>> 16 & 2;
+   i3 = 14 - (i18 | i19 | i3) + (i20 << i3 >>> 15) | 0;
+   i3 = i12 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+  }
+ } else {
+  i3 = 0;
+ }
+ i6 = 13216 + (i3 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i3;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i5 = HEAP32[12916 >> 2] | 0;
+ i4 = 1 << i3;
+ if ((i5 & i4 | 0) == 0) {
+  HEAP32[12916 >> 2] = i5 | i4;
+  HEAP32[i6 >> 2] = i2;
+  HEAP32[i2 + 24 >> 2] = i6;
+  HEAP32[i2 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i2;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = HEAP32[i6 >> 2] | 0;
+ if ((i3 | 0) == 31) {
+  i3 = 0;
+ } else {
+  i3 = 25 - (i3 >>> 1) | 0;
+ }
+ L194 : do {
+  if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i12 | 0)) {
+   i3 = i12 << i3;
+   i6 = i4;
+   while (1) {
+    i5 = i6 + (i3 >>> 31 << 2) + 16 | 0;
+    i4 = HEAP32[i5 >> 2] | 0;
+    if ((i4 | 0) == 0) {
+     break;
+    }
+    if ((HEAP32[i4 + 4 >> 2] & -8 | 0) == (i12 | 0)) {
+     break L194;
+    } else {
+     i3 = i3 << 1;
+     i6 = i4;
+    }
+   }
+   if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+    _abort();
+   }
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i6;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+   STACKTOP = i1;
+   return;
+  }
+ } while (0);
+ i3 = i4 + 8 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i5 = HEAP32[12928 >> 2] | 0;
+ if (i4 >>> 0 < i5 >>> 0) {
+  _abort();
+ }
+ if (i6 >>> 0 < i5 >>> 0) {
+  _abort();
+ }
+ HEAP32[i6 + 12 >> 2] = i2;
+ HEAP32[i3 >> 2] = i2;
+ HEAP32[i2 + 8 >> 2] = i6;
+ HEAP32[i2 + 12 >> 2] = i4;
+ HEAP32[i2 + 24 >> 2] = 0;
+ STACKTOP = i1;
+ return;
+}
+function _singlestep(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i14 = i1;
+ i3 = i2 + 12 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ i6 = i8 + 61 | 0;
+ switch (HEAPU8[i6] | 0) {
+ case 0:
+  {
+   if ((HEAP32[i8 + 84 >> 2] | 0) != 0) {
+    i21 = i8 + 16 | 0;
+    i22 = HEAP32[i21 >> 2] | 0;
+    _propagatemark(i8);
+    i22 = (HEAP32[i21 >> 2] | 0) - i22 | 0;
+    STACKTOP = i1;
+    return i22 | 0;
+   }
+   HEAP8[i6] = 1;
+   i6 = i8 + 20 | 0;
+   HEAP32[i6 >> 2] = HEAP32[i8 + 16 >> 2];
+   i8 = HEAP32[i3 >> 2] | 0;
+   i7 = i8 + 16 | 0;
+   i14 = HEAP32[i7 >> 2] | 0;
+   if ((i2 | 0) != 0 ? !((HEAP8[i2 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i8, i2);
+   }
+   if ((HEAP32[i8 + 48 >> 2] & 64 | 0) != 0 ? (i13 = HEAP32[i8 + 40 >> 2] | 0, !((HEAP8[i13 + 5 | 0] & 3) == 0)) : 0) {
+    _reallymarkobject(i8, i13);
+   }
+   _markmt(i8);
+   i13 = i8 + 112 | 0;
+   i15 = HEAP32[i8 + 132 >> 2] | 0;
+   if ((i15 | 0) != (i13 | 0)) {
+    do {
+     if (((HEAP8[i15 + 5 | 0] & 7) == 0 ? (i12 = HEAP32[i15 + 8 >> 2] | 0, (HEAP32[i12 + 8 >> 2] & 64 | 0) != 0) : 0) ? (i11 = HEAP32[i12 >> 2] | 0, !((HEAP8[i11 + 5 | 0] & 3) == 0)) : 0) {
+      _reallymarkobject(i8, i11);
+     }
+     i15 = HEAP32[i15 + 20 >> 2] | 0;
+    } while ((i15 | 0) != (i13 | 0));
+   }
+   i16 = i8 + 84 | 0;
+   if ((HEAP32[i16 >> 2] | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   i17 = (HEAP32[i7 >> 2] | 0) - i14 | 0;
+   i11 = i8 + 92 | 0;
+   i12 = HEAP32[i11 >> 2] | 0;
+   i21 = i8 + 88 | 0;
+   i22 = HEAP32[i21 >> 2] | 0;
+   i15 = i8 + 96 | 0;
+   i13 = HEAP32[i15 >> 2] | 0;
+   HEAP32[i15 >> 2] = 0;
+   HEAP32[i21 >> 2] = 0;
+   HEAP32[i11 >> 2] = 0;
+   HEAP32[i16 >> 2] = i22;
+   if ((i22 | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   HEAP32[i16 >> 2] = i12;
+   if ((i12 | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   HEAP32[i16 >> 2] = i13;
+   if ((i13 | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   i18 = HEAP32[i7 >> 2] | 0;
+   while (1) {
+    i13 = HEAP32[i15 >> 2] | 0;
+    HEAP32[i15 >> 2] = 0;
+    i12 = 0;
+    L42 : while (1) {
+     i14 = i13;
+     while (1) {
+      if ((i14 | 0) == 0) {
+       break L42;
+      }
+      i13 = HEAP32[i14 + 24 >> 2] | 0;
+      if ((_traverseephemeron(i8, i14) | 0) == 0) {
+       i14 = i13;
+      } else {
+       break;
+      }
+     }
+     if ((HEAP32[i16 >> 2] | 0) == 0) {
+      i12 = 1;
+      continue;
+     }
+     while (1) {
+      _propagatemark(i8);
+      if ((HEAP32[i16 >> 2] | 0) == 0) {
+       i12 = 1;
+       continue L42;
+      }
+     }
+    }
+    if ((i12 | 0) == 0) {
+     break;
+    }
+   }
+   _clearvalues(i8, HEAP32[i11 >> 2] | 0, 0);
+   i14 = i8 + 100 | 0;
+   _clearvalues(i8, HEAP32[i14 >> 2] | 0, 0);
+   i13 = HEAP32[i11 >> 2] | 0;
+   i12 = HEAP32[i14 >> 2] | 0;
+   i21 = HEAP32[i7 >> 2] | 0;
+   i20 = HEAP32[i3 >> 2] | 0;
+   i19 = i20 + 104 | 0;
+   while (1) {
+    i22 = HEAP32[i19 >> 2] | 0;
+    if ((i22 | 0) == 0) {
+     break;
+    } else {
+     i19 = i22;
+    }
+   }
+   i17 = i17 - i18 + i21 | 0;
+   i20 = i20 + 72 | 0;
+   i21 = HEAP32[i20 >> 2] | 0;
+   L55 : do {
+    if ((i21 | 0) != 0) {
+     while (1) {
+      i18 = i21;
+      while (1) {
+       i22 = i18 + 5 | 0;
+       i21 = HEAP8[i22] | 0;
+       if ((i21 & 3) == 0) {
+        break;
+       }
+       HEAP8[i22] = i21 & 255 | 8;
+       HEAP32[i20 >> 2] = HEAP32[i18 >> 2];
+       HEAP32[i18 >> 2] = HEAP32[i19 >> 2];
+       HEAP32[i19 >> 2] = i18;
+       i19 = HEAP32[i20 >> 2] | 0;
+       if ((i19 | 0) == 0) {
+        break L55;
+       } else {
+        i22 = i18;
+        i18 = i19;
+        i19 = i22;
+       }
+      }
+      i21 = HEAP32[i18 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i20 = i18;
+      }
+     }
+    }
+   } while (0);
+   i19 = HEAP32[i8 + 104 >> 2] | 0;
+   if ((i19 | 0) != 0) {
+    i18 = i8 + 60 | 0;
+    do {
+     i22 = i19 + 5 | 0;
+     HEAP8[i22] = HEAP8[i18] & 3 | HEAP8[i22] & 184;
+     _reallymarkobject(i8, i19);
+     i19 = HEAP32[i19 >> 2] | 0;
+    } while ((i19 | 0) != 0);
+   }
+   if ((HEAP32[i16 >> 2] | 0) != 0) {
+    do {
+     _propagatemark(i8);
+    } while ((HEAP32[i16 >> 2] | 0) != 0);
+   }
+   i18 = HEAP32[i7 >> 2] | 0;
+   while (1) {
+    i20 = HEAP32[i15 >> 2] | 0;
+    HEAP32[i15 >> 2] = 0;
+    i19 = 0;
+    L74 : while (1) {
+     i21 = i20;
+     while (1) {
+      if ((i21 | 0) == 0) {
+       break L74;
+      }
+      i20 = HEAP32[i21 + 24 >> 2] | 0;
+      if ((_traverseephemeron(i8, i21) | 0) == 0) {
+       i21 = i20;
+      } else {
+       break;
+      }
+     }
+     if ((HEAP32[i16 >> 2] | 0) == 0) {
+      i19 = 1;
+      continue;
+     }
+     while (1) {
+      _propagatemark(i8);
+      if ((HEAP32[i16 >> 2] | 0) == 0) {
+       i19 = 1;
+       continue L74;
+      }
+     }
+    }
+    if ((i19 | 0) == 0) {
+     break;
+    }
+   }
+   i16 = i17 - i18 | 0;
+   i15 = HEAP32[i15 >> 2] | 0;
+   if ((i15 | 0) != 0) {
+    do {
+     i22 = 1 << HEAPU8[i15 + 7 | 0];
+     i19 = HEAP32[i15 + 16 >> 2] | 0;
+     i17 = i19 + (i22 << 5) | 0;
+     if ((i22 | 0) > 0) {
+      do {
+       i18 = i19 + 8 | 0;
+       do {
+        if ((HEAP32[i18 >> 2] | 0) != 0 ? (i9 = i19 + 24 | 0, i10 = HEAP32[i9 >> 2] | 0, (i10 & 64 | 0) != 0) : 0) {
+         i20 = HEAP32[i19 + 16 >> 2] | 0;
+         if ((i10 & 15 | 0) == 4) {
+          if ((i20 | 0) == 0) {
+           break;
+          }
+          if ((HEAP8[i20 + 5 | 0] & 3) == 0) {
+           break;
+          }
+          _reallymarkobject(i8, i20);
+          break;
+         } else {
+          i20 = i20 + 5 | 0;
+          if ((HEAP8[i20] & 3) == 0) {
+           break;
+          }
+          HEAP32[i18 >> 2] = 0;
+          if ((HEAP8[i20] & 3) == 0) {
+           break;
+          }
+          HEAP32[i9 >> 2] = 11;
+          break;
+         }
+        }
+       } while (0);
+       i19 = i19 + 32 | 0;
+      } while (i19 >>> 0 < i17 >>> 0);
+     }
+     i15 = HEAP32[i15 + 24 >> 2] | 0;
+    } while ((i15 | 0) != 0);
+   }
+   i10 = HEAP32[i14 >> 2] | 0;
+   if ((i10 | 0) != 0) {
+    do {
+     i22 = 1 << HEAPU8[i10 + 7 | 0];
+     i17 = HEAP32[i10 + 16 >> 2] | 0;
+     i9 = i17 + (i22 << 5) | 0;
+     if ((i22 | 0) > 0) {
+      do {
+       i15 = i17 + 8 | 0;
+       do {
+        if ((HEAP32[i15 >> 2] | 0) != 0 ? (i5 = i17 + 24 | 0, i4 = HEAP32[i5 >> 2] | 0, (i4 & 64 | 0) != 0) : 0) {
+         i18 = HEAP32[i17 + 16 >> 2] | 0;
+         if ((i4 & 15 | 0) == 4) {
+          if ((i18 | 0) == 0) {
+           break;
+          }
+          if ((HEAP8[i18 + 5 | 0] & 3) == 0) {
+           break;
+          }
+          _reallymarkobject(i8, i18);
+          break;
+         } else {
+          i18 = i18 + 5 | 0;
+          if ((HEAP8[i18] & 3) == 0) {
+           break;
+          }
+          HEAP32[i15 >> 2] = 0;
+          if ((HEAP8[i18] & 3) == 0) {
+           break;
+          }
+          HEAP32[i5 >> 2] = 11;
+          break;
+         }
+        }
+       } while (0);
+       i17 = i17 + 32 | 0;
+      } while (i17 >>> 0 < i9 >>> 0);
+     }
+     i10 = HEAP32[i10 + 24 >> 2] | 0;
+    } while ((i10 | 0) != 0);
+   }
+   _clearvalues(i8, HEAP32[i11 >> 2] | 0, i13);
+   _clearvalues(i8, HEAP32[i14 >> 2] | 0, i12);
+   i4 = i8 + 60 | 0;
+   HEAP8[i4] = HEAPU8[i4] ^ 3;
+   i4 = i16 + (HEAP32[i7 >> 2] | 0) | 0;
+   HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i4;
+   i3 = HEAP32[i3 >> 2] | 0;
+   HEAP8[i3 + 61 | 0] = 2;
+   HEAP32[i3 + 64 >> 2] = 0;
+   i7 = i3 + 72 | 0;
+   i5 = 0;
+   do {
+    i5 = i5 + 1 | 0;
+    i6 = _sweeplist(i2, i7, 1) | 0;
+   } while ((i6 | 0) == (i7 | 0));
+   HEAP32[i3 + 80 >> 2] = i6;
+   i6 = i3 + 68 | 0;
+   i7 = 0;
+   do {
+    i7 = i7 + 1 | 0;
+    i8 = _sweeplist(i2, i6, 1) | 0;
+   } while ((i8 | 0) == (i6 | 0));
+   HEAP32[i3 + 76 >> 2] = i8;
+   i22 = ((i7 + i5 | 0) * 5 | 0) + i4 | 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ case 2:
+  {
+   i3 = i8 + 64 | 0;
+   i4 = i8 + 32 | 0;
+   i8 = i8 + 24 | 0;
+   i5 = 0;
+   while (1) {
+    i10 = HEAP32[i3 >> 2] | 0;
+    i11 = i10 + i5 | 0;
+    i9 = HEAP32[i4 >> 2] | 0;
+    if ((i11 | 0) >= (i9 | 0)) {
+     i2 = i10;
+     break;
+    }
+    _sweeplist(i2, (HEAP32[i8 >> 2] | 0) + (i11 << 2) | 0, -3) | 0;
+    i5 = i5 + 1 | 0;
+    if ((i5 | 0) >= 80) {
+     i7 = 96;
+     break;
+    }
+   }
+   if ((i7 | 0) == 96) {
+    i2 = HEAP32[i3 >> 2] | 0;
+    i9 = HEAP32[i4 >> 2] | 0;
+   }
+   i22 = i2 + i5 | 0;
+   HEAP32[i3 >> 2] = i22;
+   if ((i22 | 0) >= (i9 | 0)) {
+    HEAP8[i6] = 3;
+   }
+   i22 = i5 * 5 | 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ case 5:
+  {
+   i2 = i8 + 16 | 0;
+   HEAP32[i2 >> 2] = HEAP32[i8 + 32 >> 2] << 2;
+   i22 = i8 + 84 | 0;
+   i3 = i8 + 172 | 0;
+   HEAP32[i22 + 0 >> 2] = 0;
+   HEAP32[i22 + 4 >> 2] = 0;
+   HEAP32[i22 + 8 >> 2] = 0;
+   HEAP32[i22 + 12 >> 2] = 0;
+   HEAP32[i22 + 16 >> 2] = 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i8, i3);
+   }
+   if ((HEAP32[i8 + 48 >> 2] & 64 | 0) != 0 ? (i15 = HEAP32[i8 + 40 >> 2] | 0, !((HEAP8[i15 + 5 | 0] & 3) == 0)) : 0) {
+    _reallymarkobject(i8, i15);
+   }
+   _markmt(i8);
+   i4 = HEAP32[i8 + 104 >> 2] | 0;
+   if ((i4 | 0) != 0) {
+    i3 = i8 + 60 | 0;
+    do {
+     i22 = i4 + 5 | 0;
+     HEAP8[i22] = HEAP8[i3] & 3 | HEAP8[i22] & 184;
+     _reallymarkobject(i8, i4);
+     i4 = HEAP32[i4 >> 2] | 0;
+    } while ((i4 | 0) != 0);
+   }
+   HEAP8[i6] = 0;
+   i22 = HEAP32[i2 >> 2] | 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ case 3:
+  {
+   i3 = i8 + 80 | 0;
+   i4 = HEAP32[i3 >> 2] | 0;
+   if ((i4 | 0) == 0) {
+    HEAP8[i6] = 4;
+    i22 = 0;
+    STACKTOP = i1;
+    return i22 | 0;
+   } else {
+    HEAP32[i3 >> 2] = _sweeplist(i2, i4, 80) | 0;
+    i22 = 400;
+    STACKTOP = i1;
+    return i22 | 0;
+   }
+  }
+ case 4:
+  {
+   i4 = i8 + 76 | 0;
+   i5 = HEAP32[i4 >> 2] | 0;
+   if ((i5 | 0) != 0) {
+    HEAP32[i4 >> 2] = _sweeplist(i2, i5, 80) | 0;
+    i22 = 400;
+    STACKTOP = i1;
+    return i22 | 0;
+   }
+   HEAP32[i14 >> 2] = HEAP32[i8 + 172 >> 2];
+   _sweeplist(i2, i14, 1) | 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP8[i3 + 62 | 0] | 0) != 1) {
+    i4 = (HEAP32[i3 + 32 >> 2] | 0) / 2 | 0;
+    if ((HEAP32[i3 + 28 >> 2] | 0) >>> 0 < i4 >>> 0) {
+     _luaS_resize(i2, i4);
+    }
+    i21 = i3 + 144 | 0;
+    i22 = i3 + 152 | 0;
+    HEAP32[i21 >> 2] = _luaM_realloc_(i2, HEAP32[i21 >> 2] | 0, HEAP32[i22 >> 2] | 0, 0) | 0;
+    HEAP32[i22 >> 2] = 0;
+   }
+   HEAP8[i6] = 5;
+   i22 = 5;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ default:
+  {
+   i22 = 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+ }
+ return 0;
+}
+function _pmain(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ i7 = _lua_tointegerx(i3, 1, 0) | 0;
+ i4 = _lua_touserdata(i3, 2) | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) != 0 ? (HEAP8[i5] | 0) != 0 : 0) {
+  HEAP32[20] = i5;
+ }
+ i12 = HEAP32[i4 + 4 >> 2] | 0;
+ do {
+  if ((i12 | 0) == 0) {
+   i5 = 0;
+   i6 = 0;
+   i8 = 0;
+   i9 = 1;
+   i10 = 1;
+  } else {
+   i9 = 0;
+   i8 = 0;
+   i11 = 0;
+   i6 = 0;
+   i5 = 1;
+   L6 : while (1) {
+    if ((HEAP8[i12] | 0) != 45) {
+     i10 = 18;
+     break;
+    }
+    switch (HEAP8[i12 + 1 | 0] | 0) {
+    case 108:
+     {
+      i10 = 12;
+      break;
+     }
+    case 69:
+     {
+      i9 = 1;
+      break;
+     }
+    case 45:
+     {
+      i10 = 7;
+      break L6;
+     }
+    case 105:
+     {
+      if ((HEAP8[i12 + 2 | 0] | 0) == 0) {
+       i11 = 1;
+       i6 = 1;
+      } else {
+       i5 = -1;
+       break L6;
+      }
+      break;
+     }
+    case 101:
+     {
+      i8 = 1;
+      i10 = 12;
+      break;
+     }
+    case 118:
+     {
+      if ((HEAP8[i12 + 2 | 0] | 0) == 0) {
+       i11 = 1;
+      } else {
+       i5 = -1;
+       break L6;
+      }
+      break;
+     }
+    case 0:
+     {
+      i10 = 18;
+      break L6;
+     }
+    default:
+     {
+      i10 = 16;
+      break L6;
+     }
+    }
+    if ((i10 | 0) == 12) {
+     i10 = 0;
+     if ((HEAP8[i12 + 2 | 0] | 0) == 0) {
+      i12 = i5 + 1 | 0;
+      i13 = HEAP32[i4 + (i12 << 2) >> 2] | 0;
+      if ((i13 | 0) == 0) {
+       i10 = 15;
+       break;
+      }
+      if ((HEAP8[i13] | 0) == 45) {
+       i10 = 15;
+       break;
+      } else {
+       i5 = i12;
+      }
+     }
+    }
+    i5 = i5 + 1 | 0;
+    i12 = HEAP32[i4 + (i5 << 2) >> 2] | 0;
+    if ((i12 | 0) == 0) {
+     i5 = 0;
+     i12 = i9;
+     i10 = 23;
+     break;
+    }
+   }
+   if ((i10 | 0) == 7) {
+    if ((HEAP8[i12 + 2 | 0] | 0) == 0) {
+     i5 = i5 + 1 | 0;
+     i5 = (HEAP32[i4 + (i5 << 2) >> 2] | 0) == 0 ? 0 : i5;
+     i10 = 18;
+    } else {
+     i5 = -1;
+    }
+   } else if ((i10 | 0) == 15) {
+    i5 = 0 - i5 | 0;
+    i10 = 18;
+   } else if ((i10 | 0) == 16) {
+    i5 = 0 - i5 | 0;
+    i10 = 18;
+   }
+   if ((i10 | 0) == 18) {
+    if ((i5 | 0) >= 0) {
+     i12 = i9;
+     i10 = 23;
+    }
+   }
+   if ((i10 | 0) == 23) {
+    if ((i11 | 0) == 0) {
+     i9 = 1;
+    } else {
+     i9 = HEAP32[_stdout >> 2] | 0;
+     _fwrite(440, 1, 51, i9 | 0) | 0;
+     _fputc(10, i9 | 0) | 0;
+     _fflush(i9 | 0) | 0;
+     i9 = 0;
+    }
+    if ((i12 | 0) == 0) {
+     i10 = 1;
+     break;
+    }
+    _lua_pushboolean(i3, 1);
+    _lua_setfield(i3, -1001e3, 96);
+    i10 = 0;
+    break;
+   }
+   i3 = HEAP32[i4 + (0 - i5 << 2) >> 2] | 0;
+   i4 = HEAP32[_stderr >> 2] | 0;
+   HEAP32[i2 >> 2] = HEAP32[20];
+   _fprintf(i4 | 0, 496, i2 | 0) | 0;
+   _fflush(i4 | 0) | 0;
+   i13 = HEAP8[i3 + 1 | 0] | 0;
+   if (i13 << 24 >> 24 == 108 | i13 << 24 >> 24 == 101) {
+    HEAP32[i2 >> 2] = i3;
+    _fprintf(i4 | 0, 504, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+   } else {
+    HEAP32[i2 >> 2] = i3;
+    _fprintf(i4 | 0, 528, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+   }
+   HEAP32[i2 >> 2] = HEAP32[20];
+   _fprintf(i4 | 0, 560, i2 | 0) | 0;
+   _fflush(i4 | 0) | 0;
+   i13 = 0;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+ } while (0);
+ _luaL_checkversion_(i3, 502.0);
+ _lua_gc(i3, 0, 0) | 0;
+ _luaL_openlibs(i3);
+ _lua_gc(i3, 1, 0) | 0;
+ do {
+  if (i10) {
+   i10 = _getenv(409 | 0) | 0;
+   if ((i10 | 0) == 0) {
+    i10 = _getenv(425 | 0) | 0;
+    if ((i10 | 0) == 0) {
+     break;
+    } else {
+     i11 = 424;
+    }
+   } else {
+    i11 = 408;
+   }
+   if ((HEAP8[i10] | 0) == 64) {
+    i13 = _luaL_loadfilex(i3, i10 + 1 | 0, 0) | 0;
+    if ((i13 | 0) == 0) {
+     i12 = _lua_gettop(i3) | 0;
+     _lua_pushcclosure(i3, 142, 0);
+     _lua_insert(i3, i12);
+     HEAP32[48] = i3;
+     _signal(2, 1) | 0;
+     i13 = _lua_pcallk(i3, 0, 0, i12, 0, 0) | 0;
+     _signal(2, 0) | 0;
+     _lua_remove(i3, i12);
+     if ((i13 | 0) == 0) {
+      break;
+     }
+    }
+    if ((_lua_type(i3, -1) | 0) == 0) {
+     i13 = 0;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    i11 = _lua_tolstring(i3, -1, 0) | 0;
+    i12 = HEAP32[20] | 0;
+    i10 = HEAP32[_stderr >> 2] | 0;
+    if ((i12 | 0) != 0) {
+     HEAP32[i2 >> 2] = i12;
+     _fprintf(i10 | 0, 496, i2 | 0) | 0;
+     _fflush(i10 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i11 | 0) == 0 ? 48 : i11;
+    _fprintf(i10 | 0, 912, i2 | 0) | 0;
+    _fflush(i10 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+   } else {
+    i13 = _luaL_loadbufferx(i3, i10, _strlen(i10 | 0) | 0, i11, 0) | 0;
+    if ((i13 | 0) == 0) {
+     i12 = _lua_gettop(i3) | 0;
+     _lua_pushcclosure(i3, 142, 0);
+     _lua_insert(i3, i12);
+     HEAP32[48] = i3;
+     _signal(2, 1) | 0;
+     i13 = _lua_pcallk(i3, 0, 0, i12, 0, 0) | 0;
+     _signal(2, 0) | 0;
+     _lua_remove(i3, i12);
+     if ((i13 | 0) == 0) {
+      break;
+     }
+    }
+    if ((_lua_type(i3, -1) | 0) == 0) {
+     i13 = 0;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    i11 = _lua_tolstring(i3, -1, 0) | 0;
+    i10 = HEAP32[20] | 0;
+    i12 = HEAP32[_stderr >> 2] | 0;
+    if ((i10 | 0) != 0) {
+     HEAP32[i2 >> 2] = i10;
+     _fprintf(i12 | 0, 496, i2 | 0) | 0;
+     _fflush(i12 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i11 | 0) == 0 ? 48 : i11;
+    _fprintf(i12 | 0, 912, i2 | 0) | 0;
+    _fflush(i12 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+   }
+   if ((i13 | 0) != 0) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+ } while (0);
+ i7 = (i5 | 0) > 0 ? i5 : i7;
+ L67 : do {
+  if ((i7 | 0) > 1) {
+   i10 = 1;
+   while (1) {
+    i11 = HEAP32[i4 + (i10 << 2) >> 2] | 0;
+    i12 = HEAP8[i11 + 1 | 0] | 0;
+    if ((i12 | 0) == 108) {
+     i11 = i11 + 2 | 0;
+     if ((HEAP8[i11] | 0) == 0) {
+      i10 = i10 + 1 | 0;
+      i11 = HEAP32[i4 + (i10 << 2) >> 2] | 0;
+     }
+     _lua_getglobal(i3, 400);
+     _lua_pushstring(i3, i11) | 0;
+     i12 = (_lua_gettop(i3) | 0) + -1 | 0;
+     _lua_pushcclosure(i3, 142, 0);
+     _lua_insert(i3, i12);
+     HEAP32[48] = i3;
+     _signal(2, 1) | 0;
+     i13 = _lua_pcallk(i3, 1, 1, i12, 0, 0) | 0;
+     _signal(2, 0) | 0;
+     _lua_remove(i3, i12);
+     if ((i13 | 0) != 0) {
+      i10 = 58;
+      break;
+     }
+     _lua_setglobal(i3, i11);
+    } else if ((i12 | 0) == 101) {
+     i11 = i11 + 2 | 0;
+     if ((HEAP8[i11] | 0) == 0) {
+      i10 = i10 + 1 | 0;
+      i11 = HEAP32[i4 + (i10 << 2) >> 2] | 0;
+     }
+     if ((_luaL_loadbufferx(i3, i11, _strlen(i11 | 0) | 0, 384, 0) | 0) != 0) {
+      i10 = 50;
+      break;
+     }
+     i12 = _lua_gettop(i3) | 0;
+     _lua_pushcclosure(i3, 142, 0);
+     _lua_insert(i3, i12);
+     HEAP32[48] = i3;
+     _signal(2, 1) | 0;
+     i13 = _lua_pcallk(i3, 0, 0, i12, 0, 0) | 0;
+     _signal(2, 0) | 0;
+     _lua_remove(i3, i12);
+     if ((i13 | 0) != 0) {
+      i10 = 50;
+      break;
+     }
+    }
+    i10 = i10 + 1 | 0;
+    if ((i10 | 0) >= (i7 | 0)) {
+     break L67;
+    }
+   }
+   if ((i10 | 0) == 50) {
+    if ((_lua_type(i3, -1) | 0) == 0) {
+     i13 = 0;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    i5 = _lua_tolstring(i3, -1, 0) | 0;
+    i6 = HEAP32[20] | 0;
+    i4 = HEAP32[_stderr >> 2] | 0;
+    if ((i6 | 0) != 0) {
+     HEAP32[i2 >> 2] = i6;
+     _fprintf(i4 | 0, 496, i2 | 0) | 0;
+     _fflush(i4 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i5 | 0) == 0 ? 48 : i5;
+    _fprintf(i4 | 0, 912, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   } else if ((i10 | 0) == 58) {
+    if ((_lua_type(i3, -1) | 0) == 0) {
+     i13 = 0;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    i5 = _lua_tolstring(i3, -1, 0) | 0;
+    i6 = HEAP32[20] | 0;
+    i4 = HEAP32[_stderr >> 2] | 0;
+    if ((i6 | 0) != 0) {
+     HEAP32[i2 >> 2] = i6;
+     _fprintf(i4 | 0, 496, i2 | 0) | 0;
+     _fflush(i4 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i5 | 0) == 0 ? 48 : i5;
+    _fprintf(i4 | 0, 912, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+ } while (0);
+ do {
+  if ((i5 | 0) != 0) {
+   i10 = 0;
+   while (1) {
+    if ((HEAP32[i4 + (i10 << 2) >> 2] | 0) == 0) {
+     break;
+    } else {
+     i10 = i10 + 1 | 0;
+    }
+   }
+   i11 = i5 + 1 | 0;
+   i7 = i10 - i11 | 0;
+   _luaL_checkstack(i3, i7 + 3 | 0, 352);
+   if ((i11 | 0) < (i10 | 0)) {
+    i12 = i11;
+    do {
+     _lua_pushstring(i3, HEAP32[i4 + (i12 << 2) >> 2] | 0) | 0;
+     i12 = i12 + 1 | 0;
+    } while ((i12 | 0) != (i10 | 0));
+   }
+   _lua_createtable(i3, i7, i11);
+   if ((i10 | 0) > 0) {
+    i11 = 0;
+    do {
+     _lua_pushstring(i3, HEAP32[i4 + (i11 << 2) >> 2] | 0) | 0;
+     _lua_rawseti(i3, -2, i11 - i5 | 0);
+     i11 = i11 + 1 | 0;
+    } while ((i11 | 0) != (i10 | 0));
+   }
+   _lua_setglobal(i3, 328);
+   i10 = HEAP32[i4 + (i5 << 2) >> 2] | 0;
+   if ((_strcmp(i10, 336) | 0) == 0) {
+    i13 = (_strcmp(HEAP32[i4 + (i5 + -1 << 2) >> 2] | 0, 344) | 0) == 0;
+    i10 = i13 ? i10 : 0;
+   }
+   i10 = _luaL_loadfilex(i3, i10, 0) | 0;
+   i4 = ~i7;
+   _lua_insert(i3, i4);
+   if ((i10 | 0) == 0) {
+    i13 = (_lua_gettop(i3) | 0) - i7 | 0;
+    _lua_pushcclosure(i3, 142, 0);
+    _lua_insert(i3, i13);
+    HEAP32[48] = i3;
+    _signal(2, 1) | 0;
+    i10 = _lua_pcallk(i3, i7, -1, i13, 0, 0) | 0;
+    _signal(2, 0) | 0;
+    _lua_remove(i3, i13);
+    if ((i10 | 0) == 0) {
+     break;
+    }
+   } else {
+    _lua_settop(i3, i4);
+   }
+   if ((_lua_type(i3, -1) | 0) != 0) {
+    i7 = _lua_tolstring(i3, -1, 0) | 0;
+    i11 = HEAP32[20] | 0;
+    i4 = HEAP32[_stderr >> 2] | 0;
+    if ((i11 | 0) != 0) {
+     HEAP32[i2 >> 2] = i11;
+     _fprintf(i4 | 0, 496, i2 | 0) | 0;
+     _fflush(i4 | 0) | 0;
+    }
+    HEAP32[i2 >> 2] = (i7 | 0) == 0 ? 48 : i7;
+    _fprintf(i4 | 0, 912, i2 | 0) | 0;
+    _fflush(i4 | 0) | 0;
+    _lua_settop(i3, -2);
+    _lua_gc(i3, 2, 0) | 0;
+   }
+   if ((i10 | 0) != 0) {
+    i13 = 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+ } while (0);
+ if ((i6 | 0) == 0) {
+  if (!((i8 | i5 | 0) != 0 | i9 ^ 1)) {
+   i13 = HEAP32[_stdout >> 2] | 0;
+   _fwrite(440, 1, 51, i13 | 0) | 0;
+   _fputc(10, i13 | 0) | 0;
+   _fflush(i13 | 0) | 0;
+   _dotty(i3);
+  }
+ } else {
+  _dotty(i3);
+ }
+ _lua_pushboolean(i3, 1);
+ i13 = 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _DumpFunction(i6, i2) {
+ i6 = i6 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i17 = i5 + 56 | 0;
+ i19 = i5 + 52 | 0;
+ i20 = i5 + 48 | 0;
+ i18 = i5;
+ i21 = i5 + 60 | 0;
+ i22 = i5 + 44 | 0;
+ i1 = i5 + 40 | 0;
+ i16 = i5 + 36 | 0;
+ i23 = i5 + 32 | 0;
+ i3 = i5 + 28 | 0;
+ i7 = i5 + 24 | 0;
+ i8 = i5 + 20 | 0;
+ i9 = i5 + 16 | 0;
+ i10 = i5 + 12 | 0;
+ i12 = i5 + 8 | 0;
+ HEAP32[i17 >> 2] = HEAP32[i6 + 64 >> 2];
+ i4 = i2 + 16 | 0;
+ i28 = HEAP32[i4 >> 2] | 0;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ HEAP32[i17 >> 2] = HEAP32[i6 + 68 >> 2];
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ HEAP8[i17] = HEAP8[i6 + 76 | 0] | 0;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 1, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ HEAP8[i17] = HEAP8[i6 + 77 | 0] | 0;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 1, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ HEAP8[i17] = HEAP8[i6 + 78 | 0] | 0;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 1, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ i25 = HEAP32[i6 + 12 >> 2] | 0;
+ i24 = HEAP32[i6 + 48 >> 2] | 0;
+ HEAP32[i23 >> 2] = i24;
+ if ((i28 | 0) == 0) {
+  i26 = i2 + 4 | 0;
+  i27 = i2 + 8 | 0;
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i26 >> 2] & 3](HEAP32[i2 >> 2] | 0, i23, 4, HEAP32[i27 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+  if ((i28 | 0) == 0) {
+   i28 = FUNCTION_TABLE_iiiii[HEAP32[i26 >> 2] & 3](HEAP32[i2 >> 2] | 0, i25, i24 << 2, HEAP32[i27 >> 2] | 0) | 0;
+   HEAP32[i4 >> 2] = i28;
+   i25 = HEAP32[i6 + 44 >> 2] | 0;
+   HEAP32[i22 >> 2] = i25;
+   if ((i28 | 0) == 0) {
+    i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i22, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i28;
+   }
+  } else {
+   i11 = 13;
+  }
+ } else {
+  i11 = 13;
+ }
+ if ((i11 | 0) == 13) {
+  i25 = HEAP32[i6 + 44 >> 2] | 0;
+  HEAP32[i22 >> 2] = i25;
+ }
+ if ((i25 | 0) > 0) {
+  i24 = i6 + 8 | 0;
+  i23 = i2 + 4 | 0;
+  i22 = i2 + 8 | 0;
+  i26 = 0;
+  do {
+   i30 = HEAP32[i24 >> 2] | 0;
+   i27 = i30 + (i26 << 4) | 0;
+   i30 = i30 + (i26 << 4) + 8 | 0;
+   i29 = HEAP32[i30 >> 2] | 0;
+   HEAP8[i17] = i29 & 15;
+   if ((i28 | 0) == 0) {
+    i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 1, HEAP32[i22 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i28;
+    i29 = HEAP32[i30 >> 2] | 0;
+   }
+   i29 = i29 & 15;
+   do {
+    if ((i29 | 0) == 3) {
+     HEAPF64[i18 >> 3] = +HEAPF64[i27 >> 3];
+     if ((i28 | 0) == 0) {
+      i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i18, 8, HEAP32[i22 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i28;
+     }
+    } else if ((i29 | 0) == 1) {
+     HEAP8[i21] = HEAP32[i27 >> 2];
+     if ((i28 | 0) == 0) {
+      i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i21, 1, HEAP32[i22 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i28;
+     }
+    } else if ((i29 | 0) == 4) {
+     i27 = HEAP32[i27 >> 2] | 0;
+     if ((i27 | 0) == 0) {
+      HEAP32[i19 >> 2] = 0;
+      if ((i28 | 0) != 0) {
+       break;
+      }
+      i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i19, 4, HEAP32[i22 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i28;
+      break;
+     }
+     HEAP32[i20 >> 2] = (HEAP32[i27 + 12 >> 2] | 0) + 1;
+     if ((i28 | 0) == 0) {
+      i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i20, 4, HEAP32[i22 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i28;
+      if ((i28 | 0) == 0) {
+       i28 = FUNCTION_TABLE_iiiii[HEAP32[i23 >> 2] & 3](HEAP32[i2 >> 2] | 0, i27 + 16 | 0, HEAP32[i20 >> 2] | 0, HEAP32[i22 >> 2] | 0) | 0;
+       HEAP32[i4 >> 2] = i28;
+      }
+     }
+    }
+   } while (0);
+   i26 = i26 + 1 | 0;
+  } while ((i26 | 0) != (i25 | 0));
+ }
+ i18 = HEAP32[i6 + 56 >> 2] | 0;
+ HEAP32[i17 >> 2] = i18;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i17, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ if ((i18 | 0) > 0) {
+  i17 = i6 + 16 | 0;
+  i19 = 0;
+  do {
+   _DumpFunction(HEAP32[(HEAP32[i17 >> 2] | 0) + (i19 << 2) >> 2] | 0, i2);
+   i19 = i19 + 1 | 0;
+  } while ((i19 | 0) != (i18 | 0));
+  i28 = HEAP32[i4 >> 2] | 0;
+ }
+ i17 = i6 + 40 | 0;
+ i18 = HEAP32[i17 >> 2] | 0;
+ HEAP32[i16 >> 2] = i18;
+ if ((i28 | 0) == 0) {
+  i28 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i16, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i28;
+ }
+ if ((i18 | 0) > 0) {
+  i19 = i6 + 28 | 0;
+  i16 = i2 + 4 | 0;
+  i20 = i2 + 8 | 0;
+  i21 = 0;
+  do {
+   i22 = HEAP32[i19 >> 2] | 0;
+   HEAP8[i1] = HEAP8[i22 + (i21 << 3) + 4 | 0] | 0;
+   if ((i28 | 0) == 0) {
+    i28 = FUNCTION_TABLE_iiiii[HEAP32[i16 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 1, HEAP32[i20 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i28;
+    i22 = HEAP32[i19 >> 2] | 0;
+   }
+   HEAP8[i1] = HEAP8[i22 + (i21 << 3) + 5 | 0] | 0;
+   if ((i28 | 0) == 0) {
+    i28 = FUNCTION_TABLE_iiiii[HEAP32[i16 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 1, HEAP32[i20 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i28;
+   }
+   i21 = i21 + 1 | 0;
+  } while ((i21 | 0) != (i18 | 0));
+ }
+ i16 = i2 + 12 | 0;
+ if ((HEAP32[i16 >> 2] | 0) == 0 ? (i13 = HEAP32[i6 + 36 >> 2] | 0, (i13 | 0) != 0) : 0) {
+  HEAP32[i12 >> 2] = (HEAP32[i13 + 12 >> 2] | 0) + 1;
+  if ((i28 | 0) == 0 ? (i14 = i2 + 4 | 0, i15 = i2 + 8 | 0, i30 = FUNCTION_TABLE_iiiii[HEAP32[i14 >> 2] & 3](HEAP32[i2 >> 2] | 0, i12, 4, HEAP32[i15 >> 2] | 0) | 0, HEAP32[i4 >> 2] = i30, (i30 | 0) == 0) : 0) {
+   HEAP32[i4 >> 2] = FUNCTION_TABLE_iiiii[HEAP32[i14 >> 2] & 3](HEAP32[i2 >> 2] | 0, i13 + 16 | 0, HEAP32[i12 >> 2] | 0, HEAP32[i15 >> 2] | 0) | 0;
+  }
+ } else {
+  i12 = i10;
+  i11 = 50;
+ }
+ if ((i11 | 0) == 50) {
+  HEAP32[i10 >> 2] = 0;
+  if ((i28 | 0) == 0) {
+   HEAP32[i4 >> 2] = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i12, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  }
+ }
+ if ((HEAP32[i16 >> 2] | 0) == 0) {
+  i11 = HEAP32[i6 + 52 >> 2] | 0;
+ } else {
+  i11 = 0;
+ }
+ i10 = HEAP32[i6 + 20 >> 2] | 0;
+ HEAP32[i9 >> 2] = i11;
+ i14 = HEAP32[i4 >> 2] | 0;
+ if ((i14 | 0) == 0) {
+  i12 = i2 + 4 | 0;
+  i13 = i2 + 8 | 0;
+  i14 = FUNCTION_TABLE_iiiii[HEAP32[i12 >> 2] & 3](HEAP32[i2 >> 2] | 0, i9, 4, HEAP32[i13 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i14;
+  if ((i14 | 0) == 0) {
+   i14 = FUNCTION_TABLE_iiiii[HEAP32[i12 >> 2] & 3](HEAP32[i2 >> 2] | 0, i10, i11 << 2, HEAP32[i13 >> 2] | 0) | 0;
+   HEAP32[i4 >> 2] = i14;
+  }
+ }
+ if ((HEAP32[i16 >> 2] | 0) == 0) {
+  i9 = HEAP32[i6 + 60 >> 2] | 0;
+ } else {
+  i9 = 0;
+ }
+ HEAP32[i8 >> 2] = i9;
+ if ((i14 | 0) == 0) {
+  i14 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i8, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i14;
+ }
+ if ((i9 | 0) > 0) {
+  i10 = i6 + 24 | 0;
+  i11 = i2 + 4 | 0;
+  i8 = i2 + 8 | 0;
+  i12 = 0;
+  do {
+   i13 = HEAP32[(HEAP32[i10 >> 2] | 0) + (i12 * 12 | 0) >> 2] | 0;
+   if ((i13 | 0) == 0) {
+    HEAP32[i1 >> 2] = 0;
+    if ((i14 | 0) == 0) {
+     i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 4, HEAP32[i8 >> 2] | 0) | 0;
+     HEAP32[i4 >> 2] = i14;
+    }
+   } else {
+    HEAP32[i3 >> 2] = (HEAP32[i13 + 12 >> 2] | 0) + 1;
+    if ((i14 | 0) == 0) {
+     i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i3, 4, HEAP32[i8 >> 2] | 0) | 0;
+     HEAP32[i4 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i13 + 16 | 0, HEAP32[i3 >> 2] | 0, HEAP32[i8 >> 2] | 0) | 0;
+      HEAP32[i4 >> 2] = i14;
+     }
+    }
+   }
+   i13 = HEAP32[i10 >> 2] | 0;
+   HEAP32[i1 >> 2] = HEAP32[i13 + (i12 * 12 | 0) + 4 >> 2];
+   if ((i14 | 0) == 0) {
+    i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 4, HEAP32[i8 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i14;
+    i13 = HEAP32[i10 >> 2] | 0;
+   }
+   HEAP32[i1 >> 2] = HEAP32[i13 + (i12 * 12 | 0) + 8 >> 2];
+   if ((i14 | 0) == 0) {
+    i14 = FUNCTION_TABLE_iiiii[HEAP32[i11 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 4, HEAP32[i8 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i14;
+   }
+   i12 = i12 + 1 | 0;
+  } while ((i12 | 0) != (i9 | 0));
+ }
+ if ((HEAP32[i16 >> 2] | 0) == 0) {
+  i8 = HEAP32[i17 >> 2] | 0;
+ } else {
+  i8 = 0;
+ }
+ HEAP32[i7 >> 2] = i8;
+ if ((i14 | 0) == 0) {
+  i14 = FUNCTION_TABLE_iiiii[HEAP32[i2 + 4 >> 2] & 3](HEAP32[i2 >> 2] | 0, i7, 4, HEAP32[i2 + 8 >> 2] | 0) | 0;
+  HEAP32[i4 >> 2] = i14;
+ }
+ if ((i8 | 0) <= 0) {
+  STACKTOP = i5;
+  return;
+ }
+ i7 = i6 + 28 | 0;
+ i6 = i2 + 4 | 0;
+ i9 = i2 + 8 | 0;
+ i10 = 0;
+ do {
+  i11 = HEAP32[(HEAP32[i7 >> 2] | 0) + (i10 << 3) >> 2] | 0;
+  if ((i11 | 0) == 0) {
+   HEAP32[i1 >> 2] = 0;
+   if ((i14 | 0) == 0) {
+    i14 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i2 >> 2] | 0, i1, 4, HEAP32[i9 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i14;
+   }
+  } else {
+   HEAP32[i3 >> 2] = (HEAP32[i11 + 12 >> 2] | 0) + 1;
+   if ((i14 | 0) == 0) {
+    i14 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i2 >> 2] | 0, i3, 4, HEAP32[i9 >> 2] | 0) | 0;
+    HEAP32[i4 >> 2] = i14;
+    if ((i14 | 0) == 0) {
+     i14 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i2 >> 2] | 0, i11 + 16 | 0, HEAP32[i3 >> 2] | 0, HEAP32[i9 >> 2] | 0) | 0;
+     HEAP32[i4 >> 2] = i14;
+    }
+   }
+  }
+  i10 = i10 + 1 | 0;
+ } while ((i10 | 0) != (i8 | 0));
+ STACKTOP = i5;
+ return;
+}
+function _LoadFunction(i2, i6) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ i5 = i1 + 8 | 0;
+ i4 = i2 + 4 | 0;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ HEAP32[i6 + 64 >> 2] = i8;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ HEAP32[i6 + 68 >> 2] = i8;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ HEAP8[i6 + 76 | 0] = HEAP8[i3] | 0;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ HEAP8[i6 + 77 | 0] = HEAP8[i3] | 0;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ HEAP8[i6 + 78 | 0] = HEAP8[i3] | 0;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i9 = HEAP32[i3 >> 2] | 0;
+ if ((i9 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i8 = HEAP32[i2 >> 2] | 0;
+ if ((i9 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i8);
+ }
+ i14 = i9 << 2;
+ i13 = _luaM_realloc_(i8, 0, 0, i14) | 0;
+ HEAP32[i6 + 12 >> 2] = i13;
+ HEAP32[i6 + 48 >> 2] = i9;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i13, i14) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i9 = HEAP32[i2 >> 2] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 268435455) {
+  _luaM_toobig(i9);
+ }
+ i11 = _luaM_realloc_(i9, 0, 0, i8 << 4) | 0;
+ i9 = i6 + 8 | 0;
+ HEAP32[i9 >> 2] = i11;
+ HEAP32[i6 + 44 >> 2] = i8;
+ i12 = (i8 | 0) > 0;
+ L43 : do {
+  if (i12) {
+   i10 = 0;
+   do {
+    HEAP32[i11 + (i10 << 4) + 8 >> 2] = 0;
+    i10 = i10 + 1 | 0;
+   } while ((i10 | 0) != (i8 | 0));
+   if (i12) {
+    i10 = i2 + 8 | 0;
+    i13 = 0;
+    while (1) {
+     i12 = i11 + (i13 << 4) | 0;
+     if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+      i9 = 34;
+      break;
+     }
+     i14 = HEAP8[i3] | 0;
+     if ((i14 | 0) == 4) {
+      if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+       i9 = 44;
+       break;
+      }
+      i14 = HEAP32[i3 >> 2] | 0;
+      if ((i14 | 0) == 0) {
+       i14 = 0;
+      } else {
+       i14 = _luaZ_openspace(HEAP32[i2 >> 2] | 0, HEAP32[i10 >> 2] | 0, i14) | 0;
+       if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i14, HEAP32[i3 >> 2] | 0) | 0) != 0) {
+        i9 = 47;
+        break;
+       }
+       i14 = _luaS_newlstr(HEAP32[i2 >> 2] | 0, i14, (HEAP32[i3 >> 2] | 0) + -1 | 0) | 0;
+      }
+      HEAP32[i12 >> 2] = i14;
+      HEAP32[i11 + (i13 << 4) + 8 >> 2] = HEAPU8[i14 + 4 | 0] | 64;
+     } else if ((i14 | 0) == 1) {
+      if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+       i9 = 38;
+       break;
+      }
+      HEAP32[i12 >> 2] = HEAP8[i3] | 0;
+      HEAP32[i11 + (i13 << 4) + 8 >> 2] = 1;
+     } else if ((i14 | 0) == 3) {
+      if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 8) | 0) != 0) {
+       i9 = 41;
+       break;
+      }
+      HEAPF64[i12 >> 3] = +HEAPF64[i3 >> 3];
+      HEAP32[i11 + (i13 << 4) + 8 >> 2] = 3;
+     } else if ((i14 | 0) == 0) {
+      HEAP32[i11 + (i13 << 4) + 8 >> 2] = 0;
+     }
+     i13 = i13 + 1 | 0;
+     if ((i13 | 0) >= (i8 | 0)) {
+      break L43;
+     }
+     i11 = HEAP32[i9 >> 2] | 0;
+    }
+    if ((i9 | 0) == 34) {
+     _error(i2, 8824);
+    } else if ((i9 | 0) == 38) {
+     _error(i2, 8824);
+    } else if ((i9 | 0) == 41) {
+     _error(i2, 8824);
+    } else if ((i9 | 0) == 44) {
+     _error(i2, 8824);
+    } else if ((i9 | 0) == 47) {
+     _error(i2, 8824);
+    }
+   }
+  }
+ } while (0);
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i9 = HEAP32[i2 >> 2] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i9);
+ }
+ i11 = _luaM_realloc_(i9, 0, 0, i8 << 2) | 0;
+ i9 = i6 + 16 | 0;
+ HEAP32[i9 >> 2] = i11;
+ HEAP32[i6 + 56 >> 2] = i8;
+ i10 = (i8 | 0) > 0;
+ if (i10) {
+  i12 = 0;
+  while (1) {
+   HEAP32[i11 + (i12 << 2) >> 2] = 0;
+   i12 = i12 + 1 | 0;
+   if ((i12 | 0) == (i8 | 0)) {
+    break;
+   }
+   i11 = HEAP32[i9 >> 2] | 0;
+  }
+  if (i10) {
+   i10 = 0;
+   do {
+    i14 = _luaF_newproto(HEAP32[i2 >> 2] | 0) | 0;
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 << 2) >> 2] = i14;
+    _LoadFunction(i2, HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 << 2) >> 2] | 0);
+    i10 = i10 + 1 | 0;
+   } while ((i10 | 0) != (i8 | 0));
+  }
+ }
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i9 = HEAP32[i3 >> 2] | 0;
+ if ((i9 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i8 = HEAP32[i2 >> 2] | 0;
+ if ((i9 + 1 | 0) >>> 0 > 536870911) {
+  _luaM_toobig(i8);
+ }
+ i10 = _luaM_realloc_(i8, 0, 0, i9 << 3) | 0;
+ i8 = i6 + 28 | 0;
+ HEAP32[i8 >> 2] = i10;
+ HEAP32[i6 + 40 >> 2] = i9;
+ L98 : do {
+  if ((i9 | 0) > 0) {
+   HEAP32[i10 >> 2] = 0;
+   if ((i9 | 0) == 1) {
+    i10 = 0;
+   } else {
+    i10 = 1;
+    while (1) {
+     HEAP32[(HEAP32[i8 >> 2] | 0) + (i10 << 3) >> 2] = 0;
+     i10 = i10 + 1 | 0;
+     if ((i10 | 0) == (i9 | 0)) {
+      i10 = 0;
+      break;
+     }
+    }
+   }
+   while (1) {
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+     i9 = 73;
+     break;
+    }
+    HEAP8[(HEAP32[i8 >> 2] | 0) + (i10 << 3) + 4 | 0] = HEAP8[i3] | 0;
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 1) | 0) != 0) {
+     i9 = 75;
+     break;
+    }
+    HEAP8[(HEAP32[i8 >> 2] | 0) + (i10 << 3) + 5 | 0] = HEAP8[i3] | 0;
+    i10 = i10 + 1 | 0;
+    if ((i10 | 0) >= (i9 | 0)) {
+     break L98;
+    }
+   }
+   if ((i9 | 0) == 73) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 75) {
+    _error(i2, 8824);
+   }
+  }
+ } while (0);
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i9 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i9 | 0) != 0) {
+   i9 = _luaZ_openspace(HEAP32[i2 >> 2] | 0, HEAP32[i2 + 8 >> 2] | 0, i9) | 0;
+   if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i9, HEAP32[i3 >> 2] | 0) | 0) == 0) {
+    i7 = _luaS_newlstr(HEAP32[i2 >> 2] | 0, i9, (HEAP32[i3 >> 2] | 0) + -1 | 0) | 0;
+    break;
+   } else {
+    _error(i2, 8824);
+   }
+  } else {
+   i7 = 0;
+  }
+ } while (0);
+ HEAP32[i6 + 36 >> 2] = i7;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i7 = HEAP32[i3 >> 2] | 0;
+ if ((i7 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i9 = HEAP32[i2 >> 2] | 0;
+ if ((i7 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i9);
+ }
+ i14 = i7 << 2;
+ i13 = _luaM_realloc_(i9, 0, 0, i14) | 0;
+ HEAP32[i6 + 20 >> 2] = i13;
+ HEAP32[i6 + 52 >> 2] = i7;
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i13, i14) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i7 = HEAP32[i3 >> 2] | 0;
+ if ((i7 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ i9 = HEAP32[i2 >> 2] | 0;
+ if ((i7 + 1 | 0) >>> 0 > 357913941) {
+  _luaM_toobig(i9);
+ }
+ i10 = _luaM_realloc_(i9, 0, 0, i7 * 12 | 0) | 0;
+ i9 = i6 + 24 | 0;
+ HEAP32[i9 >> 2] = i10;
+ HEAP32[i6 + 60 >> 2] = i7;
+ L141 : do {
+  if ((i7 | 0) > 0) {
+   HEAP32[i10 >> 2] = 0;
+   if ((i7 | 0) != 1) {
+    i6 = 1;
+    do {
+     HEAP32[(HEAP32[i9 >> 2] | 0) + (i6 * 12 | 0) >> 2] = 0;
+     i6 = i6 + 1 | 0;
+    } while ((i6 | 0) != (i7 | 0));
+   }
+   i6 = i2 + 8 | 0;
+   i10 = 0;
+   while (1) {
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+     i9 = 102;
+     break;
+    }
+    i11 = HEAP32[i3 >> 2] | 0;
+    if ((i11 | 0) == 0) {
+     i11 = 0;
+    } else {
+     i11 = _luaZ_openspace(HEAP32[i2 >> 2] | 0, HEAP32[i6 >> 2] | 0, i11) | 0;
+     if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i11, HEAP32[i3 >> 2] | 0) | 0) != 0) {
+      i9 = 105;
+      break;
+     }
+     i11 = _luaS_newlstr(HEAP32[i2 >> 2] | 0, i11, (HEAP32[i3 >> 2] | 0) + -1 | 0) | 0;
+    }
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 * 12 | 0) >> 2] = i11;
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+     i9 = 108;
+     break;
+    }
+    i11 = HEAP32[i3 >> 2] | 0;
+    if ((i11 | 0) < 0) {
+     i9 = 110;
+     break;
+    }
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 * 12 | 0) + 4 >> 2] = i11;
+    if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+     i9 = 112;
+     break;
+    }
+    i11 = HEAP32[i3 >> 2] | 0;
+    if ((i11 | 0) < 0) {
+     i9 = 114;
+     break;
+    }
+    HEAP32[(HEAP32[i9 >> 2] | 0) + (i10 * 12 | 0) + 8 >> 2] = i11;
+    i10 = i10 + 1 | 0;
+    if ((i10 | 0) >= (i7 | 0)) {
+     break L141;
+    }
+   }
+   if ((i9 | 0) == 102) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 105) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 108) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 110) {
+    _error(i2, 8872);
+   } else if ((i9 | 0) == 112) {
+    _error(i2, 8824);
+   } else if ((i9 | 0) == 114) {
+    _error(i2, 8872);
+   }
+  }
+ } while (0);
+ if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i5, 4) | 0) != 0) {
+  _error(i2, 8824);
+ }
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) < 0) {
+  _error(i2, 8872);
+ }
+ if ((i6 | 0) <= 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i2 + 8 | 0;
+ i7 = 0;
+ while (1) {
+  if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i3, 4) | 0) != 0) {
+   i9 = 123;
+   break;
+  }
+  i9 = HEAP32[i3 >> 2] | 0;
+  if ((i9 | 0) == 0) {
+   i9 = 0;
+  } else {
+   i9 = _luaZ_openspace(HEAP32[i2 >> 2] | 0, HEAP32[i5 >> 2] | 0, i9) | 0;
+   if ((_luaZ_read(HEAP32[i4 >> 2] | 0, i9, HEAP32[i3 >> 2] | 0) | 0) != 0) {
+    i9 = 126;
+    break;
+   }
+   i9 = _luaS_newlstr(HEAP32[i2 >> 2] | 0, i9, (HEAP32[i3 >> 2] | 0) + -1 | 0) | 0;
+  }
+  HEAP32[(HEAP32[i8 >> 2] | 0) + (i7 << 3) >> 2] = i9;
+  i7 = i7 + 1 | 0;
+  if ((i7 | 0) >= (i6 | 0)) {
+   i9 = 129;
+   break;
+  }
+ }
+ if ((i9 | 0) == 123) {
+  _error(i2, 8824);
+ } else if ((i9 | 0) == 126) {
+  _error(i2, 8824);
+ } else if ((i9 | 0) == 129) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _exp2reg(i4, i1, i7) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0;
+ i5 = STACKTOP;
+ _discharge2reg(i4, i1, i7);
+ i6 = i1 + 16 | 0;
+ do {
+  if ((HEAP32[i1 >> 2] | 0) == 10 ? (i10 = HEAP32[i1 + 8 >> 2] | 0, !((i10 | 0) == -1)) : 0) {
+   i22 = HEAP32[i6 >> 2] | 0;
+   if ((i22 | 0) == -1) {
+    HEAP32[i6 >> 2] = i10;
+    break;
+   }
+   i20 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i19 = i20 + (i22 << 2) | 0;
+    i21 = HEAP32[i19 >> 2] | 0;
+    i23 = (i21 >>> 14) + -131071 | 0;
+    if ((i23 | 0) == -1) {
+     break;
+    }
+    i23 = i22 + 1 + i23 | 0;
+    if ((i23 | 0) == -1) {
+     break;
+    } else {
+     i22 = i23;
+    }
+   }
+   i10 = i10 + ~i22 | 0;
+   if ((((i10 | 0) > -1 ? i10 : 0 - i10 | 0) | 0) > 131071) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   } else {
+    HEAP32[i19 >> 2] = (i10 << 14) + 2147467264 | i21 & 16383;
+    break;
+   }
+  }
+ } while (0);
+ i21 = HEAP32[i6 >> 2] | 0;
+ i10 = i1 + 20 | 0;
+ i19 = HEAP32[i10 >> 2] | 0;
+ if ((i21 | 0) == (i19 | 0)) {
+  HEAP32[i6 >> 2] = -1;
+  HEAP32[i10 >> 2] = -1;
+  i25 = i1 + 8 | 0;
+  HEAP32[i25 >> 2] = i7;
+  HEAP32[i1 >> 2] = 6;
+  STACKTOP = i5;
+  return;
+ }
+ L18 : do {
+  if ((i21 | 0) == -1) {
+   i18 = 20;
+  } else {
+   i20 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i23 = i20 + (i21 << 2) | 0;
+    if ((i21 | 0) > 0 ? (i18 = HEAP32[i20 + (i21 + -1 << 2) >> 2] | 0, (HEAP8[5584 + (i18 & 63) | 0] | 0) < 0) : 0) {
+     i22 = i18;
+    } else {
+     i22 = HEAP32[i23 >> 2] | 0;
+    }
+    if ((i22 & 63 | 0) != 28) {
+     i18 = 28;
+     break L18;
+    }
+    i22 = ((HEAP32[i23 >> 2] | 0) >>> 14) + -131071 | 0;
+    if ((i22 | 0) == -1) {
+     i18 = 20;
+     break L18;
+    }
+    i21 = i21 + 1 + i22 | 0;
+    if ((i21 | 0) == -1) {
+     i18 = 20;
+     break;
+    }
+   }
+  }
+ } while (0);
+ L29 : do {
+  if ((i18 | 0) == 20) {
+   if ((i19 | 0) == -1) {
+    i15 = -1;
+    i8 = -1;
+   } else {
+    i20 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+    while (1) {
+     i21 = i20 + (i19 << 2) | 0;
+     if ((i19 | 0) > 0 ? (i17 = HEAP32[i20 + (i19 + -1 << 2) >> 2] | 0, (HEAP8[5584 + (i17 & 63) | 0] | 0) < 0) : 0) {
+      i22 = i17;
+     } else {
+      i22 = HEAP32[i21 >> 2] | 0;
+     }
+     if ((i22 & 63 | 0) != 28) {
+      i18 = 28;
+      break L29;
+     }
+     i21 = ((HEAP32[i21 >> 2] | 0) >>> 14) + -131071 | 0;
+     if ((i21 | 0) == -1) {
+      i15 = -1;
+      i8 = -1;
+      break L29;
+     }
+     i19 = i19 + 1 + i21 | 0;
+     if ((i19 | 0) == -1) {
+      i15 = -1;
+      i8 = -1;
+      break;
+     }
+    }
+   }
+  }
+ } while (0);
+ do {
+  if ((i18 | 0) == 28) {
+   i17 = i4 + 28 | 0;
+   do {
+    if ((HEAP32[i1 >> 2] | 0) != 10) {
+     i21 = HEAP32[i17 >> 2] | 0;
+     HEAP32[i17 >> 2] = -1;
+     i18 = _luaK_code(i4, 2147450903) | 0;
+     if (!((i21 | 0) == -1)) {
+      if (!((i18 | 0) == -1)) {
+       i23 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+       i22 = i18;
+       while (1) {
+        i20 = i23 + (i22 << 2) | 0;
+        i19 = HEAP32[i20 >> 2] | 0;
+        i24 = (i19 >>> 14) + -131071 | 0;
+        if ((i24 | 0) == -1) {
+         break;
+        }
+        i24 = i22 + 1 + i24 | 0;
+        if ((i24 | 0) == -1) {
+         break;
+        } else {
+         i22 = i24;
+        }
+       }
+       i21 = i21 + ~i22 | 0;
+       if ((((i21 | 0) > -1 ? i21 : 0 - i21 | 0) | 0) > 131071) {
+        _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+       } else {
+        HEAP32[i20 >> 2] = (i21 << 14) + 2147467264 | i19 & 16383;
+        i16 = i18;
+        break;
+       }
+      } else {
+       i16 = i21;
+      }
+     } else {
+      i16 = i18;
+     }
+    } else {
+     i16 = -1;
+    }
+   } while (0);
+   i24 = i4 + 20 | 0;
+   i25 = i4 + 24 | 0;
+   HEAP32[i25 >> 2] = HEAP32[i24 >> 2];
+   i19 = i7 << 6;
+   i18 = _luaK_code(i4, i19 | 16387) | 0;
+   HEAP32[i25 >> 2] = HEAP32[i24 >> 2];
+   i19 = _luaK_code(i4, i19 | 8388611) | 0;
+   HEAP32[i25 >> 2] = HEAP32[i24 >> 2];
+   if (!((i16 | 0) == -1)) {
+    i22 = HEAP32[i17 >> 2] | 0;
+    if ((i22 | 0) == -1) {
+     HEAP32[i17 >> 2] = i16;
+     i15 = i18;
+     i8 = i19;
+     break;
+    }
+    i17 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+    while (1) {
+     i21 = i17 + (i22 << 2) | 0;
+     i20 = HEAP32[i21 >> 2] | 0;
+     i23 = (i20 >>> 14) + -131071 | 0;
+     if ((i23 | 0) == -1) {
+      break;
+     }
+     i23 = i22 + 1 + i23 | 0;
+     if ((i23 | 0) == -1) {
+      break;
+     } else {
+      i22 = i23;
+     }
+    }
+    i16 = i16 + ~i22 | 0;
+    if ((((i16 | 0) > -1 ? i16 : 0 - i16 | 0) | 0) > 131071) {
+     _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+    } else {
+     HEAP32[i21 >> 2] = (i16 << 14) + 2147467264 | i20 & 16383;
+     i15 = i18;
+     i8 = i19;
+     break;
+    }
+   } else {
+    i15 = i18;
+    i8 = i19;
+   }
+  }
+ } while (0);
+ i16 = HEAP32[i4 + 20 >> 2] | 0;
+ HEAP32[i4 + 24 >> 2] = i16;
+ i22 = HEAP32[i10 >> 2] | 0;
+ L67 : do {
+  if (!((i22 | 0) == -1)) {
+   i19 = (i7 | 0) == 255;
+   i17 = i7 << 6 & 16320;
+   i18 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i20 = i18 + (i22 << 2) | 0;
+    i23 = HEAP32[i20 >> 2] | 0;
+    i21 = (i23 >>> 14) + -131071 | 0;
+    if ((i21 | 0) == -1) {
+     i21 = -1;
+    } else {
+     i21 = i22 + 1 + i21 | 0;
+    }
+    if ((i22 | 0) > 0 ? (i14 = i18 + (i22 + -1 << 2) | 0, i13 = HEAP32[i14 >> 2] | 0, (HEAP8[5584 + (i13 & 63) | 0] | 0) < 0) : 0) {
+     i24 = i14;
+     i25 = i13;
+    } else {
+     i24 = i20;
+     i25 = i23;
+    }
+    if ((i25 & 63 | 0) == 28) {
+     i23 = i25 >>> 23;
+     if (i19 | (i23 | 0) == (i7 | 0)) {
+      i23 = i25 & 8372224 | i23 << 6 | 27;
+     } else {
+      i23 = i25 & -16321 | i17;
+     }
+     HEAP32[i24 >> 2] = i23;
+     i22 = i16 + ~i22 | 0;
+     if ((((i22 | 0) > -1 ? i22 : 0 - i22 | 0) | 0) > 131071) {
+      i18 = 58;
+      break;
+     }
+     i22 = HEAP32[i20 >> 2] & 16383 | (i22 << 14) + 2147467264;
+    } else {
+     i22 = i15 + ~i22 | 0;
+     if ((((i22 | 0) > -1 ? i22 : 0 - i22 | 0) | 0) > 131071) {
+      i18 = 61;
+      break;
+     }
+     i22 = i23 & 16383 | (i22 << 14) + 2147467264;
+    }
+    HEAP32[i20 >> 2] = i22;
+    if ((i21 | 0) == -1) {
+     break L67;
+    } else {
+     i22 = i21;
+    }
+   }
+   if ((i18 | 0) == 58) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   } else if ((i18 | 0) == 61) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   }
+  }
+ } while (0);
+ i20 = HEAP32[i6 >> 2] | 0;
+ if ((i20 | 0) == -1) {
+  HEAP32[i6 >> 2] = -1;
+  HEAP32[i10 >> 2] = -1;
+  i25 = i1 + 8 | 0;
+  HEAP32[i25 >> 2] = i7;
+  HEAP32[i1 >> 2] = 6;
+  STACKTOP = i5;
+  return;
+ }
+ i13 = i7 << 6;
+ i15 = i13 & 16320;
+ i14 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+ if ((i7 | 0) == 255) {
+  while (1) {
+   i17 = i14 + (i20 << 2) | 0;
+   i19 = HEAP32[i17 >> 2] | 0;
+   i18 = (i19 >>> 14) + -131071 | 0;
+   if ((i18 | 0) == -1) {
+    i18 = -1;
+   } else {
+    i18 = i20 + 1 + i18 | 0;
+   }
+   if ((i20 | 0) > 0 ? (i12 = i14 + (i20 + -1 << 2) | 0, i11 = HEAP32[i12 >> 2] | 0, (HEAP8[5584 + (i11 & 63) | 0] | 0) < 0) : 0) {
+    i22 = i12;
+    i21 = i11;
+   } else {
+    i22 = i17;
+    i21 = i19;
+   }
+   if ((i21 & 63 | 0) == 28) {
+    HEAP32[i22 >> 2] = i21 & 8372224 | i21 >>> 23 << 6 | 27;
+    i19 = i16 + ~i20 | 0;
+    if ((((i19 | 0) > -1 ? i19 : 0 - i19 | 0) | 0) > 131071) {
+     i18 = 87;
+     break;
+    }
+    i19 = HEAP32[i17 >> 2] & 16383 | (i19 << 14) + 2147467264;
+   } else {
+    i20 = i8 + ~i20 | 0;
+    if ((((i20 | 0) > -1 ? i20 : 0 - i20 | 0) | 0) > 131071) {
+     i18 = 90;
+     break;
+    }
+    i19 = i19 & 16383 | (i20 << 14) + 2147467264;
+   }
+   HEAP32[i17 >> 2] = i19;
+   if ((i18 | 0) == -1) {
+    i18 = 93;
+    break;
+   } else {
+    i20 = i18;
+   }
+  }
+  if ((i18 | 0) == 87) {
+   i25 = i4 + 12 | 0;
+   i25 = HEAP32[i25 >> 2] | 0;
+   _luaX_syntaxerror(i25, 10624);
+  } else if ((i18 | 0) == 90) {
+   i25 = i4 + 12 | 0;
+   i25 = HEAP32[i25 >> 2] | 0;
+   _luaX_syntaxerror(i25, 10624);
+  } else if ((i18 | 0) == 93) {
+   HEAP32[i6 >> 2] = -1;
+   HEAP32[i10 >> 2] = -1;
+   i25 = i1 + 8 | 0;
+   HEAP32[i25 >> 2] = i7;
+   HEAP32[i1 >> 2] = 6;
+   STACKTOP = i5;
+   return;
+  }
+ } else {
+  i9 = i20;
+ }
+ while (1) {
+  i11 = i14 + (i9 << 2) | 0;
+  i17 = HEAP32[i11 >> 2] | 0;
+  i12 = (i17 >>> 14) + -131071 | 0;
+  if ((i12 | 0) == -1) {
+   i12 = -1;
+  } else {
+   i12 = i9 + 1 + i12 | 0;
+  }
+  if ((i9 | 0) > 0 ? (i3 = i14 + (i9 + -1 << 2) | 0, i2 = HEAP32[i3 >> 2] | 0, (HEAP8[5584 + (i2 & 63) | 0] | 0) < 0) : 0) {
+   i18 = i3;
+   i19 = i2;
+  } else {
+   i18 = i11;
+   i19 = i17;
+  }
+  if ((i19 & 63 | 0) == 28) {
+   if ((i19 >>> 23 | 0) == (i7 | 0)) {
+    i17 = i19 & 8372224 | i13 | 27;
+   } else {
+    i17 = i19 & -16321 | i15;
+   }
+   HEAP32[i18 >> 2] = i17;
+   i9 = i16 + ~i9 | 0;
+   if ((((i9 | 0) > -1 ? i9 : 0 - i9 | 0) | 0) > 131071) {
+    i18 = 87;
+    break;
+   }
+   i9 = HEAP32[i11 >> 2] & 16383 | (i9 << 14) + 2147467264;
+  } else {
+   i9 = i8 + ~i9 | 0;
+   if ((((i9 | 0) > -1 ? i9 : 0 - i9 | 0) | 0) > 131071) {
+    i18 = 90;
+    break;
+   }
+   i9 = i17 & 16383 | (i9 << 14) + 2147467264;
+  }
+  HEAP32[i11 >> 2] = i9;
+  if ((i12 | 0) == -1) {
+   i18 = 93;
+   break;
+  } else {
+   i9 = i12;
+  }
+ }
+ if ((i18 | 0) == 87) {
+  i25 = i4 + 12 | 0;
+  i25 = HEAP32[i25 >> 2] | 0;
+  _luaX_syntaxerror(i25, 10624);
+ } else if ((i18 | 0) == 90) {
+  i25 = i4 + 12 | 0;
+  i25 = HEAP32[i25 >> 2] | 0;
+  _luaX_syntaxerror(i25, 10624);
+ } else if ((i18 | 0) == 93) {
+  HEAP32[i6 >> 2] = -1;
+  HEAP32[i10 >> 2] = -1;
+  i25 = i1 + 8 | 0;
+  HEAP32[i25 >> 2] = i7;
+  HEAP32[i1 >> 2] = 6;
+  STACKTOP = i5;
+  return;
+ }
+}
+function _propagatemark(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i1 = STACKTOP;
+ i15 = i2 + 84 | 0;
+ i3 = HEAP32[i15 >> 2] | 0;
+ i10 = i3 + 5 | 0;
+ HEAP8[i10] = HEAPU8[i10] | 4;
+ switch (HEAPU8[i3 + 4 | 0] | 0) {
+ case 5:
+  {
+   i9 = i3 + 24 | 0;
+   HEAP32[i15 >> 2] = HEAP32[i9 >> 2];
+   i15 = i3 + 8 | 0;
+   i14 = HEAP32[i15 >> 2] | 0;
+   do {
+    if ((i14 | 0) != 0) {
+     if ((HEAP8[i14 + 6 | 0] & 8) == 0) {
+      i11 = _luaT_gettm(i14, 3, HEAP32[i2 + 196 >> 2] | 0) | 0;
+      i14 = HEAP32[i15 >> 2] | 0;
+      if ((i14 | 0) != 0) {
+       i6 = 5;
+      }
+     } else {
+      i11 = 0;
+      i6 = 5;
+     }
+     if ((i6 | 0) == 5) {
+      if (!((HEAP8[i14 + 5 | 0] & 3) == 0)) {
+       _reallymarkobject(i2, i14);
+      }
+     }
+     if (((i11 | 0) != 0 ? (HEAP32[i11 + 8 >> 2] & 15 | 0) == 4 : 0) ? (i13 = (HEAP32[i11 >> 2] | 0) + 16 | 0, i12 = _strchr(i13, 107) | 0, i12 = (i12 | 0) != 0, i13 = (_strchr(i13, 118) | 0) == 0, !(i13 & (i12 ^ 1))) : 0) {
+      HEAP8[i10] = HEAP8[i10] & 251;
+      if (i12) {
+       if (i13) {
+        _traverseephemeron(i2, i3) | 0;
+        break;
+       } else {
+        i15 = i2 + 100 | 0;
+        HEAP32[i9 >> 2] = HEAP32[i15 >> 2];
+        HEAP32[i15 >> 2] = i3;
+        break;
+       }
+      }
+      i15 = 1 << HEAPU8[i3 + 7 | 0];
+      i5 = HEAP32[i3 + 16 >> 2] | 0;
+      i4 = i5 + (i15 << 5) | 0;
+      i8 = (HEAP32[i3 + 28 >> 2] | 0) > 0 | 0;
+      if ((i15 | 0) > 0) {
+       do {
+        i12 = i5 + 8 | 0;
+        i10 = i5 + 24 | 0;
+        i11 = (HEAP32[i10 >> 2] & 64 | 0) == 0;
+        do {
+         if ((HEAP32[i12 >> 2] | 0) == 0) {
+          if (!i11 ? !((HEAP8[(HEAP32[i5 + 16 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) {
+           HEAP32[i10 >> 2] = 11;
+          }
+         } else {
+          if (!i11 ? (i7 = HEAP32[i5 + 16 >> 2] | 0, !((HEAP8[i7 + 5 | 0] & 3) == 0)) : 0) {
+           _reallymarkobject(i2, i7);
+          }
+          if ((i8 | 0) == 0) {
+           i10 = HEAP32[i12 >> 2] | 0;
+           if ((i10 & 64 | 0) != 0) {
+            i8 = HEAP32[i5 >> 2] | 0;
+            if ((i10 & 15 | 0) != 4) {
+             i8 = (HEAP8[i8 + 5 | 0] & 3) != 0 | 0;
+             break;
+            }
+            if ((i8 | 0) != 0 ? !((HEAP8[i8 + 5 | 0] & 3) == 0) : 0) {
+             _reallymarkobject(i2, i8);
+             i8 = 0;
+            } else {
+             i8 = 0;
+            }
+           } else {
+            i8 = 0;
+           }
+          }
+         }
+        } while (0);
+        i5 = i5 + 32 | 0;
+       } while (i5 >>> 0 < i4 >>> 0);
+      }
+      if ((i8 | 0) == 0) {
+       i15 = i2 + 88 | 0;
+       HEAP32[i9 >> 2] = HEAP32[i15 >> 2];
+       HEAP32[i15 >> 2] = i3;
+       break;
+      } else {
+       i15 = i2 + 92 | 0;
+       HEAP32[i9 >> 2] = HEAP32[i15 >> 2];
+       HEAP32[i15 >> 2] = i3;
+       break;
+      }
+     } else {
+      i6 = 33;
+     }
+    } else {
+     i6 = 33;
+    }
+   } while (0);
+   if ((i6 | 0) == 33) {
+    i7 = i3 + 16 | 0;
+    i10 = HEAP32[i7 >> 2] | 0;
+    i6 = i10 + (1 << HEAPU8[i3 + 7 | 0] << 5) | 0;
+    i9 = i3 + 28 | 0;
+    i13 = HEAP32[i9 >> 2] | 0;
+    if ((i13 | 0) > 0) {
+     i10 = i3 + 12 | 0;
+     i11 = 0;
+     do {
+      i12 = HEAP32[i10 >> 2] | 0;
+      if ((HEAP32[i12 + (i11 << 4) + 8 >> 2] & 64 | 0) != 0 ? (i8 = HEAP32[i12 + (i11 << 4) >> 2] | 0, !((HEAP8[i8 + 5 | 0] & 3) == 0)) : 0) {
+       _reallymarkobject(i2, i8);
+       i13 = HEAP32[i9 >> 2] | 0;
+      }
+      i11 = i11 + 1 | 0;
+     } while ((i11 | 0) < (i13 | 0));
+     i7 = HEAP32[i7 >> 2] | 0;
+    } else {
+     i7 = i10;
+    }
+    if (i7 >>> 0 < i6 >>> 0) {
+     do {
+      i10 = i7 + 8 | 0;
+      i11 = HEAP32[i10 >> 2] | 0;
+      i9 = i7 + 24 | 0;
+      i8 = (HEAP32[i9 >> 2] & 64 | 0) == 0;
+      if ((i11 | 0) == 0) {
+       if (!i8 ? !((HEAP8[(HEAP32[i7 + 16 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) {
+        HEAP32[i9 >> 2] = 11;
+       }
+      } else {
+       if (!i8 ? (i5 = HEAP32[i7 + 16 >> 2] | 0, !((HEAP8[i5 + 5 | 0] & 3) == 0)) : 0) {
+        _reallymarkobject(i2, i5);
+        i11 = HEAP32[i10 >> 2] | 0;
+       }
+       if ((i11 & 64 | 0) != 0 ? (i4 = HEAP32[i7 >> 2] | 0, !((HEAP8[i4 + 5 | 0] & 3) == 0)) : 0) {
+        _reallymarkobject(i2, i4);
+       }
+      }
+      i7 = i7 + 32 | 0;
+     } while (i7 >>> 0 < i6 >>> 0);
+    }
+   }
+   i3 = (HEAP32[i3 + 28 >> 2] << 4) + 32 + (32 << HEAPU8[i3 + 7 | 0]) | 0;
+   break;
+  }
+ case 8:
+  {
+   i7 = i3 + 60 | 0;
+   HEAP32[i15 >> 2] = HEAP32[i7 >> 2];
+   i4 = i2 + 88 | 0;
+   HEAP32[i7 >> 2] = HEAP32[i4 >> 2];
+   HEAP32[i4 >> 2] = i3;
+   HEAP8[i10] = HEAP8[i10] & 251;
+   i4 = i3 + 28 | 0;
+   i7 = HEAP32[i4 >> 2] | 0;
+   if ((i7 | 0) == 0) {
+    i3 = 1;
+   } else {
+    i5 = i3 + 8 | 0;
+    i6 = HEAP32[i5 >> 2] | 0;
+    if (i7 >>> 0 < i6 >>> 0) {
+     do {
+      if ((HEAP32[i7 + 8 >> 2] & 64 | 0) != 0 ? (i11 = HEAP32[i7 >> 2] | 0, !((HEAP8[i11 + 5 | 0] & 3) == 0)) : 0) {
+       _reallymarkobject(i2, i11);
+       i6 = HEAP32[i5 >> 2] | 0;
+      }
+      i7 = i7 + 16 | 0;
+     } while (i7 >>> 0 < i6 >>> 0);
+    }
+    if ((HEAP8[i2 + 61 | 0] | 0) == 1) {
+     i3 = i3 + 32 | 0;
+     i4 = (HEAP32[i4 >> 2] | 0) + (HEAP32[i3 >> 2] << 4) | 0;
+     if (i7 >>> 0 < i4 >>> 0) {
+      do {
+       HEAP32[i7 + 8 >> 2] = 0;
+       i7 = i7 + 16 | 0;
+      } while (i7 >>> 0 < i4 >>> 0);
+     }
+    } else {
+     i3 = i3 + 32 | 0;
+    }
+    i3 = (HEAP32[i3 >> 2] << 4) + 112 | 0;
+   }
+   break;
+  }
+ case 9:
+  {
+   HEAP32[i15 >> 2] = HEAP32[i3 + 72 >> 2];
+   i5 = i3 + 32 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) != 0 ? !((HEAP8[i4 + 5 | 0] & 3) == 0) : 0) {
+    HEAP32[i5 >> 2] = 0;
+   }
+   i4 = HEAP32[i3 + 36 >> 2] | 0;
+   if ((i4 | 0) != 0 ? !((HEAP8[i4 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i2, i4);
+   }
+   i4 = i3 + 44 | 0;
+   i8 = HEAP32[i4 >> 2] | 0;
+   if ((i8 | 0) > 0) {
+    i5 = i3 + 8 | 0;
+    i6 = 0;
+    do {
+     i7 = HEAP32[i5 >> 2] | 0;
+     if ((HEAP32[i7 + (i6 << 4) + 8 >> 2] & 64 | 0) != 0 ? (i9 = HEAP32[i7 + (i6 << 4) >> 2] | 0, !((HEAP8[i9 + 5 | 0] & 3) == 0)) : 0) {
+      _reallymarkobject(i2, i9);
+      i8 = HEAP32[i4 >> 2] | 0;
+     }
+     i6 = i6 + 1 | 0;
+    } while ((i6 | 0) < (i8 | 0));
+   }
+   i5 = i3 + 40 | 0;
+   i8 = HEAP32[i5 >> 2] | 0;
+   if ((i8 | 0) > 0) {
+    i6 = i3 + 28 | 0;
+    i7 = 0;
+    do {
+     i9 = HEAP32[(HEAP32[i6 >> 2] | 0) + (i7 << 3) >> 2] | 0;
+     if ((i9 | 0) != 0 ? !((HEAP8[i9 + 5 | 0] & 3) == 0) : 0) {
+      _reallymarkobject(i2, i9);
+      i8 = HEAP32[i5 >> 2] | 0;
+     }
+     i7 = i7 + 1 | 0;
+    } while ((i7 | 0) < (i8 | 0));
+   }
+   i6 = i3 + 56 | 0;
+   i8 = HEAP32[i6 >> 2] | 0;
+   if ((i8 | 0) > 0) {
+    i7 = i3 + 16 | 0;
+    i9 = 0;
+    do {
+     i10 = HEAP32[(HEAP32[i7 >> 2] | 0) + (i9 << 2) >> 2] | 0;
+     if ((i10 | 0) != 0 ? !((HEAP8[i10 + 5 | 0] & 3) == 0) : 0) {
+      _reallymarkobject(i2, i10);
+      i8 = HEAP32[i6 >> 2] | 0;
+     }
+     i9 = i9 + 1 | 0;
+    } while ((i9 | 0) < (i8 | 0));
+   }
+   i7 = i3 + 60 | 0;
+   i11 = HEAP32[i7 >> 2] | 0;
+   if ((i11 | 0) > 0) {
+    i8 = i3 + 24 | 0;
+    i9 = 0;
+    do {
+     i10 = HEAP32[(HEAP32[i8 >> 2] | 0) + (i9 * 12 | 0) >> 2] | 0;
+     if ((i10 | 0) != 0 ? !((HEAP8[i10 + 5 | 0] & 3) == 0) : 0) {
+      _reallymarkobject(i2, i10);
+      i11 = HEAP32[i7 >> 2] | 0;
+     }
+     i9 = i9 + 1 | 0;
+    } while ((i9 | 0) < (i11 | 0));
+    i8 = HEAP32[i6 >> 2] | 0;
+   }
+   i3 = (i11 * 12 | 0) + 80 + (HEAP32[i4 >> 2] << 4) + (HEAP32[i5 >> 2] << 3) + ((HEAP32[i3 + 48 >> 2] | 0) + i8 + (HEAP32[i3 + 52 >> 2] | 0) << 2) | 0;
+   break;
+  }
+ case 38:
+  {
+   HEAP32[i15 >> 2] = HEAP32[i3 + 8 >> 2];
+   i4 = i3 + 6 | 0;
+   i5 = HEAP8[i4] | 0;
+   if (i5 << 24 >> 24 == 0) {
+    i7 = i5 & 255;
+   } else {
+    i6 = 0;
+    do {
+     if ((HEAP32[i3 + (i6 << 4) + 24 >> 2] & 64 | 0) != 0 ? (i14 = HEAP32[i3 + (i6 << 4) + 16 >> 2] | 0, !((HEAP8[i14 + 5 | 0] & 3) == 0)) : 0) {
+      _reallymarkobject(i2, i14);
+      i5 = HEAP8[i4] | 0;
+     }
+     i6 = i6 + 1 | 0;
+     i7 = i5 & 255;
+    } while ((i6 | 0) < (i7 | 0));
+   }
+   i3 = (i7 << 4) + 16 | 0;
+   break;
+  }
+ case 6:
+  {
+   HEAP32[i15 >> 2] = HEAP32[i3 + 8 >> 2];
+   i4 = HEAP32[i3 + 12 >> 2] | 0;
+   if ((i4 | 0) != 0 ? !((HEAP8[i4 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i2, i4);
+   }
+   i4 = i3 + 6 | 0;
+   i6 = HEAP8[i4] | 0;
+   if (i6 << 24 >> 24 == 0) {
+    i7 = i6 & 255;
+   } else {
+    i5 = 0;
+    do {
+     i7 = HEAP32[i3 + (i5 << 2) + 16 >> 2] | 0;
+     if ((i7 | 0) != 0 ? !((HEAP8[i7 + 5 | 0] & 3) == 0) : 0) {
+      _reallymarkobject(i2, i7);
+      i6 = HEAP8[i4] | 0;
+     }
+     i5 = i5 + 1 | 0;
+     i7 = i6 & 255;
+    } while ((i5 | 0) < (i7 | 0));
+   }
+   i3 = (i7 << 2) + 16 | 0;
+   break;
+  }
+ default:
+  {
+   STACKTOP = i1;
+   return;
+  }
+ }
+ i15 = i2 + 16 | 0;
+ HEAP32[i15 >> 2] = (HEAP32[i15 >> 2] | 0) + i3;
+ STACKTOP = i1;
+ return;
+}
+function _strstr(i8, i4) {
+ i8 = i8 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i6 = i1 + 1024 | 0;
+ i2 = i1;
+ i10 = HEAP8[i4] | 0;
+ if (i10 << 24 >> 24 == 0) {
+  i20 = i8;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i8 = _strchr(i8, i10 << 24 >> 24) | 0;
+ if ((i8 | 0) == 0) {
+  i20 = 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i13 = HEAP8[i4 + 1 | 0] | 0;
+ if (i13 << 24 >> 24 == 0) {
+  i20 = i8;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i11 = i8 + 1 | 0;
+ i9 = HEAP8[i11] | 0;
+ if (i9 << 24 >> 24 == 0) {
+  i20 = 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i15 = HEAP8[i4 + 2 | 0] | 0;
+ if (i15 << 24 >> 24 == 0) {
+  i2 = i13 & 255 | (i10 & 255) << 8;
+  i3 = i9;
+  i4 = HEAPU8[i8] << 8 | i9 & 255;
+  while (1) {
+   i5 = i4 & 65535;
+   if ((i5 | 0) == (i2 | 0)) {
+    break;
+   }
+   i11 = i11 + 1 | 0;
+   i4 = HEAP8[i11] | 0;
+   if (i4 << 24 >> 24 == 0) {
+    i3 = 0;
+    break;
+   } else {
+    i3 = i4;
+    i4 = i4 & 255 | i5 << 8;
+   }
+  }
+  i20 = i3 << 24 >> 24 == 0 ? 0 : i11 + -1 | 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i16 = i8 + 2 | 0;
+ i11 = HEAP8[i16] | 0;
+ if (i11 << 24 >> 24 == 0) {
+  i20 = 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i18 = HEAP8[i4 + 3 | 0] | 0;
+ if (i18 << 24 >> 24 == 0) {
+  i2 = (i13 & 255) << 16 | (i10 & 255) << 24 | (i15 & 255) << 8;
+  i4 = (i11 & 255) << 8 | (i9 & 255) << 16 | HEAPU8[i8] << 24;
+  if ((i4 | 0) == (i2 | 0)) {
+   i3 = 0;
+  } else {
+   do {
+    i16 = i16 + 1 | 0;
+    i3 = HEAP8[i16] | 0;
+    i4 = (i3 & 255 | i4) << 8;
+    i3 = i3 << 24 >> 24 == 0;
+   } while (!(i3 | (i4 | 0) == (i2 | 0)));
+  }
+  i20 = i3 ? 0 : i16 + -2 | 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ i16 = i8 + 3 | 0;
+ i17 = HEAP8[i16] | 0;
+ if (i17 << 24 >> 24 == 0) {
+  i20 = 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ if ((HEAP8[i4 + 4 | 0] | 0) == 0) {
+  i2 = (i13 & 255) << 16 | (i10 & 255) << 24 | (i15 & 255) << 8 | i18 & 255;
+  i3 = (i11 & 255) << 8 | (i9 & 255) << 16 | i17 & 255 | HEAPU8[i8] << 24;
+  if ((i3 | 0) == (i2 | 0)) {
+   i4 = 0;
+  } else {
+   do {
+    i16 = i16 + 1 | 0;
+    i4 = HEAP8[i16] | 0;
+    i3 = i4 & 255 | i3 << 8;
+    i4 = i4 << 24 >> 24 == 0;
+   } while (!(i4 | (i3 | 0) == (i2 | 0)));
+  }
+  i20 = i4 ? 0 : i16 + -3 | 0;
+  STACKTOP = i1;
+  return i20 | 0;
+ }
+ HEAP32[i6 + 0 >> 2] = 0;
+ HEAP32[i6 + 4 >> 2] = 0;
+ HEAP32[i6 + 8 >> 2] = 0;
+ HEAP32[i6 + 12 >> 2] = 0;
+ HEAP32[i6 + 16 >> 2] = 0;
+ HEAP32[i6 + 20 >> 2] = 0;
+ HEAP32[i6 + 24 >> 2] = 0;
+ HEAP32[i6 + 28 >> 2] = 0;
+ i9 = 0;
+ while (1) {
+  if ((HEAP8[i8 + i9 | 0] | 0) == 0) {
+   i14 = 0;
+   i12 = 80;
+   break;
+  }
+  i20 = i10 & 255;
+  i3 = i6 + (i20 >>> 5 << 2) | 0;
+  HEAP32[i3 >> 2] = HEAP32[i3 >> 2] | 1 << (i20 & 31);
+  i3 = i9 + 1 | 0;
+  HEAP32[i2 + (i20 << 2) >> 2] = i3;
+  i10 = HEAP8[i4 + i3 | 0] | 0;
+  if (i10 << 24 >> 24 == 0) {
+   break;
+  } else {
+   i9 = i3;
+  }
+ }
+ if ((i12 | 0) == 80) {
+  STACKTOP = i1;
+  return i14 | 0;
+ }
+ L49 : do {
+  if (i3 >>> 0 > 1) {
+   i14 = 1;
+   i11 = -1;
+   i12 = 0;
+   L50 : while (1) {
+    i10 = 1;
+    while (1) {
+     i13 = i14;
+     L54 : while (1) {
+      i14 = 1;
+      while (1) {
+       i15 = HEAP8[i4 + (i14 + i11) | 0] | 0;
+       i16 = HEAP8[i4 + i13 | 0] | 0;
+       if (!(i15 << 24 >> 24 == i16 << 24 >> 24)) {
+        break L54;
+       }
+       i15 = i14 + 1 | 0;
+       if ((i14 | 0) == (i10 | 0)) {
+        break;
+       }
+       i13 = i15 + i12 | 0;
+       if (i13 >>> 0 < i3 >>> 0) {
+        i14 = i15;
+       } else {
+        break L50;
+       }
+      }
+      i12 = i12 + i10 | 0;
+      i13 = i12 + 1 | 0;
+      if (!(i13 >>> 0 < i3 >>> 0)) {
+       break L50;
+      }
+     }
+     i10 = i13 - i11 | 0;
+     if (!((i15 & 255) > (i16 & 255))) {
+      break;
+     }
+     i14 = i13 + 1 | 0;
+     if (i14 >>> 0 < i3 >>> 0) {
+      i12 = i13;
+     } else {
+      break L50;
+     }
+    }
+    i14 = i12 + 2 | 0;
+    if (i14 >>> 0 < i3 >>> 0) {
+     i11 = i12;
+     i12 = i12 + 1 | 0;
+    } else {
+     i11 = i12;
+     i10 = 1;
+     break;
+    }
+   }
+   i16 = 1;
+   i12 = -1;
+   i14 = 0;
+   while (1) {
+    i13 = 1;
+    while (1) {
+     i15 = i16;
+     L69 : while (1) {
+      i18 = 1;
+      while (1) {
+       i17 = HEAP8[i4 + (i18 + i12) | 0] | 0;
+       i16 = HEAP8[i4 + i15 | 0] | 0;
+       if (!(i17 << 24 >> 24 == i16 << 24 >> 24)) {
+        break L69;
+       }
+       i16 = i18 + 1 | 0;
+       if ((i18 | 0) == (i13 | 0)) {
+        break;
+       }
+       i15 = i16 + i14 | 0;
+       if (i15 >>> 0 < i3 >>> 0) {
+        i18 = i16;
+       } else {
+        i14 = i12;
+        break L49;
+       }
+      }
+      i14 = i14 + i13 | 0;
+      i15 = i14 + 1 | 0;
+      if (!(i15 >>> 0 < i3 >>> 0)) {
+       i14 = i12;
+       break L49;
+      }
+     }
+     i13 = i15 - i12 | 0;
+     if (!((i17 & 255) < (i16 & 255))) {
+      break;
+     }
+     i16 = i15 + 1 | 0;
+     if (i16 >>> 0 < i3 >>> 0) {
+      i14 = i15;
+     } else {
+      i14 = i12;
+      break L49;
+     }
+    }
+    i16 = i14 + 2 | 0;
+    if (i16 >>> 0 < i3 >>> 0) {
+     i12 = i14;
+     i14 = i14 + 1 | 0;
+    } else {
+     i13 = 1;
+     break;
+    }
+   }
+  } else {
+   i11 = -1;
+   i14 = -1;
+   i10 = 1;
+   i13 = 1;
+  }
+ } while (0);
+ i15 = (i14 + 1 | 0) >>> 0 > (i11 + 1 | 0) >>> 0;
+ i12 = i15 ? i13 : i10;
+ i11 = i15 ? i14 : i11;
+ i10 = i11 + 1 | 0;
+ if ((_memcmp(i4, i4 + i12 | 0, i10) | 0) == 0) {
+  i15 = i3 - i12 | 0;
+  i16 = i3 | 63;
+  if ((i3 | 0) != (i12 | 0)) {
+   i14 = i8;
+   i13 = 0;
+   i17 = i8;
+   L82 : while (1) {
+    i18 = i14;
+    do {
+     if ((i17 - i18 | 0) >>> 0 < i3 >>> 0) {
+      i19 = _memchr(i17, 0, i16) | 0;
+      if ((i19 | 0) != 0) {
+       if ((i19 - i18 | 0) >>> 0 < i3 >>> 0) {
+        i14 = 0;
+        i12 = 80;
+        break L82;
+       } else {
+        i17 = i19;
+        break;
+       }
+      } else {
+       i17 = i17 + i16 | 0;
+       break;
+      }
+     }
+    } while (0);
+    i18 = HEAPU8[i14 + i9 | 0] | 0;
+    if ((1 << (i18 & 31) & HEAP32[i6 + (i18 >>> 5 << 2) >> 2] | 0) == 0) {
+     i14 = i14 + i3 | 0;
+     i13 = 0;
+     continue;
+    }
+    i20 = HEAP32[i2 + (i18 << 2) >> 2] | 0;
+    i18 = i3 - i20 | 0;
+    if ((i3 | 0) != (i20 | 0)) {
+     i14 = i14 + ((i13 | 0) != 0 & i18 >>> 0 < i12 >>> 0 ? i15 : i18) | 0;
+     i13 = 0;
+     continue;
+    }
+    i20 = i10 >>> 0 > i13 >>> 0 ? i10 : i13;
+    i18 = HEAP8[i4 + i20 | 0] | 0;
+    L96 : do {
+     if (i18 << 24 >> 24 == 0) {
+      i19 = i10;
+     } else {
+      while (1) {
+       i19 = i20 + 1 | 0;
+       if (!(i18 << 24 >> 24 == (HEAP8[i14 + i20 | 0] | 0))) {
+        break;
+       }
+       i18 = HEAP8[i4 + i19 | 0] | 0;
+       if (i18 << 24 >> 24 == 0) {
+        i19 = i10;
+        break L96;
+       } else {
+        i20 = i19;
+       }
+      }
+      i14 = i14 + (i20 - i11) | 0;
+      i13 = 0;
+      continue L82;
+     }
+    } while (0);
+    while (1) {
+     if (!(i19 >>> 0 > i13 >>> 0)) {
+      break;
+     }
+     i18 = i19 + -1 | 0;
+     if ((HEAP8[i4 + i18 | 0] | 0) == (HEAP8[i14 + i18 | 0] | 0)) {
+      i19 = i18;
+     } else {
+      break;
+     }
+    }
+    if ((i19 | 0) == (i13 | 0)) {
+     i12 = 80;
+     break;
+    }
+    i14 = i14 + i12 | 0;
+    i13 = i15;
+   }
+   if ((i12 | 0) == 80) {
+    STACKTOP = i1;
+    return i14 | 0;
+   }
+  } else {
+   i5 = i16;
+   i7 = i3;
+  }
+ } else {
+  i7 = i3 - i11 + -1 | 0;
+  i5 = i3 | 63;
+  i7 = (i11 >>> 0 > i7 >>> 0 ? i11 : i7) + 1 | 0;
+ }
+ i12 = i4 + i10 | 0;
+ i14 = i8;
+ L111 : while (1) {
+  i13 = i14;
+  do {
+   if ((i8 - i13 | 0) >>> 0 < i3 >>> 0) {
+    i15 = _memchr(i8, 0, i5) | 0;
+    if ((i15 | 0) != 0) {
+     if ((i15 - i13 | 0) >>> 0 < i3 >>> 0) {
+      i14 = 0;
+      i12 = 80;
+      break L111;
+     } else {
+      i8 = i15;
+      break;
+     }
+    } else {
+     i8 = i8 + i5 | 0;
+     break;
+    }
+   }
+  } while (0);
+  i13 = HEAPU8[i14 + i9 | 0] | 0;
+  if ((1 << (i13 & 31) & HEAP32[i6 + (i13 >>> 5 << 2) >> 2] | 0) == 0) {
+   i14 = i14 + i3 | 0;
+   continue;
+  }
+  i13 = HEAP32[i2 + (i13 << 2) >> 2] | 0;
+  if ((i3 | 0) != (i13 | 0)) {
+   i14 = i14 + (i3 - i13) | 0;
+   continue;
+  }
+  i15 = HEAP8[i12] | 0;
+  L125 : do {
+   if (i15 << 24 >> 24 == 0) {
+    i13 = i10;
+   } else {
+    i16 = i10;
+    while (1) {
+     i13 = i16 + 1 | 0;
+     if (!(i15 << 24 >> 24 == (HEAP8[i14 + i16 | 0] | 0))) {
+      break;
+     }
+     i15 = HEAP8[i4 + i13 | 0] | 0;
+     if (i15 << 24 >> 24 == 0) {
+      i13 = i10;
+      break L125;
+     } else {
+      i16 = i13;
+     }
+    }
+    i14 = i14 + (i16 - i11) | 0;
+    continue L111;
+   }
+  } while (0);
+  do {
+   if ((i13 | 0) == 0) {
+    i12 = 80;
+    break L111;
+   }
+   i13 = i13 + -1 | 0;
+  } while ((HEAP8[i4 + i13 | 0] | 0) == (HEAP8[i14 + i13 | 0] | 0));
+  i14 = i14 + i7 | 0;
+ }
+ if ((i12 | 0) == 80) {
+  STACKTOP = i1;
+  return i14 | 0;
+ }
+ return 0;
+}
+function _str_format(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, d21 = 0.0, i22 = 0;
+ i12 = STACKTOP;
+ STACKTOP = STACKTOP + 1104 | 0;
+ i4 = i12;
+ i7 = i12 + 1060 | 0;
+ i9 = i12 + 1082 | 0;
+ i20 = i12 + 1056 | 0;
+ i10 = i12 + 16 | 0;
+ i5 = i12 + 1064 | 0;
+ i6 = i12 + 8 | 0;
+ i8 = _lua_gettop(i2) | 0;
+ i16 = _luaL_checklstring(i2, 1, i20) | 0;
+ i20 = HEAP32[i20 >> 2] | 0;
+ i3 = i16 + i20 | 0;
+ _luaL_buffinit(i2, i10);
+ L1 : do {
+  if ((i20 | 0) > 0) {
+   i1 = i10 + 8 | 0;
+   i13 = i10 + 4 | 0;
+   i14 = i5 + 1 | 0;
+   i19 = 1;
+   L3 : while (1) {
+    while (1) {
+     i15 = HEAP8[i16] | 0;
+     if (i15 << 24 >> 24 == 37) {
+      i18 = i16 + 1 | 0;
+      if ((HEAP8[i18] | 0) != 37) {
+       break;
+      }
+      i15 = HEAP32[i1 >> 2] | 0;
+      if (i15 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0) {
+       i17 = 37;
+      } else {
+       _luaL_prepbuffsize(i10, 1) | 0;
+       i15 = HEAP32[i1 >> 2] | 0;
+       i17 = HEAP8[i18] | 0;
+      }
+      HEAP32[i1 >> 2] = i15 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i15 | 0] = i17;
+      i16 = i16 + 2 | 0;
+     } else {
+      i17 = HEAP32[i1 >> 2] | 0;
+      if (!(i17 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+       _luaL_prepbuffsize(i10, 1) | 0;
+       i17 = HEAP32[i1 >> 2] | 0;
+       i15 = HEAP8[i16] | 0;
+      }
+      HEAP32[i1 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i17 | 0] = i15;
+      i16 = i16 + 1 | 0;
+     }
+     if (!(i16 >>> 0 < i3 >>> 0)) {
+      break L1;
+     }
+    }
+    i17 = _luaL_prepbuffsize(i10, 512) | 0;
+    i15 = i19 + 1 | 0;
+    if ((i19 | 0) >= (i8 | 0)) {
+     _luaL_argerror(i2, i15, 7648) | 0;
+    }
+    i19 = HEAP8[i18] | 0;
+    L22 : do {
+     if (i19 << 24 >> 24 == 0) {
+      i19 = 0;
+      i20 = i18;
+     } else {
+      i20 = i18;
+      while (1) {
+       i16 = i20 + 1 | 0;
+       if ((_memchr(7800, i19 << 24 >> 24, 6) | 0) == 0) {
+        break L22;
+       }
+       i19 = HEAP8[i16] | 0;
+       if (i19 << 24 >> 24 == 0) {
+        i19 = 0;
+        i20 = i16;
+        break;
+       } else {
+        i20 = i16;
+       }
+      }
+     }
+    } while (0);
+    i16 = i18;
+    if ((i20 - i16 | 0) >>> 0 > 5) {
+     _luaL_error(i2, 7808, i4) | 0;
+     i19 = HEAP8[i20] | 0;
+    }
+    i19 = ((i19 & 255) + -48 | 0) >>> 0 < 10 ? i20 + 1 | 0 : i20;
+    i19 = ((HEAPU8[i19] | 0) + -48 | 0) >>> 0 < 10 ? i19 + 1 | 0 : i19;
+    i20 = HEAP8[i19] | 0;
+    if (i20 << 24 >> 24 == 46) {
+     i20 = i19 + 1 | 0;
+     i19 = ((HEAPU8[i20] | 0) + -48 | 0) >>> 0 < 10 ? i19 + 2 | 0 : i20;
+     i19 = ((HEAPU8[i19] | 0) + -48 | 0) >>> 0 < 10 ? i19 + 1 | 0 : i19;
+     i20 = HEAP8[i19] | 0;
+    }
+    if (((i20 & 255) + -48 | 0) >>> 0 < 10) {
+     _luaL_error(i2, 7840, i4) | 0;
+    }
+    HEAP8[i5] = 37;
+    i16 = i19 - i16 | 0;
+    _memcpy(i14 | 0, i18 | 0, i16 + 1 | 0) | 0;
+    HEAP8[i5 + (i16 + 2) | 0] = 0;
+    i16 = i19 + 1 | 0;
+    i18 = HEAP8[i19] | 0;
+    L36 : do {
+     switch (i18 | 0) {
+     case 115:
+      {
+       i18 = _luaL_tolstring(i2, i15, i6) | 0;
+       if ((_strchr(i5, 46) | 0) == 0 ? (HEAP32[i6 >> 2] | 0) >>> 0 > 99 : 0) {
+        _luaL_addvalue(i10);
+        i17 = 0;
+        break L36;
+       }
+       HEAP32[i4 >> 2] = i18;
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       _lua_settop(i2, -2);
+       break;
+      }
+     case 88:
+     case 120:
+     case 117:
+     case 111:
+      {
+       d21 = +_luaL_checknumber(i2, i15);
+       i18 = ~~d21 >>> 0;
+       d21 = d21 - +(i18 >>> 0);
+       if (!(d21 > -1.0 & d21 < 1.0)) {
+        _luaL_argerror(i2, i15, 7696) | 0;
+       }
+       i20 = _strlen(i5 | 0) | 0;
+       i22 = i5 + (i20 + -1) | 0;
+       i19 = HEAP8[i22] | 0;
+       HEAP8[i22] = 108;
+       HEAP8[i22 + 1 | 0] = 0;
+       HEAP8[i5 + i20 | 0] = i19;
+       HEAP8[i5 + (i20 + 1) | 0] = 0;
+       HEAP32[i4 >> 2] = i18;
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       break;
+      }
+     case 99:
+      {
+       HEAP32[i4 >> 2] = _luaL_checkinteger(i2, i15) | 0;
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       break;
+      }
+     case 113:
+      {
+       i17 = _luaL_checklstring(i2, i15, i7) | 0;
+       i18 = HEAP32[i1 >> 2] | 0;
+       if (!(i18 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+        _luaL_prepbuffsize(i10, 1) | 0;
+        i18 = HEAP32[i1 >> 2] | 0;
+       }
+       HEAP32[i1 >> 2] = i18 + 1;
+       HEAP8[(HEAP32[i10 >> 2] | 0) + i18 | 0] = 34;
+       i22 = HEAP32[i7 >> 2] | 0;
+       HEAP32[i7 >> 2] = i22 + -1;
+       if ((i22 | 0) != 0) {
+        while (1) {
+         i18 = HEAP8[i17] | 0;
+         do {
+          if (i18 << 24 >> 24 == 10 | i18 << 24 >> 24 == 92 | i18 << 24 >> 24 == 34) {
+           i18 = HEAP32[i1 >> 2] | 0;
+           if (!(i18 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+            _luaL_prepbuffsize(i10, 1) | 0;
+            i18 = HEAP32[i1 >> 2] | 0;
+           }
+           HEAP32[i1 >> 2] = i18 + 1;
+           HEAP8[(HEAP32[i10 >> 2] | 0) + i18 | 0] = 92;
+           i18 = HEAP32[i1 >> 2] | 0;
+           if (!(i18 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+            _luaL_prepbuffsize(i10, 1) | 0;
+            i18 = HEAP32[i1 >> 2] | 0;
+           }
+           i22 = HEAP8[i17] | 0;
+           HEAP32[i1 >> 2] = i18 + 1;
+           HEAP8[(HEAP32[i10 >> 2] | 0) + i18 | 0] = i22;
+          } else if (i18 << 24 >> 24 == 0) {
+           i18 = 0;
+           i11 = 44;
+          } else {
+           if ((_iscntrl(i18 & 255 | 0) | 0) != 0) {
+            i18 = HEAP8[i17] | 0;
+            i11 = 44;
+            break;
+           }
+           i18 = HEAP32[i1 >> 2] | 0;
+           if (!(i18 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+            _luaL_prepbuffsize(i10, 1) | 0;
+            i18 = HEAP32[i1 >> 2] | 0;
+           }
+           i22 = HEAP8[i17] | 0;
+           HEAP32[i1 >> 2] = i18 + 1;
+           HEAP8[(HEAP32[i10 >> 2] | 0) + i18 | 0] = i22;
+          }
+         } while (0);
+         if ((i11 | 0) == 44) {
+          i11 = 0;
+          i18 = i18 & 255;
+          if (((HEAPU8[i17 + 1 | 0] | 0) + -48 | 0) >>> 0 < 10) {
+           HEAP32[i4 >> 2] = i18;
+           _sprintf(i9 | 0, 7792, i4 | 0) | 0;
+          } else {
+           HEAP32[i4 >> 2] = i18;
+           _sprintf(i9 | 0, 7784, i4 | 0) | 0;
+          }
+          _luaL_addstring(i10, i9);
+         }
+         i22 = HEAP32[i7 >> 2] | 0;
+         HEAP32[i7 >> 2] = i22 + -1;
+         if ((i22 | 0) == 0) {
+          break;
+         } else {
+          i17 = i17 + 1 | 0;
+         }
+        }
+       }
+       i17 = HEAP32[i1 >> 2] | 0;
+       if (!(i17 >>> 0 < (HEAP32[i13 >> 2] | 0) >>> 0)) {
+        _luaL_prepbuffsize(i10, 1) | 0;
+        i17 = HEAP32[i1 >> 2] | 0;
+       }
+       HEAP32[i1 >> 2] = i17 + 1;
+       HEAP8[(HEAP32[i10 >> 2] | 0) + i17 | 0] = 34;
+       i17 = 0;
+       break;
+      }
+     case 71:
+     case 103:
+     case 102:
+     case 69:
+     case 101:
+      {
+       HEAP8[i5 + (_strlen(i5 | 0) | 0) | 0] = 0;
+       d21 = +_luaL_checknumber(i2, i15);
+       HEAPF64[tempDoublePtr >> 3] = d21;
+       HEAP32[i4 >> 2] = HEAP32[tempDoublePtr >> 2];
+       HEAP32[i4 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       break;
+      }
+     case 105:
+     case 100:
+      {
+       d21 = +_luaL_checknumber(i2, i15);
+       i18 = ~~d21;
+       d21 = d21 - +(i18 | 0);
+       if (!(d21 > -1.0 & d21 < 1.0)) {
+        _luaL_argerror(i2, i15, 7664) | 0;
+       }
+       i22 = _strlen(i5 | 0) | 0;
+       i19 = i5 + (i22 + -1) | 0;
+       i20 = HEAP8[i19] | 0;
+       HEAP8[i19] = 108;
+       HEAP8[i19 + 1 | 0] = 0;
+       HEAP8[i5 + i22 | 0] = i20;
+       HEAP8[i5 + (i22 + 1) | 0] = 0;
+       HEAP32[i4 >> 2] = i18;
+       i17 = _sprintf(i17 | 0, i5 | 0, i4 | 0) | 0;
+       break;
+      }
+     default:
+      {
+       break L3;
+      }
+     }
+    } while (0);
+    HEAP32[i1 >> 2] = (HEAP32[i1 >> 2] | 0) + i17;
+    if (i16 >>> 0 < i3 >>> 0) {
+     i19 = i15;
+    } else {
+     break L1;
+    }
+   }
+   HEAP32[i4 >> 2] = i18;
+   i22 = _luaL_error(i2, 7744, i4) | 0;
+   STACKTOP = i12;
+   return i22 | 0;
+  }
+ } while (0);
+ _luaL_pushresult(i10);
+ i22 = 1;
+ STACKTOP = i12;
+ return i22 | 0;
+}
+function _luaD_precall(i3, i17, i4) {
+ i3 = i3 | 0;
+ i17 = i17 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i8 = i1;
+ i6 = i3 + 28 | 0;
+ i2 = i3 + 8 | 0;
+ i13 = i3 + 24 | 0;
+ i14 = i3 + 32 | 0;
+ while (1) {
+  i15 = HEAP32[i6 >> 2] | 0;
+  i16 = i17;
+  i12 = i15;
+  i5 = i16 - i12 | 0;
+  i11 = HEAP32[i17 + 8 >> 2] & 63;
+  if ((i11 | 0) == 38) {
+   i11 = 4;
+   break;
+  } else if ((i11 | 0) == 22) {
+   i11 = 3;
+   break;
+  } else if ((i11 | 0) == 6) {
+   i11 = 31;
+   break;
+  }
+  i11 = _luaT_gettmbyobj(i3, i17, 16) | 0;
+  i15 = i16 - (HEAP32[i6 >> 2] | 0) | 0;
+  i16 = i11 + 8 | 0;
+  if ((HEAP32[i16 >> 2] & 15 | 0) != 6) {
+   i11 = 54;
+   break;
+  }
+  i19 = HEAP32[i2 >> 2] | 0;
+  if (i19 >>> 0 > i17 >>> 0) {
+   while (1) {
+    i18 = i19 + -16 | 0;
+    i22 = i18;
+    i21 = HEAP32[i22 + 4 >> 2] | 0;
+    i20 = i19;
+    HEAP32[i20 >> 2] = HEAP32[i22 >> 2];
+    HEAP32[i20 + 4 >> 2] = i21;
+    HEAP32[i19 + 8 >> 2] = HEAP32[i19 + -8 >> 2];
+    if (i18 >>> 0 > i17 >>> 0) {
+     i19 = i18;
+    } else {
+     break;
+    }
+   }
+   i19 = HEAP32[i2 >> 2] | 0;
+  }
+  i17 = i19 + 16 | 0;
+  HEAP32[i2 >> 2] = i17;
+  if (((HEAP32[i13 >> 2] | 0) - i17 | 0) < 16) {
+   i18 = HEAP32[i14 >> 2] | 0;
+   if ((i18 | 0) > 1e6) {
+    i11 = 60;
+    break;
+   }
+   i17 = (i17 - (HEAP32[i6 >> 2] | 0) >> 4) + 5 | 0;
+   i18 = i18 << 1;
+   i18 = (i18 | 0) > 1e6 ? 1e6 : i18;
+   i17 = (i18 | 0) < (i17 | 0) ? i17 : i18;
+   if ((i17 | 0) > 1e6) {
+    i11 = 62;
+    break;
+   }
+   _luaD_reallocstack(i3, i17);
+  }
+  i22 = HEAP32[i6 >> 2] | 0;
+  i17 = i22 + i15 | 0;
+  i19 = i11;
+  i20 = HEAP32[i19 + 4 >> 2] | 0;
+  i21 = i17;
+  HEAP32[i21 >> 2] = HEAP32[i19 >> 2];
+  HEAP32[i21 + 4 >> 2] = i20;
+  HEAP32[i22 + (i15 + 8) >> 2] = HEAP32[i16 >> 2];
+ }
+ if ((i11 | 0) == 3) {
+  i10 = i17;
+ } else if ((i11 | 0) == 4) {
+  i10 = (HEAP32[i17 >> 2] | 0) + 12 | 0;
+ } else if ((i11 | 0) == 31) {
+  i10 = HEAP32[(HEAP32[i17 >> 2] | 0) + 12 >> 2] | 0;
+  i18 = HEAP32[i2 >> 2] | 0;
+  i16 = i18;
+  i11 = i10 + 78 | 0;
+  i17 = HEAPU8[i11] | 0;
+  do {
+   if (((HEAP32[i13 >> 2] | 0) - i16 >> 4 | 0) <= (i17 | 0)) {
+    i13 = HEAP32[i14 >> 2] | 0;
+    if ((i13 | 0) > 1e6) {
+     _luaD_throw(i3, 6);
+    }
+    i12 = i17 + 5 + (i16 - i12 >> 4) | 0;
+    i13 = i13 << 1;
+    i13 = (i13 | 0) > 1e6 ? 1e6 : i13;
+    i12 = (i13 | 0) < (i12 | 0) ? i12 : i13;
+    if ((i12 | 0) > 1e6) {
+     _luaD_reallocstack(i3, 1000200);
+     _luaG_runerror(i3, 2224, i8);
+    } else {
+     _luaD_reallocstack(i3, i12);
+     i7 = HEAP32[i6 >> 2] | 0;
+     i9 = HEAP32[i2 >> 2] | 0;
+     break;
+    }
+   } else {
+    i7 = i15;
+    i9 = i18;
+   }
+  } while (0);
+  i6 = i7 + i5 | 0;
+  i22 = i9 - i6 >> 4;
+  i12 = i22 + -1 | 0;
+  i8 = i10 + 76 | 0;
+  i13 = HEAP8[i8] | 0;
+  if ((i22 | 0) > (i13 & 255 | 0)) {
+   i8 = i13;
+  } else {
+   i13 = i9;
+   while (1) {
+    i9 = i13 + 16 | 0;
+    HEAP32[i2 >> 2] = i9;
+    HEAP32[i13 + 8 >> 2] = 0;
+    i12 = i12 + 1 | 0;
+    i13 = HEAP8[i8] | 0;
+    if ((i12 | 0) < (i13 & 255 | 0)) {
+     i13 = i9;
+    } else {
+     i8 = i13;
+     break;
+    }
+   }
+  }
+  if ((HEAP8[i10 + 77 | 0] | 0) != 0) {
+   i5 = i8 & 255;
+   if (!(i8 << 24 >> 24 == 0) ? (i22 = 0 - i12 | 0, HEAP32[i2 >> 2] = i9 + 16, i19 = i9 + (i22 << 4) | 0, i20 = HEAP32[i19 + 4 >> 2] | 0, i21 = i9, HEAP32[i21 >> 2] = HEAP32[i19 >> 2], HEAP32[i21 + 4 >> 2] = i20, i22 = i9 + (i22 << 4) + 8 | 0, HEAP32[i9 + 8 >> 2] = HEAP32[i22 >> 2], HEAP32[i22 >> 2] = 0, (i8 & 255) > 1) : 0) {
+    i7 = 1;
+    do {
+     i21 = HEAP32[i2 >> 2] | 0;
+     i22 = i7 - i12 | 0;
+     HEAP32[i2 >> 2] = i21 + 16;
+     i18 = i9 + (i22 << 4) | 0;
+     i19 = HEAP32[i18 + 4 >> 2] | 0;
+     i20 = i21;
+     HEAP32[i20 >> 2] = HEAP32[i18 >> 2];
+     HEAP32[i20 + 4 >> 2] = i19;
+     i22 = i9 + (i22 << 4) + 8 | 0;
+     HEAP32[i21 + 8 >> 2] = HEAP32[i22 >> 2];
+     HEAP32[i22 >> 2] = 0;
+     i7 = i7 + 1 | 0;
+    } while ((i7 | 0) < (i5 | 0));
+   }
+  } else {
+   i9 = i7 + (i5 + 16) | 0;
+  }
+  i7 = i3 + 16 | 0;
+  i5 = HEAP32[(HEAP32[i7 >> 2] | 0) + 12 >> 2] | 0;
+  if ((i5 | 0) == 0) {
+   i5 = _luaE_extendCI(i3) | 0;
+  }
+  HEAP32[i7 >> 2] = i5;
+  HEAP16[i5 + 16 >> 1] = i4;
+  HEAP32[i5 >> 2] = i6;
+  HEAP32[i5 + 24 >> 2] = i9;
+  i22 = i9 + (HEAPU8[i11] << 4) | 0;
+  HEAP32[i5 + 4 >> 2] = i22;
+  i4 = i5 + 28 | 0;
+  HEAP32[i4 >> 2] = HEAP32[i10 + 12 >> 2];
+  i6 = i5 + 18 | 0;
+  HEAP8[i6] = 1;
+  HEAP32[i2 >> 2] = i22;
+  if ((HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+   _luaC_step(i3);
+  }
+  if ((HEAP8[i3 + 40 | 0] & 1) == 0) {
+   i22 = 0;
+   STACKTOP = i1;
+   return i22 | 0;
+  }
+  HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 4;
+  i2 = HEAP32[i5 + 8 >> 2] | 0;
+  if (!((HEAP8[i2 + 18 | 0] & 1) == 0) ? (HEAP32[(HEAP32[i2 + 28 >> 2] | 0) + -4 >> 2] & 63 | 0) == 30 : 0) {
+   HEAP8[i6] = HEAPU8[i6] | 64;
+   i2 = 4;
+  } else {
+   i2 = 0;
+  }
+  _luaD_hook(i3, i2, -1);
+  HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -4;
+  i22 = 0;
+  STACKTOP = i1;
+  return i22 | 0;
+ } else if ((i11 | 0) == 54) {
+  _luaG_typeerror(i3, i17, 2520);
+ } else if ((i11 | 0) == 60) {
+  _luaD_throw(i3, 6);
+ } else if ((i11 | 0) == 62) {
+  _luaD_reallocstack(i3, 1000200);
+  _luaG_runerror(i3, 2224, i8);
+ }
+ i7 = HEAP32[i10 >> 2] | 0;
+ i9 = HEAP32[i2 >> 2] | 0;
+ do {
+  if (((HEAP32[i13 >> 2] | 0) - i9 | 0) < 336) {
+   i10 = HEAP32[i14 >> 2] | 0;
+   if ((i10 | 0) > 1e6) {
+    _luaD_throw(i3, 6);
+   }
+   i9 = (i9 - i12 >> 4) + 25 | 0;
+   i10 = i10 << 1;
+   i10 = (i10 | 0) > 1e6 ? 1e6 : i10;
+   i9 = (i10 | 0) < (i9 | 0) ? i9 : i10;
+   if ((i9 | 0) > 1e6) {
+    _luaD_reallocstack(i3, 1000200);
+    _luaG_runerror(i3, 2224, i8);
+   } else {
+    _luaD_reallocstack(i3, i9);
+    break;
+   }
+  }
+ } while (0);
+ i8 = i3 + 16 | 0;
+ i9 = HEAP32[(HEAP32[i8 >> 2] | 0) + 12 >> 2] | 0;
+ if ((i9 | 0) == 0) {
+  i9 = _luaE_extendCI(i3) | 0;
+ }
+ HEAP32[i8 >> 2] = i9;
+ HEAP16[i9 + 16 >> 1] = i4;
+ HEAP32[i9 >> 2] = (HEAP32[i6 >> 2] | 0) + i5;
+ HEAP32[i9 + 4 >> 2] = (HEAP32[i2 >> 2] | 0) + 320;
+ HEAP8[i9 + 18 | 0] = 0;
+ if ((HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i3);
+ }
+ i5 = i3 + 40 | 0;
+ if (!((HEAP8[i5] & 1) == 0)) {
+  _luaD_hook(i3, 0, -1);
+ }
+ i7 = FUNCTION_TABLE_ii[i7 & 255](i3) | 0;
+ i7 = (HEAP32[i2 >> 2] | 0) + (0 - i7 << 4) | 0;
+ i4 = HEAP32[i8 >> 2] | 0;
+ i5 = HEAPU8[i5] | 0;
+ if ((i5 & 6 | 0) == 0) {
+  i5 = i7;
+  i6 = i4 + 8 | 0;
+ } else {
+  if ((i5 & 2 | 0) == 0) {
+   i5 = i7;
+  } else {
+   i5 = i7 - (HEAP32[i6 >> 2] | 0) | 0;
+   _luaD_hook(i3, 1, -1);
+   i5 = (HEAP32[i6 >> 2] | 0) + i5 | 0;
+  }
+  i6 = i4 + 8 | 0;
+  HEAP32[i3 + 20 >> 2] = HEAP32[(HEAP32[i6 >> 2] | 0) + 28 >> 2];
+ }
+ i3 = HEAP32[i4 >> 2] | 0;
+ i4 = HEAP16[i4 + 16 >> 1] | 0;
+ HEAP32[i8 >> 2] = HEAP32[i6 >> 2];
+ L82 : do {
+  if (!(i4 << 16 >> 16 == 0)) {
+   i4 = i4 << 16 >> 16;
+   while (1) {
+    if (!(i5 >>> 0 < (HEAP32[i2 >> 2] | 0) >>> 0)) {
+     break;
+    }
+    i6 = i3 + 16 | 0;
+    i20 = i5;
+    i21 = HEAP32[i20 + 4 >> 2] | 0;
+    i22 = i3;
+    HEAP32[i22 >> 2] = HEAP32[i20 >> 2];
+    HEAP32[i22 + 4 >> 2] = i21;
+    HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+    i4 = i4 + -1 | 0;
+    if ((i4 | 0) == 0) {
+     i3 = i6;
+     break L82;
+    }
+    i5 = i5 + 16 | 0;
+    i3 = i6;
+   }
+   if ((i4 | 0) > 0) {
+    i5 = i4;
+    i6 = i3;
+    while (1) {
+     i5 = i5 + -1 | 0;
+     HEAP32[i6 + 8 >> 2] = 0;
+     if ((i5 | 0) <= 0) {
+      break;
+     } else {
+      i6 = i6 + 16 | 0;
+     }
+    }
+    i3 = i3 + (i4 << 4) | 0;
+   }
+  }
+ } while (0);
+ HEAP32[i2 >> 2] = i3;
+ i22 = 1;
+ STACKTOP = i1;
+ return i22 | 0;
+}
+function _lua_getinfo(i1, i6, i29) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i29 = i29 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i3;
+ if ((HEAP8[i6] | 0) == 62) {
+  i10 = i1 + 8 | 0;
+  i7 = (HEAP32[i10 >> 2] | 0) + -16 | 0;
+  HEAP32[i10 >> 2] = i7;
+  i6 = i6 + 1 | 0;
+  i10 = 0;
+ } else {
+  i7 = HEAP32[i29 + 96 >> 2] | 0;
+  i10 = i7;
+  i7 = HEAP32[i7 >> 2] | 0;
+ }
+ i8 = i7 + 8 | 0;
+ if ((HEAP32[i8 >> 2] & 31 | 0) == 6) {
+  i9 = HEAP32[i7 >> 2] | 0;
+ } else {
+  i9 = 0;
+ }
+ i34 = HEAP8[i6] | 0;
+ L8 : do {
+  if (i34 << 24 >> 24 == 0) {
+   i33 = 1;
+  } else {
+   i12 = (i9 | 0) == 0;
+   i27 = i29 + 16 | 0;
+   i28 = i29 + 24 | 0;
+   i21 = i29 + 28 | 0;
+   i25 = i29 + 12 | 0;
+   i26 = i29 + 36 | 0;
+   i19 = i9 + 4 | 0;
+   i24 = i9 + 12 | 0;
+   i18 = (i10 | 0) == 0;
+   i23 = i29 + 20 | 0;
+   i17 = i10 + 18 | 0;
+   i22 = i10 + 28 | 0;
+   i15 = i29 + 32 | 0;
+   i14 = i29 + 34 | 0;
+   i13 = i29 + 33 | 0;
+   i11 = i9 + 6 | 0;
+   i16 = i29 + 35 | 0;
+   i20 = i29 + 8 | 0;
+   i30 = i29 + 4 | 0;
+   i29 = i10 + 8 | 0;
+   i31 = i1 + 12 | 0;
+   i32 = i6;
+   i33 = 1;
+   while (1) {
+    L12 : do {
+     switch (i34 << 24 >> 24 | 0) {
+     case 116:
+      {
+       if (i18) {
+        i34 = 0;
+       } else {
+        i34 = HEAPU8[i17] & 64;
+       }
+       HEAP8[i16] = i34;
+       break;
+      }
+     case 110:
+      {
+       L18 : do {
+        if ((!i18 ? (HEAP8[i17] & 64) == 0 : 0) ? (i5 = HEAP32[i29 >> 2] | 0, !((HEAP8[i5 + 18 | 0] & 1) == 0)) : 0) {
+         i36 = HEAP32[(HEAP32[HEAP32[i5 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+         i35 = HEAP32[i36 + 12 >> 2] | 0;
+         i34 = ((HEAP32[i5 + 28 >> 2] | 0) - i35 >> 2) + -1 | 0;
+         i35 = HEAP32[i35 + (i34 << 2) >> 2] | 0;
+         switch (i35 & 63 | 0) {
+         case 10:
+         case 8:
+          {
+           i34 = 1;
+           i4 = 46;
+           break;
+          }
+         case 24:
+          {
+           i34 = 5;
+           i4 = 46;
+           break;
+          }
+         case 13:
+          {
+           i34 = 6;
+           i4 = 46;
+           break;
+          }
+         case 14:
+          {
+           i34 = 7;
+           i4 = 46;
+           break;
+          }
+         case 15:
+          {
+           i34 = 8;
+           i4 = 46;
+           break;
+          }
+         case 16:
+          {
+           i34 = 9;
+           i4 = 46;
+           break;
+          }
+         case 17:
+          {
+           i34 = 10;
+           i4 = 46;
+           break;
+          }
+         case 18:
+          {
+           i34 = 11;
+           i4 = 46;
+           break;
+          }
+         case 19:
+          {
+           i34 = 12;
+           i4 = 46;
+           break;
+          }
+         case 21:
+          {
+           i34 = 4;
+           i4 = 46;
+           break;
+          }
+         case 25:
+          {
+           i34 = 13;
+           i4 = 46;
+           break;
+          }
+         case 26:
+          {
+           i34 = 14;
+           i4 = 46;
+           break;
+          }
+         case 22:
+          {
+           i34 = 15;
+           i4 = 46;
+           break;
+          }
+         case 7:
+         case 6:
+         case 12:
+          {
+           i34 = 0;
+           i4 = 46;
+           break;
+          }
+         case 34:
+          {
+           i34 = 2120;
+           i35 = 2120;
+           break;
+          }
+         case 30:
+         case 29:
+          {
+           i36 = _getobjname(i36, i34, i35 >>> 6 & 255, i30) | 0;
+           HEAP32[i20 >> 2] = i36;
+           if ((i36 | 0) == 0) {
+            break L18;
+           } else {
+            break L12;
+           }
+          }
+         default:
+          {
+           i4 = 47;
+           break L18;
+          }
+         }
+         if ((i4 | 0) == 46) {
+          i4 = 0;
+          i34 = (HEAP32[(HEAP32[i31 >> 2] | 0) + (i34 << 2) + 184 >> 2] | 0) + 16 | 0;
+          i35 = 2136;
+         }
+         HEAP32[i30 >> 2] = i34;
+         HEAP32[i20 >> 2] = i35;
+         break L12;
+        } else {
+         i4 = 47;
+        }
+       } while (0);
+       if ((i4 | 0) == 47) {
+        i4 = 0;
+        HEAP32[i20 >> 2] = 0;
+       }
+       HEAP32[i20 >> 2] = 2112;
+       HEAP32[i30 >> 2] = 0;
+       break;
+      }
+     case 108:
+      {
+       if (!i18 ? !((HEAP8[i17] & 1) == 0) : 0) {
+        i35 = HEAP32[(HEAP32[HEAP32[i10 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+        i34 = HEAP32[i35 + 20 >> 2] | 0;
+        if ((i34 | 0) == 0) {
+         i34 = 0;
+        } else {
+         i34 = HEAP32[i34 + (((HEAP32[i22 >> 2] | 0) - (HEAP32[i35 + 12 >> 2] | 0) >> 2) + -1 << 2) >> 2] | 0;
+        }
+       } else {
+        i34 = -1;
+       }
+       HEAP32[i23 >> 2] = i34;
+       break;
+      }
+     case 83:
+      {
+       if (!i12 ? (HEAP8[i19] | 0) != 38 : 0) {
+        i34 = HEAP32[i24 >> 2] | 0;
+        i35 = HEAP32[i34 + 36 >> 2] | 0;
+        if ((i35 | 0) == 0) {
+         i35 = 2168;
+        } else {
+         i35 = i35 + 16 | 0;
+        }
+        HEAP32[i27 >> 2] = i35;
+        i36 = HEAP32[i34 + 64 >> 2] | 0;
+        HEAP32[i28 >> 2] = i36;
+        HEAP32[i21 >> 2] = HEAP32[i34 + 68 >> 2];
+        i34 = (i36 | 0) == 0 ? 2176 : 2184;
+       } else {
+        HEAP32[i27 >> 2] = 2152;
+        HEAP32[i28 >> 2] = -1;
+        HEAP32[i21 >> 2] = -1;
+        i35 = 2152;
+        i34 = 2160;
+       }
+       HEAP32[i25 >> 2] = i34;
+       _luaO_chunkid(i26, i35, 60);
+       break;
+      }
+     case 117:
+      {
+       if (!i12) {
+        HEAP8[i15] = HEAP8[i11] | 0;
+        if ((HEAP8[i19] | 0) != 38) {
+         HEAP8[i14] = HEAP8[(HEAP32[i24 >> 2] | 0) + 77 | 0] | 0;
+         HEAP8[i13] = HEAP8[(HEAP32[i24 >> 2] | 0) + 76 | 0] | 0;
+         break L12;
+        }
+       } else {
+        HEAP8[i15] = 0;
+       }
+       HEAP8[i14] = 1;
+       HEAP8[i13] = 0;
+       break;
+      }
+     case 102:
+     case 76:
+      {
+       break;
+      }
+     default:
+      {
+       i33 = 0;
+      }
+     }
+    } while (0);
+    i32 = i32 + 1 | 0;
+    i34 = HEAP8[i32] | 0;
+    if (i34 << 24 >> 24 == 0) {
+     break L8;
+    }
+   }
+  }
+ } while (0);
+ if ((_strchr(i6, 102) | 0) != 0) {
+  i36 = i1 + 8 | 0;
+  i35 = HEAP32[i36 >> 2] | 0;
+  i31 = i7;
+  i32 = HEAP32[i31 + 4 >> 2] | 0;
+  i34 = i35;
+  HEAP32[i34 >> 2] = HEAP32[i31 >> 2];
+  HEAP32[i34 + 4 >> 2] = i32;
+  HEAP32[i35 + 8 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i36 >> 2] = (HEAP32[i36 >> 2] | 0) + 16;
+ }
+ if ((_strchr(i6, 76) | 0) == 0) {
+  STACKTOP = i3;
+  return i33 | 0;
+ }
+ if ((i9 | 0) != 0 ? (HEAP8[i9 + 4 | 0] | 0) != 38 : 0) {
+  i6 = i9 + 12 | 0;
+  i5 = HEAP32[(HEAP32[i6 >> 2] | 0) + 20 >> 2] | 0;
+  i4 = _luaH_new(i1) | 0;
+  i36 = i1 + 8 | 0;
+  i35 = HEAP32[i36 >> 2] | 0;
+  HEAP32[i35 >> 2] = i4;
+  HEAP32[i35 + 8 >> 2] = 69;
+  HEAP32[i36 >> 2] = (HEAP32[i36 >> 2] | 0) + 16;
+  HEAP32[i2 >> 2] = 1;
+  HEAP32[i2 + 8 >> 2] = 1;
+  if ((HEAP32[(HEAP32[i6 >> 2] | 0) + 52 >> 2] | 0) > 0) {
+   i7 = 0;
+  } else {
+   STACKTOP = i3;
+   return i33 | 0;
+  }
+  do {
+   _luaH_setint(i1, i4, HEAP32[i5 + (i7 << 2) >> 2] | 0, i2);
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) < (HEAP32[(HEAP32[i6 >> 2] | 0) + 52 >> 2] | 0));
+  STACKTOP = i3;
+  return i33 | 0;
+ }
+ i36 = i1 + 8 | 0;
+ i35 = HEAP32[i36 >> 2] | 0;
+ HEAP32[i35 + 8 >> 2] = 0;
+ HEAP32[i36 >> 2] = i35 + 16;
+ STACKTOP = i3;
+ return i33 | 0;
+}
+function _read_long_string(i3, i1, i5) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0;
+ i2 = STACKTOP;
+ i14 = HEAP32[i3 >> 2] | 0;
+ i4 = i3 + 60 | 0;
+ i13 = HEAP32[i4 >> 2] | 0;
+ i15 = i13 + 4 | 0;
+ i16 = HEAP32[i15 >> 2] | 0;
+ i10 = i13 + 8 | 0;
+ i12 = HEAP32[i10 >> 2] | 0;
+ do {
+  if ((i16 + 1 | 0) >>> 0 > i12 >>> 0) {
+   if (i12 >>> 0 > 2147483645) {
+    _lexerror(i3, 12368, 0);
+   }
+   i16 = i12 << 1;
+   i17 = HEAP32[i3 + 52 >> 2] | 0;
+   if ((i16 | 0) == -2) {
+    _luaM_toobig(i17);
+   } else {
+    i8 = _luaM_realloc_(i17, HEAP32[i13 >> 2] | 0, i12, i16) | 0;
+    HEAP32[i13 >> 2] = i8;
+    HEAP32[i10 >> 2] = i16;
+    i9 = HEAP32[i15 >> 2] | 0;
+    break;
+   }
+  } else {
+   i9 = i16;
+   i8 = HEAP32[i13 >> 2] | 0;
+  }
+ } while (0);
+ HEAP32[i15 >> 2] = i9 + 1;
+ HEAP8[i8 + i9 | 0] = i14;
+ i9 = i3 + 56 | 0;
+ i8 = HEAP32[i9 >> 2] | 0;
+ i18 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i18 + -1;
+ if ((i18 | 0) == 0) {
+  i12 = _luaZ_fill(i8) | 0;
+ } else {
+  i18 = i8 + 4 | 0;
+  i12 = HEAP32[i18 >> 2] | 0;
+  HEAP32[i18 >> 2] = i12 + 1;
+  i12 = HEAPU8[i12] | 0;
+ }
+ HEAP32[i3 >> 2] = i12;
+ if ((i12 | 0) == 13 | (i12 | 0) == 10) {
+  _inclinenumber(i3);
+  i11 = 13;
+ }
+ L17 : while (1) {
+  if ((i11 | 0) == 13) {
+   i11 = 0;
+   i12 = HEAP32[i3 >> 2] | 0;
+  }
+  i8 = (i1 | 0) == 0;
+  i10 = i3 + 52 | 0;
+  L21 : do {
+   if (i8) {
+    while (1) {
+     if ((i12 | 0) == 13 | (i12 | 0) == 10) {
+      break L21;
+     } else if ((i12 | 0) == 93) {
+      i11 = 22;
+      break L21;
+     } else if ((i12 | 0) == -1) {
+      i11 = 21;
+      break L17;
+     }
+     i12 = HEAP32[i9 >> 2] | 0;
+     i18 = HEAP32[i12 >> 2] | 0;
+     HEAP32[i12 >> 2] = i18 + -1;
+     if ((i18 | 0) == 0) {
+      i12 = _luaZ_fill(i12) | 0;
+     } else {
+      i18 = i12 + 4 | 0;
+      i12 = HEAP32[i18 >> 2] | 0;
+      HEAP32[i18 >> 2] = i12 + 1;
+      i12 = HEAPU8[i12] | 0;
+     }
+     HEAP32[i3 >> 2] = i12;
+    }
+   } else {
+    while (1) {
+     if ((i12 | 0) == 13 | (i12 | 0) == 10) {
+      break L21;
+     } else if ((i12 | 0) == 93) {
+      i11 = 22;
+      break L21;
+     } else if ((i12 | 0) == -1) {
+      i11 = 21;
+      break L17;
+     }
+     i14 = HEAP32[i4 >> 2] | 0;
+     i13 = i14 + 4 | 0;
+     i17 = HEAP32[i13 >> 2] | 0;
+     i16 = i14 + 8 | 0;
+     i15 = HEAP32[i16 >> 2] | 0;
+     if ((i17 + 1 | 0) >>> 0 > i15 >>> 0) {
+      if (i15 >>> 0 > 2147483645) {
+       i11 = 46;
+       break L17;
+      }
+      i17 = i15 << 1;
+      i18 = HEAP32[i10 >> 2] | 0;
+      if ((i17 | 0) == -2) {
+       i11 = 48;
+       break L17;
+      }
+      i18 = _luaM_realloc_(i18, HEAP32[i14 >> 2] | 0, i15, i17) | 0;
+      HEAP32[i14 >> 2] = i18;
+      HEAP32[i16 >> 2] = i17;
+      i17 = HEAP32[i13 >> 2] | 0;
+      i14 = i18;
+     } else {
+      i14 = HEAP32[i14 >> 2] | 0;
+     }
+     HEAP32[i13 >> 2] = i17 + 1;
+     HEAP8[i14 + i17 | 0] = i12;
+     i12 = HEAP32[i9 >> 2] | 0;
+     i18 = HEAP32[i12 >> 2] | 0;
+     HEAP32[i12 >> 2] = i18 + -1;
+     if ((i18 | 0) == 0) {
+      i12 = _luaZ_fill(i12) | 0;
+     } else {
+      i18 = i12 + 4 | 0;
+      i12 = HEAP32[i18 >> 2] | 0;
+      HEAP32[i18 >> 2] = i12 + 1;
+      i12 = HEAPU8[i12] | 0;
+     }
+     HEAP32[i3 >> 2] = i12;
+    }
+   }
+  } while (0);
+  if ((i11 | 0) == 22) {
+   if ((_skip_sep(i3) | 0) == (i5 | 0)) {
+    i11 = 23;
+    break;
+   } else {
+    i11 = 13;
+    continue;
+   }
+  }
+  i12 = HEAP32[i4 >> 2] | 0;
+  i11 = i12 + 4 | 0;
+  i15 = HEAP32[i11 >> 2] | 0;
+  i14 = i12 + 8 | 0;
+  i13 = HEAP32[i14 >> 2] | 0;
+  if ((i15 + 1 | 0) >>> 0 > i13 >>> 0) {
+   if (i13 >>> 0 > 2147483645) {
+    i11 = 37;
+    break;
+   }
+   i15 = i13 << 1;
+   i10 = HEAP32[i10 >> 2] | 0;
+   if ((i15 | 0) == -2) {
+    i11 = 39;
+    break;
+   }
+   i10 = _luaM_realloc_(i10, HEAP32[i12 >> 2] | 0, i13, i15) | 0;
+   HEAP32[i12 >> 2] = i10;
+   HEAP32[i14 >> 2] = i15;
+   i15 = HEAP32[i11 >> 2] | 0;
+  } else {
+   i10 = HEAP32[i12 >> 2] | 0;
+  }
+  HEAP32[i11 >> 2] = i15 + 1;
+  HEAP8[i10 + i15 | 0] = 10;
+  _inclinenumber(i3);
+  if (!i8) {
+   i11 = 13;
+   continue;
+  }
+  HEAP32[(HEAP32[i4 >> 2] | 0) + 4 >> 2] = 0;
+  i11 = 13;
+ }
+ if ((i11 | 0) == 21) {
+  _lexerror(i3, (i1 | 0) != 0 ? 12512 : 12536, 286);
+ } else if ((i11 | 0) == 23) {
+  i15 = HEAP32[i3 >> 2] | 0;
+  i13 = HEAP32[i4 >> 2] | 0;
+  i14 = i13 + 4 | 0;
+  i16 = HEAP32[i14 >> 2] | 0;
+  i11 = i13 + 8 | 0;
+  i12 = HEAP32[i11 >> 2] | 0;
+  do {
+   if ((i16 + 1 | 0) >>> 0 > i12 >>> 0) {
+    if (i12 >>> 0 > 2147483645) {
+     _lexerror(i3, 12368, 0);
+    }
+    i17 = i12 << 1;
+    i16 = HEAP32[i10 >> 2] | 0;
+    if ((i17 | 0) == -2) {
+     _luaM_toobig(i16);
+    } else {
+     i6 = _luaM_realloc_(i16, HEAP32[i13 >> 2] | 0, i12, i17) | 0;
+     HEAP32[i13 >> 2] = i6;
+     HEAP32[i11 >> 2] = i17;
+     i7 = HEAP32[i14 >> 2] | 0;
+     break;
+    }
+   } else {
+    i7 = i16;
+    i6 = HEAP32[i13 >> 2] | 0;
+   }
+  } while (0);
+  HEAP32[i14 >> 2] = i7 + 1;
+  HEAP8[i6 + i7 | 0] = i15;
+  i6 = HEAP32[i9 >> 2] | 0;
+  i18 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i18 + -1;
+  if ((i18 | 0) == 0) {
+   i6 = _luaZ_fill(i6) | 0;
+  } else {
+   i18 = i6 + 4 | 0;
+   i6 = HEAP32[i18 >> 2] | 0;
+   HEAP32[i18 >> 2] = i6 + 1;
+   i6 = HEAPU8[i6] | 0;
+  }
+  HEAP32[i3 >> 2] = i6;
+  if (i8) {
+   STACKTOP = i2;
+   return;
+  }
+  i4 = HEAP32[i4 >> 2] | 0;
+  i5 = i5 + 2 | 0;
+  i6 = HEAP32[i10 >> 2] | 0;
+  i5 = _luaS_newlstr(i6, (HEAP32[i4 >> 2] | 0) + i5 | 0, (HEAP32[i4 + 4 >> 2] | 0) - (i5 << 1) | 0) | 0;
+  i4 = i6 + 8 | 0;
+  i7 = HEAP32[i4 >> 2] | 0;
+  HEAP32[i4 >> 2] = i7 + 16;
+  HEAP32[i7 >> 2] = i5;
+  HEAP32[i7 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 0 | 64;
+  i7 = _luaH_set(i6, HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 4 >> 2] | 0, (HEAP32[i4 >> 2] | 0) + -16 | 0) | 0;
+  i3 = i7 + 8 | 0;
+  if ((HEAP32[i3 >> 2] | 0) == 0 ? (HEAP32[i7 >> 2] = 1, HEAP32[i3 >> 2] = 1, (HEAP32[(HEAP32[i6 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) : 0) {
+   _luaC_step(i6);
+  }
+  HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -16;
+  HEAP32[i1 >> 2] = i5;
+  STACKTOP = i2;
+  return;
+ } else if ((i11 | 0) == 37) {
+  _lexerror(i3, 12368, 0);
+ } else if ((i11 | 0) == 39) {
+  _luaM_toobig(i10);
+ } else if ((i11 | 0) == 46) {
+  _lexerror(i3, 12368, 0);
+ } else if ((i11 | 0) == 48) {
+  _luaM_toobig(i18);
+ }
+}
+function _try_realloc_chunk(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i2 = STACKTOP;
+ i4 = i1 + 4 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ i8 = i6 & -8;
+ i5 = i1 + i8 | 0;
+ i10 = HEAP32[12928 >> 2] | 0;
+ if (i1 >>> 0 < i10 >>> 0) {
+  _abort();
+ }
+ i12 = i6 & 3;
+ if (!((i12 | 0) != 1 & i1 >>> 0 < i5 >>> 0)) {
+  _abort();
+ }
+ i7 = i1 + (i8 | 4) | 0;
+ i13 = HEAP32[i7 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i12 | 0) == 0) {
+  if (i3 >>> 0 < 256) {
+   i15 = 0;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  if (!(i8 >>> 0 < (i3 + 4 | 0) >>> 0) ? !((i8 - i3 | 0) >>> 0 > HEAP32[13392 >> 2] << 1 >>> 0) : 0) {
+   i15 = i1;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  i15 = 0;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ if (!(i8 >>> 0 < i3 >>> 0)) {
+  i5 = i8 - i3 | 0;
+  if (!(i5 >>> 0 > 15)) {
+   i15 = i1;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  HEAP32[i4 >> 2] = i6 & 1 | i3 | 2;
+  HEAP32[i1 + (i3 + 4) >> 2] = i5 | 3;
+  HEAP32[i7 >> 2] = HEAP32[i7 >> 2] | 1;
+  _dispose_chunk(i1 + i3 | 0, i5);
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ if ((i5 | 0) == (HEAP32[12936 >> 2] | 0)) {
+  i5 = (HEAP32[12924 >> 2] | 0) + i8 | 0;
+  if (!(i5 >>> 0 > i3 >>> 0)) {
+   i15 = 0;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  i15 = i5 - i3 | 0;
+  HEAP32[i4 >> 2] = i6 & 1 | i3 | 2;
+  HEAP32[i1 + (i3 + 4) >> 2] = i15 | 1;
+  HEAP32[12936 >> 2] = i1 + i3;
+  HEAP32[12924 >> 2] = i15;
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ if ((i5 | 0) == (HEAP32[12932 >> 2] | 0)) {
+  i7 = (HEAP32[12920 >> 2] | 0) + i8 | 0;
+  if (i7 >>> 0 < i3 >>> 0) {
+   i15 = 0;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+  i5 = i7 - i3 | 0;
+  if (i5 >>> 0 > 15) {
+   HEAP32[i4 >> 2] = i6 & 1 | i3 | 2;
+   HEAP32[i1 + (i3 + 4) >> 2] = i5 | 1;
+   HEAP32[i1 + i7 >> 2] = i5;
+   i15 = i1 + (i7 + 4) | 0;
+   HEAP32[i15 >> 2] = HEAP32[i15 >> 2] & -2;
+   i3 = i1 + i3 | 0;
+  } else {
+   HEAP32[i4 >> 2] = i6 & 1 | i7 | 2;
+   i3 = i1 + (i7 + 4) | 0;
+   HEAP32[i3 >> 2] = HEAP32[i3 >> 2] | 1;
+   i3 = 0;
+   i5 = 0;
+  }
+  HEAP32[12920 >> 2] = i5;
+  HEAP32[12932 >> 2] = i3;
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ if ((i13 & 2 | 0) != 0) {
+  i15 = 0;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ i7 = (i13 & -8) + i8 | 0;
+ if (i7 >>> 0 < i3 >>> 0) {
+  i15 = 0;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ i6 = i7 - i3 | 0;
+ i12 = i13 >>> 3;
+ do {
+  if (!(i13 >>> 0 < 256)) {
+   i11 = HEAP32[i1 + (i8 + 24) >> 2] | 0;
+   i13 = HEAP32[i1 + (i8 + 12) >> 2] | 0;
+   do {
+    if ((i13 | 0) == (i5 | 0)) {
+     i13 = i1 + (i8 + 20) | 0;
+     i12 = HEAP32[i13 >> 2] | 0;
+     if ((i12 | 0) == 0) {
+      i13 = i1 + (i8 + 16) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i9 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i15 = i12 + 20 | 0;
+      i14 = HEAP32[i15 >> 2] | 0;
+      if ((i14 | 0) != 0) {
+       i12 = i14;
+       i13 = i15;
+       continue;
+      }
+      i15 = i12 + 16 | 0;
+      i14 = HEAP32[i15 >> 2] | 0;
+      if ((i14 | 0) == 0) {
+       break;
+      } else {
+       i12 = i14;
+       i13 = i15;
+      }
+     }
+     if (i13 >>> 0 < i10 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i13 >> 2] = 0;
+      i9 = i12;
+      break;
+     }
+    } else {
+     i12 = HEAP32[i1 + (i8 + 8) >> 2] | 0;
+     if (i12 >>> 0 < i10 >>> 0) {
+      _abort();
+     }
+     i14 = i12 + 12 | 0;
+     if ((HEAP32[i14 >> 2] | 0) != (i5 | 0)) {
+      _abort();
+     }
+     i10 = i13 + 8 | 0;
+     if ((HEAP32[i10 >> 2] | 0) == (i5 | 0)) {
+      HEAP32[i14 >> 2] = i13;
+      HEAP32[i10 >> 2] = i12;
+      i9 = i13;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i11 | 0) != 0) {
+    i10 = HEAP32[i1 + (i8 + 28) >> 2] | 0;
+    i12 = 13216 + (i10 << 2) | 0;
+    if ((i5 | 0) == (HEAP32[i12 >> 2] | 0)) {
+     HEAP32[i12 >> 2] = i9;
+     if ((i9 | 0) == 0) {
+      HEAP32[12916 >> 2] = HEAP32[12916 >> 2] & ~(1 << i10);
+      break;
+     }
+    } else {
+     if (i11 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i10 = i11 + 16 | 0;
+     if ((HEAP32[i10 >> 2] | 0) == (i5 | 0)) {
+      HEAP32[i10 >> 2] = i9;
+     } else {
+      HEAP32[i11 + 20 >> 2] = i9;
+     }
+     if ((i9 | 0) == 0) {
+      break;
+     }
+    }
+    if (i9 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i9 + 24 >> 2] = i11;
+    i5 = HEAP32[i1 + (i8 + 16) >> 2] | 0;
+    do {
+     if ((i5 | 0) != 0) {
+      if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 16 >> 2] = i5;
+       HEAP32[i5 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    } while (0);
+    i5 = HEAP32[i1 + (i8 + 20) >> 2] | 0;
+    if ((i5 | 0) != 0) {
+     if (i5 >>> 0 < (HEAP32[12928 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i9 + 20 >> 2] = i5;
+      HEAP32[i5 + 24 >> 2] = i9;
+      break;
+     }
+    }
+   }
+  } else {
+   i9 = HEAP32[i1 + (i8 + 8) >> 2] | 0;
+   i8 = HEAP32[i1 + (i8 + 12) >> 2] | 0;
+   i13 = 12952 + (i12 << 1 << 2) | 0;
+   if ((i9 | 0) != (i13 | 0)) {
+    if (i9 >>> 0 < i10 >>> 0) {
+     _abort();
+    }
+    if ((HEAP32[i9 + 12 >> 2] | 0) != (i5 | 0)) {
+     _abort();
+    }
+   }
+   if ((i8 | 0) == (i9 | 0)) {
+    HEAP32[3228] = HEAP32[3228] & ~(1 << i12);
+    break;
+   }
+   if ((i8 | 0) != (i13 | 0)) {
+    if (i8 >>> 0 < i10 >>> 0) {
+     _abort();
+    }
+    i10 = i8 + 8 | 0;
+    if ((HEAP32[i10 >> 2] | 0) == (i5 | 0)) {
+     i11 = i10;
+    } else {
+     _abort();
+    }
+   } else {
+    i11 = i8 + 8 | 0;
+   }
+   HEAP32[i9 + 12 >> 2] = i8;
+   HEAP32[i11 >> 2] = i9;
+  }
+ } while (0);
+ if (i6 >>> 0 < 16) {
+  HEAP32[i4 >> 2] = i7 | HEAP32[i4 >> 2] & 1 | 2;
+  i15 = i1 + (i7 | 4) | 0;
+  HEAP32[i15 >> 2] = HEAP32[i15 >> 2] | 1;
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ } else {
+  HEAP32[i4 >> 2] = HEAP32[i4 >> 2] & 1 | i3 | 2;
+  HEAP32[i1 + (i3 + 4) >> 2] = i6 | 3;
+  i15 = i1 + (i7 | 4) | 0;
+  HEAP32[i15 >> 2] = HEAP32[i15 >> 2] | 1;
+  _dispose_chunk(i1 + i3 | 0, i6);
+  i15 = i1;
+  STACKTOP = i2;
+  return i15 | 0;
+ }
+ return 0;
+}
+function _luaK_posfix(i3, i16, i1, i4, i14) {
+ i3 = i3 | 0;
+ i16 = i16 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i14 = i14 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i15 = 0;
+ i2 = STACKTOP;
+ switch (i16 | 0) {
+ case 14:
+  {
+   _luaK_dischargevars(i3, i4);
+   i6 = i4 + 16 | 0;
+   i5 = HEAP32[i1 + 16 >> 2] | 0;
+   do {
+    if (!((i5 | 0) == -1)) {
+     i9 = HEAP32[i6 >> 2] | 0;
+     if ((i9 | 0) == -1) {
+      HEAP32[i6 >> 2] = i5;
+      break;
+     }
+     i7 = HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0;
+     while (1) {
+      i6 = i7 + (i9 << 2) | 0;
+      i8 = HEAP32[i6 >> 2] | 0;
+      i10 = (i8 >>> 14) + -131071 | 0;
+      if ((i10 | 0) == -1) {
+       break;
+      }
+      i10 = i9 + 1 + i10 | 0;
+      if ((i10 | 0) == -1) {
+       break;
+      } else {
+       i9 = i10;
+      }
+     }
+     i5 = i5 + ~i9 | 0;
+     if ((((i5 | 0) > -1 ? i5 : 0 - i5 | 0) | 0) > 131071) {
+      _luaX_syntaxerror(HEAP32[i3 + 12 >> 2] | 0, 10624);
+     } else {
+      HEAP32[i6 >> 2] = (i5 << 14) + 2147467264 | i8 & 16383;
+      break;
+     }
+    }
+   } while (0);
+   HEAP32[i1 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i1 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i1 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i1 + 12 >> 2] = HEAP32[i4 + 12 >> 2];
+   HEAP32[i1 + 16 >> 2] = HEAP32[i4 + 16 >> 2];
+   HEAP32[i1 + 20 >> 2] = HEAP32[i4 + 20 >> 2];
+   STACKTOP = i2;
+   return;
+  }
+ case 13:
+  {
+   _luaK_dischargevars(i3, i4);
+   i6 = i4 + 20 | 0;
+   i5 = HEAP32[i1 + 20 >> 2] | 0;
+   do {
+    if (!((i5 | 0) == -1)) {
+     i9 = HEAP32[i6 >> 2] | 0;
+     if ((i9 | 0) == -1) {
+      HEAP32[i6 >> 2] = i5;
+      break;
+     }
+     i7 = HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0;
+     while (1) {
+      i8 = i7 + (i9 << 2) | 0;
+      i6 = HEAP32[i8 >> 2] | 0;
+      i10 = (i6 >>> 14) + -131071 | 0;
+      if ((i10 | 0) == -1) {
+       break;
+      }
+      i10 = i9 + 1 + i10 | 0;
+      if ((i10 | 0) == -1) {
+       break;
+      } else {
+       i9 = i10;
+      }
+     }
+     i5 = i5 + ~i9 | 0;
+     if ((((i5 | 0) > -1 ? i5 : 0 - i5 | 0) | 0) > 131071) {
+      _luaX_syntaxerror(HEAP32[i3 + 12 >> 2] | 0, 10624);
+     } else {
+      HEAP32[i8 >> 2] = (i5 << 14) + 2147467264 | i6 & 16383;
+      break;
+     }
+    }
+   } while (0);
+   HEAP32[i1 + 0 >> 2] = HEAP32[i4 + 0 >> 2];
+   HEAP32[i1 + 4 >> 2] = HEAP32[i4 + 4 >> 2];
+   HEAP32[i1 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+   HEAP32[i1 + 12 >> 2] = HEAP32[i4 + 12 >> 2];
+   HEAP32[i1 + 16 >> 2] = HEAP32[i4 + 16 >> 2];
+   HEAP32[i1 + 20 >> 2] = HEAP32[i4 + 20 >> 2];
+   STACKTOP = i2;
+   return;
+  }
+ case 6:
+  {
+   i12 = i4 + 16 | 0;
+   i13 = i4 + 20 | 0;
+   i16 = (HEAP32[i12 >> 2] | 0) == (HEAP32[i13 >> 2] | 0);
+   _luaK_dischargevars(i3, i4);
+   do {
+    if (!i16) {
+     if ((HEAP32[i4 >> 2] | 0) == 6) {
+      i10 = HEAP32[i4 + 8 >> 2] | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (HEAP32[i13 >> 2] | 0)) {
+       break;
+      }
+      if ((i10 | 0) >= (HEAPU8[i3 + 46 | 0] | 0 | 0)) {
+       _exp2reg(i3, i4, i10);
+       break;
+      }
+     }
+     _luaK_exp2nextreg(i3, i4);
+    }
+   } while (0);
+   if ((HEAP32[i4 >> 2] | 0) == 11 ? (i5 = i4 + 8 | 0, i7 = HEAP32[i5 >> 2] | 0, i8 = (HEAP32[i3 >> 2] | 0) + 12 | 0, i9 = HEAP32[i8 >> 2] | 0, i6 = HEAP32[i9 + (i7 << 2) >> 2] | 0, (i6 & 63 | 0) == 22) : 0) {
+    i4 = i1 + 8 | 0;
+    if (((HEAP32[i1 >> 2] | 0) == 6 ? (i11 = HEAP32[i4 >> 2] | 0, (i11 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i11 | 0) : 0) {
+     i6 = i3 + 48 | 0;
+     HEAP8[i6] = (HEAP8[i6] | 0) + -1 << 24 >> 24;
+     i6 = HEAP32[i5 >> 2] | 0;
+     i16 = HEAP32[i8 >> 2] | 0;
+     i9 = i16;
+     i7 = i6;
+     i6 = HEAP32[i16 + (i6 << 2) >> 2] | 0;
+    }
+    HEAP32[i9 + (i7 << 2) >> 2] = HEAP32[i4 >> 2] << 23 | i6 & 8388607;
+    HEAP32[i1 >> 2] = 11;
+    HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+    STACKTOP = i2;
+    return;
+   }
+   _luaK_exp2nextreg(i3, i4);
+   _codearith(i3, 22, i1, i4, i14);
+   STACKTOP = i2;
+   return;
+  }
+ case 9:
+ case 8:
+ case 7:
+  {
+   i7 = i16 + 17 | 0;
+   i6 = _luaK_exp2RK(i3, i1) | 0;
+   i5 = _luaK_exp2RK(i3, i4) | 0;
+   if (((HEAP32[i4 >> 2] | 0) == 6 ? (i15 = HEAP32[i4 + 8 >> 2] | 0, (i15 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i15 | 0) : 0) {
+    i16 = i3 + 48 | 0;
+    HEAP8[i16] = (HEAP8[i16] | 0) + -1 << 24 >> 24;
+   }
+   i4 = i1 + 8 | 0;
+   if (((HEAP32[i1 >> 2] | 0) == 6 ? (i10 = HEAP32[i4 >> 2] | 0, (i10 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i10 | 0) : 0) {
+    i16 = i3 + 48 | 0;
+    HEAP8[i16] = (HEAP8[i16] | 0) + -1 << 24 >> 24;
+   }
+   HEAP32[i4 >> 2] = _condjump(i3, i7, 1, i6, i5) | 0;
+   HEAP32[i1 >> 2] = 10;
+   STACKTOP = i2;
+   return;
+  }
+ case 12:
+ case 11:
+ case 10:
+  {
+   i7 = i16 + 14 | 0;
+   i6 = _luaK_exp2RK(i3, i1) | 0;
+   i5 = _luaK_exp2RK(i3, i4) | 0;
+   if (((HEAP32[i4 >> 2] | 0) == 6 ? (i13 = HEAP32[i4 + 8 >> 2] | 0, (i13 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i13 | 0) : 0) {
+    i16 = i3 + 48 | 0;
+    HEAP8[i16] = (HEAP8[i16] | 0) + -1 << 24 >> 24;
+   }
+   i4 = i1 + 8 | 0;
+   if (((HEAP32[i1 >> 2] | 0) == 6 ? (i12 = HEAP32[i4 >> 2] | 0, (i12 & 256 | 0) == 0) : 0) ? (HEAPU8[i3 + 46 | 0] | 0 | 0) <= (i12 | 0) : 0) {
+    i16 = i3 + 48 | 0;
+    HEAP8[i16] = (HEAP8[i16] | 0) + -1 << 24 >> 24;
+   }
+   i8 = (i7 | 0) == 24;
+   HEAP32[i4 >> 2] = _condjump(i3, i7, i8 & 1 ^ 1, i8 ? i6 : i5, i8 ? i5 : i6) | 0;
+   HEAP32[i1 >> 2] = 10;
+   STACKTOP = i2;
+   return;
+  }
+ case 5:
+ case 4:
+ case 3:
+ case 2:
+ case 1:
+ case 0:
+  {
+   _codearith(i3, i16 + 13 | 0, i1, i4, i14);
+   STACKTOP = i2;
+   return;
+  }
+ default:
+  {
+   STACKTOP = i2;
+   return;
+  }
+ }
+}
+function _body(i1, i4, i13, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i13 = i13 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i3 = i6 + 12 | 0;
+ i14 = i6;
+ i2 = i1 + 48 | 0;
+ i19 = HEAP32[i2 >> 2] | 0;
+ i18 = i1 + 52 | 0;
+ i17 = HEAP32[i18 >> 2] | 0;
+ i16 = HEAP32[i19 >> 2] | 0;
+ i19 = i19 + 36 | 0;
+ i23 = i16 + 56 | 0;
+ i24 = HEAP32[i23 >> 2] | 0;
+ i15 = i16 + 16 | 0;
+ if (((HEAP32[i19 >> 2] | 0) >= (i24 | 0) ? (i21 = _luaM_growaux_(i17, HEAP32[i15 >> 2] | 0, i23, 4, 262143, 6512) | 0, HEAP32[i15 >> 2] = i21, i20 = HEAP32[i23 >> 2] | 0, (i24 | 0) < (i20 | 0)) : 0) ? (i22 = i24 + 1 | 0, HEAP32[i21 + (i24 << 2) >> 2] = 0, (i22 | 0) < (i20 | 0)) : 0) {
+  while (1) {
+   i21 = i22 + 1 | 0;
+   HEAP32[(HEAP32[i15 >> 2] | 0) + (i22 << 2) >> 2] = 0;
+   if ((i21 | 0) == (i20 | 0)) {
+    break;
+   } else {
+    i22 = i21;
+   }
+  }
+ }
+ i20 = _luaF_newproto(i17) | 0;
+ i24 = HEAP32[i19 >> 2] | 0;
+ HEAP32[i19 >> 2] = i24 + 1;
+ HEAP32[(HEAP32[i15 >> 2] | 0) + (i24 << 2) >> 2] = i20;
+ if (!((HEAP8[i20 + 5 | 0] & 3) == 0) ? !((HEAP8[i16 + 5 | 0] & 4) == 0) : 0) {
+  _luaC_barrier_(i17, i16, i20);
+ }
+ HEAP32[i3 >> 2] = i20;
+ HEAP32[i20 + 64 >> 2] = i5;
+ i16 = HEAP32[i18 >> 2] | 0;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i2 >> 2];
+ i17 = i3 + 12 | 0;
+ HEAP32[i17 >> 2] = i1;
+ HEAP32[i2 >> 2] = i3;
+ HEAP32[i3 + 20 >> 2] = 0;
+ HEAP32[i3 + 24 >> 2] = 0;
+ HEAP32[i3 + 28 >> 2] = -1;
+ HEAP32[i3 + 32 >> 2] = 0;
+ HEAP32[i3 + 36 >> 2] = 0;
+ i22 = i3 + 44 | 0;
+ i15 = i1 + 64 | 0;
+ HEAP32[i22 + 0 >> 2] = 0;
+ HEAP8[i22 + 4 | 0] = 0;
+ HEAP32[i3 + 40 >> 2] = HEAP32[(HEAP32[i15 >> 2] | 0) + 4 >> 2];
+ i15 = i3 + 16 | 0;
+ HEAP32[i15 >> 2] = 0;
+ HEAP32[i20 + 36 >> 2] = HEAP32[i1 + 68 >> 2];
+ HEAP8[i20 + 78 | 0] = 2;
+ i22 = _luaH_new(i16) | 0;
+ HEAP32[i3 + 4 >> 2] = i22;
+ i23 = i16 + 8 | 0;
+ i24 = HEAP32[i23 >> 2] | 0;
+ HEAP32[i24 >> 2] = i22;
+ HEAP32[i24 + 8 >> 2] = 69;
+ i24 = (HEAP32[i23 >> 2] | 0) + 16 | 0;
+ HEAP32[i23 >> 2] = i24;
+ if (((HEAP32[i16 + 24 >> 2] | 0) - i24 | 0) < 16) {
+  _luaD_growstack(i16, 0);
+ }
+ HEAP8[i14 + 10 | 0] = 0;
+ HEAP8[i14 + 8 | 0] = HEAP8[i3 + 46 | 0] | 0;
+ i24 = HEAP32[(HEAP32[i17 >> 2] | 0) + 64 >> 2] | 0;
+ HEAP16[i14 + 4 >> 1] = HEAP32[i24 + 28 >> 2];
+ HEAP16[i14 + 6 >> 1] = HEAP32[i24 + 16 >> 2];
+ HEAP8[i14 + 9 | 0] = 0;
+ HEAP32[i14 >> 2] = HEAP32[i15 >> 2];
+ HEAP32[i15 >> 2] = i14;
+ i14 = i1 + 16 | 0;
+ if ((HEAP32[i14 >> 2] | 0) != 40) {
+  _error_expected(i1, 40);
+ }
+ _luaX_next(i1);
+ if ((i13 | 0) != 0) {
+  _new_localvar(i1, _luaX_newstring(i1, 6456, 4) | 0);
+  i24 = HEAP32[i2 >> 2] | 0;
+  i22 = i24 + 46 | 0;
+  i23 = (HEAPU8[i22] | 0) + 1 | 0;
+  HEAP8[i22] = i23;
+  HEAP32[(HEAP32[(HEAP32[i24 >> 2] | 0) + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i24 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((i23 & 255) + -1 + (HEAP32[i24 + 40 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i24 + 20 >> 2];
+ }
+ i13 = HEAP32[i2 >> 2] | 0;
+ i15 = HEAP32[i13 >> 2] | 0;
+ i16 = i15 + 77 | 0;
+ HEAP8[i16] = 0;
+ i19 = HEAP32[i14 >> 2] | 0;
+ L20 : do {
+  if ((i19 | 0) != 41) {
+   i17 = i1 + 24 | 0;
+   i18 = 0;
+   while (1) {
+    if ((i19 | 0) == 280) {
+     i17 = 18;
+     break;
+    } else if ((i19 | 0) != 288) {
+     i17 = 19;
+     break;
+    }
+    i24 = HEAP32[i17 >> 2] | 0;
+    _luaX_next(i1);
+    _new_localvar(i1, i24);
+    i18 = i18 + 1 | 0;
+    if ((HEAP8[i16] | 0) != 0) {
+     i11 = i18;
+     break L20;
+    }
+    if ((HEAP32[i14 >> 2] | 0) != 44) {
+     i11 = i18;
+     break L20;
+    }
+    _luaX_next(i1);
+    i19 = HEAP32[i14 >> 2] | 0;
+   }
+   if ((i17 | 0) == 18) {
+    _luaX_next(i1);
+    HEAP8[i16] = 1;
+    i11 = i18;
+    break;
+   } else if ((i17 | 0) == 19) {
+    _luaX_syntaxerror(i1, 6464);
+   }
+  } else {
+   i11 = 0;
+  }
+ } while (0);
+ i18 = HEAP32[i2 >> 2] | 0;
+ i16 = i18 + 46 | 0;
+ i17 = (HEAPU8[i16] | 0) + i11 | 0;
+ HEAP8[i16] = i17;
+ if ((i11 | 0) != 0 ? (i8 = i18 + 20 | 0, i9 = i18 + 40 | 0, i7 = HEAP32[(HEAP32[i18 >> 2] | 0) + 24 >> 2] | 0, i10 = HEAP32[HEAP32[(HEAP32[i18 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0, HEAP32[i7 + ((HEAP16[i10 + ((i17 & 255) - i11 + (HEAP32[i9 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i8 >> 2], i12 = i11 + -1 | 0, (i12 | 0) != 0) : 0) {
+  do {
+   HEAP32[i7 + ((HEAP16[i10 + ((HEAPU8[i16] | 0) - i12 + (HEAP32[i9 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i8 >> 2];
+   i12 = i12 + -1 | 0;
+  } while ((i12 | 0) != 0);
+ }
+ i24 = i13 + 46 | 0;
+ HEAP8[i15 + 76 | 0] = HEAP8[i24] | 0;
+ _luaK_reserveregs(i13, HEAPU8[i24] | 0);
+ if ((HEAP32[i14 >> 2] | 0) != 41) {
+  _error_expected(i1, 41);
+ }
+ _luaX_next(i1);
+ L39 : while (1) {
+  i7 = HEAP32[i14 >> 2] | 0;
+  switch (i7 | 0) {
+  case 277:
+  case 286:
+  case 262:
+  case 261:
+  case 260:
+   {
+    i17 = 30;
+    break L39;
+   }
+  default:
+   {}
+  }
+  _statement(i1);
+  if ((i7 | 0) == 274) {
+   i17 = 30;
+   break;
+  }
+ }
+ if ((i17 | 0) == 30) {
+  HEAP32[(HEAP32[i3 >> 2] | 0) + 68 >> 2] = HEAP32[i1 + 4 >> 2];
+  _check_match(i1, 262, 265, i5);
+  i24 = HEAP32[(HEAP32[i2 >> 2] | 0) + 8 >> 2] | 0;
+  i23 = _luaK_codeABx(i24, 37, 0, (HEAP32[i24 + 36 >> 2] | 0) + -1 | 0) | 0;
+  HEAP32[i4 + 16 >> 2] = -1;
+  HEAP32[i4 + 20 >> 2] = -1;
+  HEAP32[i4 >> 2] = 11;
+  HEAP32[i4 + 8 >> 2] = i23;
+  _luaK_exp2nextreg(i24, i4);
+  _close_func(i1);
+  STACKTOP = i6;
+  return;
+ }
+}
+function _luaH_newkey(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, d21 = 0.0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 144 | 0;
+ i8 = i4 + 8 | 0;
+ i10 = i4;
+ i5 = i4 + 16 | 0;
+ i6 = i1 + 8 | 0;
+ i11 = HEAP32[i6 >> 2] | 0;
+ if ((i11 | 0) == 0) {
+  _luaG_runerror(i3, 7968, i8);
+ } else if ((i11 | 0) == 3) {
+  i15 = 3;
+ }
+ if ((i15 | 0) == 3 ? (d21 = +HEAPF64[i1 >> 3], !(d21 == d21 & 0.0 == 0.0)) : 0) {
+  _luaG_runerror(i3, 7992, i8);
+ }
+ i13 = _mainposition(i2, i1) | 0;
+ i14 = i13 + 8 | 0;
+ do {
+  if ((HEAP32[i14 >> 2] | 0) != 0 | (i13 | 0) == 8016) {
+   i18 = i2 + 20 | 0;
+   i11 = i2 + 16 | 0;
+   i17 = HEAP32[i11 >> 2] | 0;
+   i16 = HEAP32[i18 >> 2] | 0;
+   while (1) {
+    if (!(i16 >>> 0 > i17 >>> 0)) {
+     break;
+    }
+    i12 = i16 + -32 | 0;
+    HEAP32[i18 >> 2] = i12;
+    if ((HEAP32[i16 + -8 >> 2] | 0) == 0) {
+     i15 = 37;
+     break;
+    } else {
+     i16 = i12;
+    }
+   }
+   if ((i15 | 0) == 37) {
+    i5 = _mainposition(i2, i13 + 16 | 0) | 0;
+    if ((i5 | 0) == (i13 | 0)) {
+     i20 = i13 + 28 | 0;
+     HEAP32[i16 + -4 >> 2] = HEAP32[i20 >> 2];
+     HEAP32[i20 >> 2] = i12;
+     break;
+    } else {
+     i7 = i5;
+    }
+    do {
+     i5 = i7 + 28 | 0;
+     i7 = HEAP32[i5 >> 2] | 0;
+    } while ((i7 | 0) != (i13 | 0));
+    HEAP32[i5 >> 2] = i12;
+    HEAP32[i12 + 0 >> 2] = HEAP32[i13 + 0 >> 2];
+    HEAP32[i12 + 4 >> 2] = HEAP32[i13 + 4 >> 2];
+    HEAP32[i12 + 8 >> 2] = HEAP32[i13 + 8 >> 2];
+    HEAP32[i12 + 12 >> 2] = HEAP32[i13 + 12 >> 2];
+    HEAP32[i12 + 16 >> 2] = HEAP32[i13 + 16 >> 2];
+    HEAP32[i12 + 20 >> 2] = HEAP32[i13 + 20 >> 2];
+    HEAP32[i12 + 24 >> 2] = HEAP32[i13 + 24 >> 2];
+    HEAP32[i12 + 28 >> 2] = HEAP32[i13 + 28 >> 2];
+    HEAP32[i13 + 28 >> 2] = 0;
+    HEAP32[i14 >> 2] = 0;
+    i12 = i13;
+    break;
+   }
+   i13 = i5 + 0 | 0;
+   i12 = i13 + 124 | 0;
+   do {
+    HEAP32[i13 >> 2] = 0;
+    i13 = i13 + 4 | 0;
+   } while ((i13 | 0) < (i12 | 0));
+   i15 = i2 + 12 | 0;
+   i13 = HEAP32[i2 + 28 >> 2] | 0;
+   i12 = 0;
+   i20 = 1;
+   i16 = 0;
+   i14 = 1;
+   while (1) {
+    if ((i14 | 0) > (i13 | 0)) {
+     if ((i20 | 0) > (i13 | 0)) {
+      break;
+     } else {
+      i19 = i13;
+     }
+    } else {
+     i19 = i14;
+    }
+    if ((i20 | 0) > (i19 | 0)) {
+     i18 = i20;
+     i17 = 0;
+    } else {
+     i18 = HEAP32[i15 >> 2] | 0;
+     i17 = 0;
+     while (1) {
+      i17 = ((HEAP32[i18 + (i20 + -1 << 4) + 8 >> 2] | 0) != 0) + i17 | 0;
+      if ((i20 | 0) >= (i19 | 0)) {
+       break;
+      } else {
+       i20 = i20 + 1 | 0;
+      }
+     }
+     i18 = i19 + 1 | 0;
+    }
+    i20 = i5 + (i16 << 2) | 0;
+    HEAP32[i20 >> 2] = (HEAP32[i20 >> 2] | 0) + i17;
+    i12 = i17 + i12 | 0;
+    i16 = i16 + 1 | 0;
+    if ((i16 | 0) < 31) {
+     i20 = i18;
+     i14 = i14 << 1;
+    } else {
+     break;
+    }
+   }
+   i14 = 0;
+   i15 = 1 << (HEAPU8[i2 + 7 | 0] | 0);
+   i13 = 0;
+   L32 : while (1) {
+    i16 = i15;
+    while (1) {
+     i15 = i16 + -1 | 0;
+     if ((i16 | 0) == 0) {
+      break L32;
+     }
+     i16 = HEAP32[i11 >> 2] | 0;
+     if ((HEAP32[i16 + (i15 << 5) + 8 >> 2] | 0) == 0) {
+      i16 = i15;
+     } else {
+      break;
+     }
+    }
+    if (((HEAP32[i16 + (i15 << 5) + 24 >> 2] | 0) == 3 ? (d21 = +HEAPF64[i16 + (i15 << 5) + 16 >> 3], HEAPF64[i10 >> 3] = d21 + 6755399441055744.0, i9 = HEAP32[i10 >> 2] | 0, +(i9 | 0) == d21) : 0) ? (i9 + -1 | 0) >>> 0 < 1073741824 : 0) {
+     i16 = i5 + ((_luaO_ceillog2(i9) | 0) << 2) | 0;
+     HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) + 1;
+     i16 = 1;
+    } else {
+     i16 = 0;
+    }
+    i14 = i16 + i14 | 0;
+    i13 = i13 + 1 | 0;
+   }
+   i9 = i14 + i12 | 0;
+   if (((HEAP32[i6 >> 2] | 0) == 3 ? (d21 = +HEAPF64[i1 >> 3], HEAPF64[i8 >> 3] = d21 + 6755399441055744.0, i7 = HEAP32[i8 >> 2] | 0, +(i7 | 0) == d21) : 0) ? (i7 + -1 | 0) >>> 0 < 1073741824 : 0) {
+    i6 = i5 + ((_luaO_ceillog2(i7) | 0) << 2) | 0;
+    HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 1;
+    i6 = 1;
+   } else {
+    i6 = 0;
+   }
+   i7 = i9 + i6 | 0;
+   L49 : do {
+    if ((i7 | 0) > 0) {
+     i14 = 0;
+     i10 = 0;
+     i6 = 0;
+     i8 = 0;
+     i11 = 0;
+     i9 = 1;
+     while (1) {
+      i15 = HEAP32[i5 + (i6 << 2) >> 2] | 0;
+      if ((i15 | 0) > 0) {
+       i15 = i15 + i10 | 0;
+       i14 = (i15 | 0) > (i14 | 0);
+       i10 = i15;
+       i8 = i14 ? i9 : i8;
+       i11 = i14 ? i15 : i11;
+      }
+      if ((i10 | 0) == (i7 | 0)) {
+       break L49;
+      }
+      i9 = i9 << 1;
+      i14 = (i9 | 0) / 2 | 0;
+      if ((i14 | 0) < (i7 | 0)) {
+       i6 = i6 + 1 | 0;
+      } else {
+       break;
+      }
+     }
+    } else {
+     i8 = 0;
+     i11 = 0;
+    }
+   } while (0);
+   _luaH_resize(i3, i2, i8, i12 + 1 + i13 - i11 | 0);
+   i5 = _luaH_get(i2, i1) | 0;
+   if ((i5 | 0) != 5192) {
+    i20 = i5;
+    STACKTOP = i4;
+    return i20 | 0;
+   }
+   i20 = _luaH_newkey(i3, i2, i1) | 0;
+   STACKTOP = i4;
+   return i20 | 0;
+  } else {
+   i12 = i13;
+  }
+ } while (0);
+ i18 = i1;
+ i19 = HEAP32[i18 + 4 >> 2] | 0;
+ i20 = i12 + 16 | 0;
+ HEAP32[i20 >> 2] = HEAP32[i18 >> 2];
+ HEAP32[i20 + 4 >> 2] = i19;
+ HEAP32[i12 + 24 >> 2] = HEAP32[i6 >> 2];
+ if (((HEAP32[i6 >> 2] & 64 | 0) != 0 ? !((HEAP8[(HEAP32[i1 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) ? !((HEAP8[i2 + 5 | 0] & 4) == 0) : 0) {
+  _luaC_barrierback_(i3, i2);
+ }
+ i20 = i12;
+ STACKTOP = i4;
+ return i20 | 0;
+}
+function _luaV_concat(i7, i10) {
+ i7 = i7 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i9 = i5;
+ i8 = i5 + 8 | 0;
+ i6 = i7 + 8 | 0;
+ i2 = i7 + 12 | 0;
+ i3 = i7 + 28 | 0;
+ i4 = i7 + 16 | 0;
+ i11 = HEAP32[i6 >> 2] | 0;
+ L1 : while (1) {
+  i14 = i11 + -32 | 0;
+  i12 = i11 + -24 | 0;
+  i17 = HEAP32[i12 >> 2] | 0;
+  i13 = i11 + -16 | 0;
+  do {
+   if ((i17 & 15 | 0) == 4 | (i17 | 0) == 3) {
+    i15 = i11 + -8 | 0;
+    i16 = HEAP32[i15 >> 2] | 0;
+    if ((i16 & 15 | 0) == 4) {
+     i16 = i13;
+    } else {
+     if ((i16 | 0) != 3) {
+      i1 = 7;
+      break;
+     }
+     HEAPF64[tempDoublePtr >> 3] = +HEAPF64[i13 >> 3];
+     HEAP32[i9 >> 2] = HEAP32[tempDoublePtr >> 2];
+     HEAP32[i9 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+     i16 = _luaS_newlstr(i7, i8, _sprintf(i8 | 0, 8936, i9 | 0) | 0) | 0;
+     HEAP32[i13 >> 2] = i16;
+     HEAP32[i15 >> 2] = HEAPU8[i16 + 4 | 0] | 0 | 64;
+     i16 = i13;
+     i17 = HEAP32[i12 >> 2] | 0;
+    }
+    i16 = HEAP32[(HEAP32[i16 >> 2] | 0) + 12 >> 2] | 0;
+    i18 = (i17 & 15 | 0) == 4;
+    if ((i16 | 0) == 0) {
+     if (i18) {
+      i12 = 2;
+      break;
+     }
+     if ((i17 | 0) != 3) {
+      i12 = 2;
+      break;
+     }
+     HEAPF64[tempDoublePtr >> 3] = +HEAPF64[i14 >> 3];
+     HEAP32[i9 >> 2] = HEAP32[tempDoublePtr >> 2];
+     HEAP32[i9 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+     i18 = _luaS_newlstr(i7, i8, _sprintf(i8 | 0, 8936, i9 | 0) | 0) | 0;
+     HEAP32[i14 >> 2] = i18;
+     HEAP32[i12 >> 2] = HEAPU8[i18 + 4 | 0] | 0 | 64;
+     i12 = 2;
+     break;
+    }
+    if (i18 ? (HEAP32[(HEAP32[i14 >> 2] | 0) + 12 >> 2] | 0) == 0 : 0) {
+     i16 = i13;
+     i17 = HEAP32[i16 + 4 >> 2] | 0;
+     i18 = i14;
+     HEAP32[i18 >> 2] = HEAP32[i16 >> 2];
+     HEAP32[i18 + 4 >> 2] = i17;
+     HEAP32[i12 >> 2] = HEAP32[i15 >> 2];
+     i12 = 2;
+     break;
+    }
+    L19 : do {
+     if ((i10 | 0) > 1) {
+      i12 = 1;
+      do {
+       i15 = ~i12;
+       i14 = i11 + (i15 << 4) | 0;
+       i15 = i11 + (i15 << 4) + 8 | 0;
+       i13 = HEAP32[i15 >> 2] | 0;
+       if ((i13 & 15 | 0) != 4) {
+        if ((i13 | 0) != 3) {
+         break L19;
+        }
+        HEAPF64[tempDoublePtr >> 3] = +HEAPF64[i14 >> 3];
+        HEAP32[i9 >> 2] = HEAP32[tempDoublePtr >> 2];
+        HEAP32[i9 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+        i18 = _luaS_newlstr(i7, i8, _sprintf(i8 | 0, 8936, i9 | 0) | 0) | 0;
+        HEAP32[i14 >> 2] = i18;
+        HEAP32[i15 >> 2] = HEAPU8[i18 + 4 | 0] | 0 | 64;
+       }
+       i13 = HEAP32[(HEAP32[i14 >> 2] | 0) + 12 >> 2] | 0;
+       if (!(i13 >>> 0 < (-3 - i16 | 0) >>> 0)) {
+        i1 = 24;
+        break L1;
+       }
+       i16 = i13 + i16 | 0;
+       i12 = i12 + 1 | 0;
+      } while ((i12 | 0) < (i10 | 0));
+     } else {
+      i12 = 1;
+     }
+    } while (0);
+    i14 = _luaZ_openspace(i7, (HEAP32[i2 >> 2] | 0) + 144 | 0, i16) | 0;
+    i15 = i12;
+    i13 = 0;
+    do {
+     i17 = HEAP32[i11 + (0 - i15 << 4) >> 2] | 0;
+     i18 = HEAP32[i17 + 12 >> 2] | 0;
+     _memcpy(i14 + i13 | 0, i17 + 16 | 0, i18 | 0) | 0;
+     i13 = i18 + i13 | 0;
+     i15 = i15 + -1 | 0;
+    } while ((i15 | 0) > 0);
+    i18 = 0 - i12 | 0;
+    i17 = _luaS_newlstr(i7, i14, i13) | 0;
+    HEAP32[i11 + (i18 << 4) >> 2] = i17;
+    HEAP32[i11 + (i18 << 4) + 8 >> 2] = HEAPU8[i17 + 4 | 0] | 0 | 64;
+   } else {
+    i1 = 7;
+   }
+  } while (0);
+  if ((i1 | 0) == 7) {
+   i1 = 0;
+   i15 = _luaT_gettmbyobj(i7, i14, 15) | 0;
+   if ((HEAP32[i15 + 8 >> 2] | 0) == 0) {
+    i15 = _luaT_gettmbyobj(i7, i13, 15) | 0;
+    if ((HEAP32[i15 + 8 >> 2] | 0) == 0) {
+     i1 = 10;
+     break;
+    }
+   }
+   i18 = i14 - (HEAP32[i3 >> 2] | 0) | 0;
+   i16 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i16 + 16;
+   i20 = i15;
+   i19 = HEAP32[i20 + 4 >> 2] | 0;
+   i17 = i16;
+   HEAP32[i17 >> 2] = HEAP32[i20 >> 2];
+   HEAP32[i17 + 4 >> 2] = i19;
+   HEAP32[i16 + 8 >> 2] = HEAP32[i15 + 8 >> 2];
+   i15 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i15 + 16;
+   i16 = i14;
+   i17 = HEAP32[i16 + 4 >> 2] | 0;
+   i14 = i15;
+   HEAP32[i14 >> 2] = HEAP32[i16 >> 2];
+   HEAP32[i14 + 4 >> 2] = i17;
+   HEAP32[i15 + 8 >> 2] = HEAP32[i12 >> 2];
+   i12 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i12 + 16;
+   i15 = i13;
+   i14 = HEAP32[i15 + 4 >> 2] | 0;
+   i17 = i12;
+   HEAP32[i17 >> 2] = HEAP32[i15 >> 2];
+   HEAP32[i17 + 4 >> 2] = i14;
+   HEAP32[i12 + 8 >> 2] = HEAP32[i11 + -8 >> 2];
+   _luaD_call(i7, (HEAP32[i6 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i4 >> 2] | 0) + 18 | 0] & 1);
+   i12 = HEAP32[i3 >> 2] | 0;
+   i17 = HEAP32[i6 >> 2] | 0;
+   i14 = i17 + -16 | 0;
+   HEAP32[i6 >> 2] = i14;
+   i15 = HEAP32[i14 + 4 >> 2] | 0;
+   i16 = i12 + i18 | 0;
+   HEAP32[i16 >> 2] = HEAP32[i14 >> 2];
+   HEAP32[i16 + 4 >> 2] = i15;
+   HEAP32[i12 + (i18 + 8) >> 2] = HEAP32[i17 + -8 >> 2];
+   i12 = 2;
+  }
+  i10 = i10 + 1 - i12 | 0;
+  i11 = (HEAP32[i6 >> 2] | 0) + (1 - i12 << 4) | 0;
+  HEAP32[i6 >> 2] = i11;
+  if ((i10 | 0) <= 1) {
+   i1 = 30;
+   break;
+  }
+ }
+ if ((i1 | 0) == 10) {
+  _luaG_concaterror(i7, i14, i13);
+ } else if ((i1 | 0) == 24) {
+  _luaG_runerror(i7, 9e3, i9);
+ } else if ((i1 | 0) == 30) {
+  STACKTOP = i5;
+  return;
+ }
+}
+function _str_gsub(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 1344 | 0;
+ i4 = i3;
+ i5 = i3 + 1336 | 0;
+ i14 = i3 + 1332 | 0;
+ i10 = i3 + 1328 | 0;
+ i6 = i3 + 1048 | 0;
+ i2 = i3 + 8 | 0;
+ i20 = _luaL_checklstring(i1, 1, i14) | 0;
+ i13 = _luaL_checklstring(i1, 2, i10) | 0;
+ i8 = _lua_type(i1, 3) | 0;
+ i9 = _luaL_optinteger(i1, 4, (HEAP32[i14 >> 2] | 0) + 1 | 0) | 0;
+ i7 = (HEAP8[i13] | 0) == 94;
+ if (!((i8 + -3 | 0) >>> 0 < 2 | (i8 | 0) == 6 | (i8 | 0) == 5)) {
+  _luaL_argerror(i1, 3, 7528) | 0;
+ }
+ _luaL_buffinit(i1, i2);
+ if (i7) {
+  i15 = (HEAP32[i10 >> 2] | 0) + -1 | 0;
+  HEAP32[i10 >> 2] = i15;
+  i13 = i13 + 1 | 0;
+ } else {
+  i15 = HEAP32[i10 >> 2] | 0;
+ }
+ i11 = i6 + 16 | 0;
+ HEAP32[i11 >> 2] = i1;
+ HEAP32[i6 >> 2] = 200;
+ i12 = i6 + 4 | 0;
+ HEAP32[i12 >> 2] = i20;
+ i10 = i6 + 8 | 0;
+ HEAP32[i10 >> 2] = i20 + (HEAP32[i14 >> 2] | 0);
+ HEAP32[i6 + 12 >> 2] = i13 + i15;
+ i14 = i6 + 20 | 0;
+ i15 = i2 + 8 | 0;
+ i18 = i2 + 4 | 0;
+ i16 = i6 + 28 | 0;
+ i17 = i6 + 24 | 0;
+ i22 = 0;
+ while (1) {
+  if (!(i22 >>> 0 < i9 >>> 0)) {
+   i19 = 48;
+   break;
+  }
+  HEAP32[i14 >> 2] = 0;
+  i21 = _match(i6, i20, i13) | 0;
+  if ((i21 | 0) != 0) {
+   i22 = i22 + 1 | 0;
+   i23 = HEAP32[i11 >> 2] | 0;
+   if ((i8 | 0) == 5) {
+    do {
+     if ((HEAP32[i14 >> 2] | 0) > 0) {
+      i24 = HEAP32[i16 >> 2] | 0;
+      if (!((i24 | 0) == -1)) {
+       i25 = HEAP32[i17 >> 2] | 0;
+       if ((i24 | 0) == -2) {
+        _lua_pushinteger(i23, i25 + 1 - (HEAP32[i12 >> 2] | 0) | 0);
+        break;
+       } else {
+        i19 = i23;
+       }
+      } else {
+       _luaL_error(i23, 7248, i4) | 0;
+       i19 = HEAP32[i11 >> 2] | 0;
+       i25 = HEAP32[i17 >> 2] | 0;
+      }
+      _lua_pushlstring(i19, i25, i24) | 0;
+     } else {
+      _lua_pushlstring(i23, i20, i21 - i20 | 0) | 0;
+     }
+    } while (0);
+    _lua_gettable(i23, 3);
+    i19 = 37;
+   } else if ((i8 | 0) != 6) {
+    i24 = _lua_tolstring(i23, 3, i5) | 0;
+    if ((HEAP32[i5 >> 2] | 0) != 0) {
+     i23 = i21 - i20 | 0;
+     i25 = 0;
+     do {
+      i26 = i24 + i25 | 0;
+      i27 = HEAP8[i26] | 0;
+      do {
+       if (i27 << 24 >> 24 == 37) {
+        i25 = i25 + 1 | 0;
+        i26 = i24 + i25 | 0;
+        i28 = HEAP8[i26] | 0;
+        i27 = i28 << 24 >> 24;
+        if (((i28 & 255) + -48 | 0) >>> 0 < 10) {
+         if (i28 << 24 >> 24 == 48) {
+          _luaL_addlstring(i2, i20, i23);
+          break;
+         } else {
+          _push_onecapture(i6, i27 + -49 | 0, i20, i21);
+          _luaL_addvalue(i2);
+          break;
+         }
+        }
+        if (!(i28 << 24 >> 24 == 37)) {
+         i28 = HEAP32[i11 >> 2] | 0;
+         HEAP32[i4 >> 2] = 37;
+         _luaL_error(i28, 7600, i4) | 0;
+        }
+        i27 = HEAP32[i15 >> 2] | 0;
+        if (!(i27 >>> 0 < (HEAP32[i18 >> 2] | 0) >>> 0)) {
+         _luaL_prepbuffsize(i2, 1) | 0;
+         i27 = HEAP32[i15 >> 2] | 0;
+        }
+        i28 = HEAP8[i26] | 0;
+        HEAP32[i15 >> 2] = i27 + 1;
+        HEAP8[(HEAP32[i2 >> 2] | 0) + i27 | 0] = i28;
+       } else {
+        i28 = HEAP32[i15 >> 2] | 0;
+        if (!(i28 >>> 0 < (HEAP32[i18 >> 2] | 0) >>> 0)) {
+         _luaL_prepbuffsize(i2, 1) | 0;
+         i28 = HEAP32[i15 >> 2] | 0;
+         i27 = HEAP8[i26] | 0;
+        }
+        HEAP32[i15 >> 2] = i28 + 1;
+        HEAP8[(HEAP32[i2 >> 2] | 0) + i28 | 0] = i27;
+       }
+      } while (0);
+      i25 = i25 + 1 | 0;
+     } while (i25 >>> 0 < (HEAP32[i5 >> 2] | 0) >>> 0);
+    }
+   } else {
+    _lua_pushvalue(i23, 3);
+    i19 = HEAP32[i14 >> 2] | 0;
+    i19 = (i19 | 0) != 0 | (i20 | 0) == 0 ? i19 : 1;
+    _luaL_checkstack(HEAP32[i11 >> 2] | 0, i19, 7200);
+    if ((i19 | 0) > 0) {
+     i24 = 0;
+     do {
+      _push_onecapture(i6, i24, i20, i21);
+      i24 = i24 + 1 | 0;
+     } while ((i24 | 0) != (i19 | 0));
+    }
+    _lua_callk(i23, i19, 1, 0, 0);
+    i19 = 37;
+   }
+   if ((i19 | 0) == 37) {
+    i19 = 0;
+    if ((_lua_toboolean(i23, -1) | 0) != 0) {
+     if ((_lua_isstring(i23, -1) | 0) == 0) {
+      HEAP32[i4 >> 2] = _lua_typename(i23, _lua_type(i23, -1) | 0) | 0;
+      _luaL_error(i23, 7560, i4) | 0;
+     }
+    } else {
+     _lua_settop(i23, -2);
+     _lua_pushlstring(i23, i20, i21 - i20 | 0) | 0;
+    }
+    _luaL_addvalue(i2);
+   }
+   if (i21 >>> 0 > i20 >>> 0) {
+    i20 = i21;
+   } else {
+    i19 = 43;
+   }
+  } else {
+   i19 = 43;
+  }
+  if ((i19 | 0) == 43) {
+   i19 = 0;
+   if (!(i20 >>> 0 < (HEAP32[i10 >> 2] | 0) >>> 0)) {
+    i19 = 48;
+    break;
+   }
+   i21 = HEAP32[i15 >> 2] | 0;
+   if (!(i21 >>> 0 < (HEAP32[i18 >> 2] | 0) >>> 0)) {
+    _luaL_prepbuffsize(i2, 1) | 0;
+    i21 = HEAP32[i15 >> 2] | 0;
+   }
+   i28 = HEAP8[i20] | 0;
+   HEAP32[i15 >> 2] = i21 + 1;
+   HEAP8[(HEAP32[i2 >> 2] | 0) + i21 | 0] = i28;
+   i20 = i20 + 1 | 0;
+  }
+  if (i7) {
+   i19 = 48;
+   break;
+  }
+ }
+ if ((i19 | 0) == 48) {
+  _luaL_addlstring(i2, i20, (HEAP32[i10 >> 2] | 0) - i20 | 0);
+  _luaL_pushresult(i2);
+  _lua_pushinteger(i1, i22);
+  STACKTOP = i3;
+  return 2;
+ }
+ return 0;
+}
+function _constructor(i11, i13) {
+ i11 = i11 | 0;
+ i13 = i13 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i10 = i5 + 40 | 0;
+ i8 = i5;
+ i12 = i11 + 48 | 0;
+ i6 = HEAP32[i12 >> 2] | 0;
+ i9 = HEAP32[i11 + 4 >> 2] | 0;
+ i2 = _luaK_codeABC(i6, 11, 0, 0, 0) | 0;
+ i7 = i8 + 36 | 0;
+ HEAP32[i7 >> 2] = 0;
+ i4 = i8 + 28 | 0;
+ HEAP32[i4 >> 2] = 0;
+ i3 = i8 + 32 | 0;
+ HEAP32[i3 >> 2] = 0;
+ i1 = i8 + 24 | 0;
+ HEAP32[i1 >> 2] = i13;
+ HEAP32[i13 + 16 >> 2] = -1;
+ HEAP32[i13 + 20 >> 2] = -1;
+ HEAP32[i13 >> 2] = 11;
+ HEAP32[i13 + 8 >> 2] = i2;
+ HEAP32[i8 + 16 >> 2] = -1;
+ HEAP32[i8 + 20 >> 2] = -1;
+ HEAP32[i8 >> 2] = 0;
+ HEAP32[i8 + 8 >> 2] = 0;
+ _luaK_exp2nextreg(HEAP32[i12 >> 2] | 0, i13);
+ i13 = i11 + 16 | 0;
+ if ((HEAP32[i13 >> 2] | 0) != 123) {
+  _error_expected(i11, 123);
+ }
+ _luaX_next(i11);
+ L4 : do {
+  if ((HEAP32[i13 >> 2] | 0) != 125) {
+   L5 : while (1) {
+    if ((HEAP32[i8 >> 2] | 0) != 0 ? (_luaK_exp2nextreg(i6, i8), HEAP32[i8 >> 2] = 0, (HEAP32[i7 >> 2] | 0) == 50) : 0) {
+     _luaK_setlist(i6, HEAP32[(HEAP32[i1 >> 2] | 0) + 8 >> 2] | 0, HEAP32[i3 >> 2] | 0, 50);
+     HEAP32[i7 >> 2] = 0;
+    }
+    i14 = HEAP32[i13 >> 2] | 0;
+    do {
+     if ((i14 | 0) == 288) {
+      if ((_luaX_lookahead(i11) | 0) == 61) {
+       _recfield(i11, i8);
+       break;
+      }
+      _subexpr(i11, i8, 0) | 0;
+      i14 = HEAP32[i12 >> 2] | 0;
+      i15 = HEAP32[i3 >> 2] | 0;
+      if ((i15 | 0) > 2147483645) {
+       i12 = 10;
+       break L5;
+      }
+      HEAP32[i3 >> 2] = i15 + 1;
+      HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + 1;
+     } else if ((i14 | 0) == 91) {
+      _recfield(i11, i8);
+     } else {
+      _subexpr(i11, i8, 0) | 0;
+      i14 = HEAP32[i12 >> 2] | 0;
+      i15 = HEAP32[i3 >> 2] | 0;
+      if ((i15 | 0) > 2147483645) {
+       i12 = 17;
+       break L5;
+      }
+      HEAP32[i3 >> 2] = i15 + 1;
+      HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + 1;
+     }
+    } while (0);
+    i14 = HEAP32[i13 >> 2] | 0;
+    if ((i14 | 0) == 44) {
+     _luaX_next(i11);
+    } else if ((i14 | 0) == 59) {
+     _luaX_next(i11);
+    } else {
+     break L4;
+    }
+    if ((HEAP32[i13 >> 2] | 0) == 125) {
+     break L4;
+    }
+   }
+   if ((i12 | 0) == 10) {
+    i12 = i14 + 12 | 0;
+    i13 = HEAP32[(HEAP32[i12 >> 2] | 0) + 52 >> 2] | 0;
+    i14 = HEAP32[(HEAP32[i14 >> 2] | 0) + 64 >> 2] | 0;
+    if ((i14 | 0) == 0) {
+     i16 = 6552;
+     HEAP32[i10 >> 2] = 6528;
+     i15 = i10 + 4 | 0;
+     HEAP32[i15 >> 2] = 2147483645;
+     i15 = i10 + 8 | 0;
+     HEAP32[i15 >> 2] = i16;
+     i15 = _luaO_pushfstring(i13, 6592, i10) | 0;
+     i16 = HEAP32[i12 >> 2] | 0;
+     _luaX_syntaxerror(i16, i15);
+    }
+    HEAP32[i10 >> 2] = i14;
+    i15 = _luaO_pushfstring(i13, 6568, i10) | 0;
+    HEAP32[i10 >> 2] = 6528;
+    i16 = i10 + 4 | 0;
+    HEAP32[i16 >> 2] = 2147483645;
+    i16 = i10 + 8 | 0;
+    HEAP32[i16 >> 2] = i15;
+    i16 = _luaO_pushfstring(i13, 6592, i10) | 0;
+    i15 = HEAP32[i12 >> 2] | 0;
+    _luaX_syntaxerror(i15, i16);
+   } else if ((i12 | 0) == 17) {
+    i13 = i14 + 12 | 0;
+    i12 = HEAP32[(HEAP32[i13 >> 2] | 0) + 52 >> 2] | 0;
+    i14 = HEAP32[(HEAP32[i14 >> 2] | 0) + 64 >> 2] | 0;
+    if ((i14 | 0) == 0) {
+     i15 = 6552;
+     HEAP32[i10 >> 2] = 6528;
+     i16 = i10 + 4 | 0;
+     HEAP32[i16 >> 2] = 2147483645;
+     i16 = i10 + 8 | 0;
+     HEAP32[i16 >> 2] = i15;
+     i16 = _luaO_pushfstring(i12, 6592, i10) | 0;
+     i15 = HEAP32[i13 >> 2] | 0;
+     _luaX_syntaxerror(i15, i16);
+    }
+    HEAP32[i10 >> 2] = i14;
+    i15 = _luaO_pushfstring(i12, 6568, i10) | 0;
+    HEAP32[i10 >> 2] = 6528;
+    i16 = i10 + 4 | 0;
+    HEAP32[i16 >> 2] = 2147483645;
+    i16 = i10 + 8 | 0;
+    HEAP32[i16 >> 2] = i15;
+    i16 = _luaO_pushfstring(i12, 6592, i10) | 0;
+    i15 = HEAP32[i13 >> 2] | 0;
+    _luaX_syntaxerror(i15, i16);
+   }
+  }
+ } while (0);
+ _check_match(i11, 125, 123, i9);
+ i9 = HEAP32[i7 >> 2] | 0;
+ do {
+  if ((i9 | 0) != 0) {
+   i10 = HEAP32[i8 >> 2] | 0;
+   if ((i10 | 0) != 0) if ((i10 | 0) == 13 | (i10 | 0) == 12) {
+    _luaK_setreturns(i6, i8, -1);
+    _luaK_setlist(i6, HEAP32[(HEAP32[i1 >> 2] | 0) + 8 >> 2] | 0, HEAP32[i3 >> 2] | 0, -1);
+    HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + -1;
+    break;
+   } else {
+    _luaK_exp2nextreg(i6, i8);
+    i9 = HEAP32[i7 >> 2] | 0;
+   }
+   _luaK_setlist(i6, HEAP32[(HEAP32[i1 >> 2] | 0) + 8 >> 2] | 0, HEAP32[i3 >> 2] | 0, i9);
+  }
+ } while (0);
+ i16 = HEAP32[(HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) + (i2 << 2) >> 2] & 8388607;
+ i16 = (_luaO_int2fb(HEAP32[i3 >> 2] | 0) | 0) << 23 | i16;
+ HEAP32[(HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) + (i2 << 2) >> 2] = i16;
+ i16 = (_luaO_int2fb(HEAP32[i4 >> 2] | 0) | 0) << 14 & 8372224 | i16 & -8372225;
+ HEAP32[(HEAP32[(HEAP32[i6 >> 2] | 0) + 12 >> 2] | 0) + (i2 << 2) >> 2] = i16;
+ STACKTOP = i5;
+ return;
+}
+function _luaK_prefix(i4, i14, i7, i13) {
+ i4 = i4 | 0;
+ i14 = i14 | 0;
+ i7 = i7 | 0;
+ i13 = i13 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i12 = i1;
+ HEAP32[i12 + 20 >> 2] = -1;
+ HEAP32[i12 + 16 >> 2] = -1;
+ HEAP32[i12 >> 2] = 5;
+ HEAPF64[i12 + 8 >> 3] = 0.0;
+ if ((i14 | 0) == 1) {
+  _luaK_dischargevars(i4, i7);
+  switch (HEAP32[i7 >> 2] | 0) {
+  case 2:
+  case 5:
+  case 4:
+   {
+    HEAP32[i7 >> 2] = 3;
+    break;
+   }
+  case 10:
+   {
+    i13 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+    i12 = HEAP32[i7 + 8 >> 2] | 0;
+    i10 = i13 + (i12 << 2) | 0;
+    if (!((i12 | 0) > 0 ? (i11 = i13 + (i12 + -1 << 2) | 0, i9 = HEAP32[i11 >> 2] | 0, (HEAP8[5584 + (i9 & 63) | 0] | 0) < 0) : 0)) {
+     i11 = i10;
+     i9 = HEAP32[i10 >> 2] | 0;
+    }
+    HEAP32[i11 >> 2] = ((i9 & 16320 | 0) == 0) << 6 | i9 & -16321;
+    break;
+   }
+  case 6:
+   {
+    i8 = 25;
+    break;
+   }
+  case 3:
+  case 1:
+   {
+    HEAP32[i7 >> 2] = 2;
+    break;
+   }
+  case 11:
+   {
+    i12 = i4 + 48 | 0;
+    i8 = HEAP8[i12] | 0;
+    i11 = (i8 & 255) + 1 | 0;
+    i9 = (HEAP32[i4 >> 2] | 0) + 78 | 0;
+    do {
+     if (i11 >>> 0 > (HEAPU8[i9] | 0) >>> 0) {
+      if (i11 >>> 0 > 249) {
+       _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10536);
+      } else {
+       HEAP8[i9] = i11;
+       i10 = HEAP8[i12] | 0;
+       break;
+      }
+     } else {
+      i10 = i8;
+     }
+    } while (0);
+    i14 = (i10 & 255) + 1 | 0;
+    HEAP8[i12] = i14;
+    _discharge2reg(i4, i7, (i14 & 255) + -1 | 0);
+    if ((HEAP32[i7 >> 2] | 0) == 6) {
+     i8 = 25;
+    } else {
+     i9 = i7 + 8 | 0;
+     i8 = 28;
+    }
+    break;
+   }
+  default:
+   {}
+  }
+  if ((i8 | 0) == 25) {
+   i8 = i7 + 8 | 0;
+   i9 = HEAP32[i8 >> 2] | 0;
+   if ((i9 & 256 | 0) == 0 ? (HEAPU8[i4 + 46 | 0] | 0) <= (i9 | 0) : 0) {
+    i9 = i4 + 48 | 0;
+    HEAP8[i9] = (HEAP8[i9] | 0) + -1 << 24 >> 24;
+    i9 = i8;
+    i8 = 28;
+   } else {
+    i9 = i8;
+    i8 = 28;
+   }
+  }
+  if ((i8 | 0) == 28) {
+   HEAP32[i9 >> 2] = _luaK_code(i4, HEAP32[i9 >> 2] << 23 | 20) | 0;
+   HEAP32[i7 >> 2] = 11;
+  }
+  i14 = i7 + 20 | 0;
+  i8 = HEAP32[i14 >> 2] | 0;
+  i7 = i7 + 16 | 0;
+  i9 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i14 >> 2] = i9;
+  HEAP32[i7 >> 2] = i8;
+  if (!((i9 | 0) == -1)) {
+   i8 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+   do {
+    i12 = i8 + (i9 << 2) | 0;
+    if ((i9 | 0) > 0 ? (i5 = i8 + (i9 + -1 << 2) | 0, i6 = HEAP32[i5 >> 2] | 0, (HEAP8[5584 + (i6 & 63) | 0] | 0) < 0) : 0) {
+     i10 = i5;
+     i11 = i6;
+    } else {
+     i10 = i12;
+     i11 = HEAP32[i12 >> 2] | 0;
+    }
+    if ((i11 & 63 | 0) == 28) {
+     HEAP32[i10 >> 2] = i11 & 8372224 | i11 >>> 23 << 6 | 27;
+    }
+    i10 = ((HEAP32[i12 >> 2] | 0) >>> 14) + -131071 | 0;
+    if ((i10 | 0) == -1) {
+     break;
+    }
+    i9 = i9 + 1 + i10 | 0;
+   } while (!((i9 | 0) == -1));
+   i8 = HEAP32[i7 >> 2] | 0;
+  }
+  if ((i8 | 0) == -1) {
+   STACKTOP = i1;
+   return;
+  }
+  i4 = HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0;
+  while (1) {
+   i6 = i4 + (i8 << 2) | 0;
+   if ((i8 | 0) > 0 ? (i2 = i4 + (i8 + -1 << 2) | 0, i3 = HEAP32[i2 >> 2] | 0, (HEAP8[5584 + (i3 & 63) | 0] | 0) < 0) : 0) {
+    i7 = i2;
+    i5 = i3;
+   } else {
+    i7 = i6;
+    i5 = HEAP32[i6 >> 2] | 0;
+   }
+   if ((i5 & 63 | 0) == 28) {
+    HEAP32[i7 >> 2] = i5 & 8372224 | i5 >>> 23 << 6 | 27;
+   }
+   i5 = ((HEAP32[i6 >> 2] | 0) >>> 14) + -131071 | 0;
+   if ((i5 | 0) == -1) {
+    i8 = 54;
+    break;
+   }
+   i8 = i8 + 1 + i5 | 0;
+   if ((i8 | 0) == -1) {
+    i8 = 54;
+    break;
+   }
+  }
+  if ((i8 | 0) == 54) {
+   STACKTOP = i1;
+   return;
+  }
+ } else if ((i14 | 0) == 0) {
+  if (((HEAP32[i7 >> 2] | 0) == 5 ? (HEAP32[i7 + 16 >> 2] | 0) == -1 : 0) ? (HEAP32[i7 + 20 >> 2] | 0) == -1 : 0) {
+   i14 = i7 + 8 | 0;
+   HEAPF64[i14 >> 3] = -+HEAPF64[i14 >> 3];
+   STACKTOP = i1;
+   return;
+  }
+  _luaK_dischargevars(i4, i7);
+  if ((HEAP32[i7 >> 2] | 0) == 6) {
+   i2 = HEAP32[i7 + 8 >> 2] | 0;
+   if ((HEAP32[i7 + 16 >> 2] | 0) != (HEAP32[i7 + 20 >> 2] | 0)) {
+    if ((i2 | 0) < (HEAPU8[i4 + 46 | 0] | 0)) {
+     i8 = 10;
+    } else {
+     _exp2reg(i4, i7, i2);
+    }
+   }
+  } else {
+   i8 = 10;
+  }
+  if ((i8 | 0) == 10) {
+   _luaK_exp2nextreg(i4, i7);
+  }
+  _codearith(i4, 19, i7, i12, i13);
+  STACKTOP = i1;
+  return;
+ } else if ((i14 | 0) == 2) {
+  _luaK_dischargevars(i4, i7);
+  if ((HEAP32[i7 >> 2] | 0) == 6) {
+   i2 = HEAP32[i7 + 8 >> 2] | 0;
+   if ((HEAP32[i7 + 16 >> 2] | 0) != (HEAP32[i7 + 20 >> 2] | 0)) {
+    if ((i2 | 0) < (HEAPU8[i4 + 46 | 0] | 0)) {
+     i8 = 52;
+    } else {
+     _exp2reg(i4, i7, i2);
+    }
+   }
+  } else {
+   i8 = 52;
+  }
+  if ((i8 | 0) == 52) {
+   _luaK_exp2nextreg(i4, i7);
+  }
+  _codearith(i4, 21, i7, i12, i13);
+  STACKTOP = i1;
+  return;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _subexpr(i6, i3, i7) {
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i11 = i2 + 24 | 0;
+ i5 = i2;
+ i4 = i6 + 48 | 0;
+ i9 = HEAP32[i4 >> 2] | 0;
+ i1 = i6 + 52 | 0;
+ i12 = (HEAP32[i1 >> 2] | 0) + 38 | 0;
+ i13 = (HEAP16[i12 >> 1] | 0) + 1 << 16 >> 16;
+ HEAP16[i12 >> 1] = i13;
+ if ((i13 & 65535) > 200) {
+  i10 = i9 + 12 | 0;
+  i12 = HEAP32[(HEAP32[i10 >> 2] | 0) + 52 >> 2] | 0;
+  i13 = HEAP32[(HEAP32[i9 >> 2] | 0) + 64 >> 2] | 0;
+  if ((i13 | 0) == 0) {
+   i15 = 6552;
+   HEAP32[i11 >> 2] = 6360;
+   i14 = i11 + 4 | 0;
+   HEAP32[i14 >> 2] = 200;
+   i14 = i11 + 8 | 0;
+   HEAP32[i14 >> 2] = i15;
+   i14 = _luaO_pushfstring(i12, 6592, i11) | 0;
+   i15 = HEAP32[i10 >> 2] | 0;
+   _luaX_syntaxerror(i15, i14);
+  }
+  HEAP32[i11 >> 2] = i13;
+  i14 = _luaO_pushfstring(i12, 6568, i11) | 0;
+  HEAP32[i11 >> 2] = 6360;
+  i15 = i11 + 4 | 0;
+  HEAP32[i15 >> 2] = 200;
+  i15 = i11 + 8 | 0;
+  HEAP32[i15 >> 2] = i14;
+  i15 = _luaO_pushfstring(i12, 6592, i11) | 0;
+  i14 = HEAP32[i10 >> 2] | 0;
+  _luaX_syntaxerror(i14, i15);
+ }
+ i10 = i6 + 16 | 0;
+ L8 : do {
+  switch (HEAP32[i10 >> 2] | 0) {
+  case 287:
+   {
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 5;
+    HEAP32[i3 + 8 >> 2] = 0;
+    HEAPF64[i3 + 8 >> 3] = +HEAPF64[i6 + 24 >> 3];
+    i8 = 20;
+    break;
+   }
+  case 271:
+   {
+    i9 = 1;
+    i8 = 8;
+    break;
+   }
+  case 289:
+   {
+    i8 = _luaK_stringK(i9, HEAP32[i6 + 24 >> 2] | 0) | 0;
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 4;
+    HEAP32[i3 + 8 >> 2] = i8;
+    i8 = 20;
+    break;
+   }
+  case 265:
+   {
+    _luaX_next(i6);
+    _body(i6, i3, 0, HEAP32[i6 + 4 >> 2] | 0);
+    break;
+   }
+  case 276:
+   {
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 2;
+    HEAP32[i3 + 8 >> 2] = 0;
+    i8 = 20;
+    break;
+   }
+  case 45:
+   {
+    i9 = 0;
+    i8 = 8;
+    break;
+   }
+  case 35:
+   {
+    i9 = 2;
+    i8 = 8;
+    break;
+   }
+  case 123:
+   {
+    _constructor(i6, i3);
+    break;
+   }
+  case 263:
+   {
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 3;
+    HEAP32[i3 + 8 >> 2] = 0;
+    i8 = 20;
+    break;
+   }
+  case 280:
+   {
+    if ((HEAP8[(HEAP32[i9 >> 2] | 0) + 77 | 0] | 0) == 0) {
+     _luaX_syntaxerror(i6, 6408);
+    } else {
+     i8 = _luaK_codeABC(i9, 38, 0, 1, 0) | 0;
+     HEAP32[i3 + 16 >> 2] = -1;
+     HEAP32[i3 + 20 >> 2] = -1;
+     HEAP32[i3 >> 2] = 13;
+     HEAP32[i3 + 8 >> 2] = i8;
+     i8 = 20;
+     break L8;
+    }
+    break;
+   }
+  case 270:
+   {
+    HEAP32[i3 + 16 >> 2] = -1;
+    HEAP32[i3 + 20 >> 2] = -1;
+    HEAP32[i3 >> 2] = 1;
+    HEAP32[i3 + 8 >> 2] = 0;
+    i8 = 20;
+    break;
+   }
+  default:
+   {
+    _suffixedexp(i6, i3);
+   }
+  }
+ } while (0);
+ if ((i8 | 0) == 8) {
+  i15 = HEAP32[i6 + 4 >> 2] | 0;
+  _luaX_next(i6);
+  _subexpr(i6, i3, 8) | 0;
+  _luaK_prefix(HEAP32[i4 >> 2] | 0, i9, i3, i15);
+ } else if ((i8 | 0) == 20) {
+  _luaX_next(i6);
+ }
+ switch (HEAP32[i10 >> 2] | 0) {
+ case 257:
+  {
+   i9 = 13;
+   break;
+  }
+ case 272:
+  {
+   i9 = 14;
+   break;
+  }
+ case 47:
+  {
+   i9 = 3;
+   break;
+  }
+ case 37:
+  {
+   i9 = 4;
+   break;
+  }
+ case 43:
+  {
+   i9 = 0;
+   break;
+  }
+ case 284:
+  {
+   i9 = 10;
+   break;
+  }
+ case 281:
+  {
+   i9 = 7;
+   break;
+  }
+ case 62:
+  {
+   i9 = 11;
+   break;
+  }
+ case 282:
+  {
+   i9 = 12;
+   break;
+  }
+ case 45:
+  {
+   i9 = 1;
+   break;
+  }
+ case 42:
+  {
+   i9 = 2;
+   break;
+  }
+ case 60:
+  {
+   i9 = 8;
+   break;
+  }
+ case 283:
+  {
+   i9 = 9;
+   break;
+  }
+ case 94:
+  {
+   i9 = 5;
+   break;
+  }
+ case 279:
+  {
+   i9 = 6;
+   break;
+  }
+ default:
+  {
+   i15 = 15;
+   i14 = HEAP32[i1 >> 2] | 0;
+   i14 = i14 + 38 | 0;
+   i13 = HEAP16[i14 >> 1] | 0;
+   i13 = i13 + -1 << 16 >> 16;
+   HEAP16[i14 >> 1] = i13;
+   STACKTOP = i2;
+   return i15 | 0;
+  }
+ }
+ i8 = i6 + 4 | 0;
+ while (1) {
+  if ((HEAPU8[6376 + (i9 << 1) | 0] | 0) <= (i7 | 0)) {
+   i8 = 39;
+   break;
+  }
+  i15 = HEAP32[i8 >> 2] | 0;
+  _luaX_next(i6);
+  _luaK_infix(HEAP32[i4 >> 2] | 0, i9, i3);
+  i10 = _subexpr(i6, i5, HEAPU8[6377 + (i9 << 1) | 0] | 0) | 0;
+  _luaK_posfix(HEAP32[i4 >> 2] | 0, i9, i3, i5, i15);
+  if ((i10 | 0) == 15) {
+   i9 = 15;
+   i8 = 39;
+   break;
+  } else {
+   i9 = i10;
+  }
+ }
+ if ((i8 | 0) == 39) {
+  i15 = HEAP32[i1 >> 2] | 0;
+  i15 = i15 + 38 | 0;
+  i14 = HEAP16[i15 >> 1] | 0;
+  i14 = i14 + -1 << 16 >> 16;
+  HEAP16[i15 >> 1] = i14;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ return 0;
+}
+function _luaV_lessequal(i5, i3, i2) {
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i4 = i3 + 8 | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ if ((i7 | 0) == 3) {
+  if ((HEAP32[i2 + 8 >> 2] | 0) == 3) {
+   i9 = +HEAPF64[i3 >> 3] <= +HEAPF64[i2 >> 3] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ } else {
+  if ((i7 & 15 | 0) == 4 ? (HEAP32[i2 + 8 >> 2] & 15 | 0) == 4 : 0) {
+   i3 = HEAP32[i3 >> 2] | 0;
+   i6 = HEAP32[i2 >> 2] | 0;
+   i4 = i3 + 16 | 0;
+   i5 = i6 + 16 | 0;
+   i7 = _strcmp(i4, i5) | 0;
+   L8 : do {
+    if ((i7 | 0) == 0) {
+     i2 = HEAP32[i3 + 12 >> 2] | 0;
+     i3 = HEAP32[i6 + 12 >> 2] | 0;
+     i6 = i5;
+     while (1) {
+      i5 = _strlen(i4 | 0) | 0;
+      i7 = (i5 | 0) == (i2 | 0);
+      if ((i5 | 0) == (i3 | 0)) {
+       break;
+      }
+      if (i7) {
+       i7 = -1;
+       break L8;
+      }
+      i5 = i5 + 1 | 0;
+      i4 = i4 + i5 | 0;
+      i6 = i6 + i5 | 0;
+      i7 = _strcmp(i4, i6) | 0;
+      if ((i7 | 0) == 0) {
+       i2 = i2 - i5 | 0;
+       i3 = i3 - i5 | 0;
+      } else {
+       break L8;
+      }
+     }
+     i7 = i7 & 1 ^ 1;
+    }
+   } while (0);
+   i9 = (i7 | 0) < 1 | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ }
+ i7 = i5 + 8 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ i9 = _luaT_gettmbyobj(i5, i3, 14) | 0;
+ if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+  i9 = _luaT_gettmbyobj(i5, i2, 14) | 0;
+  if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+   i8 = HEAP32[i7 >> 2] | 0;
+   i9 = _luaT_gettmbyobj(i5, i2, 13) | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+    i9 = _luaT_gettmbyobj(i5, i3, 13) | 0;
+    if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+     _luaG_ordererror(i5, i3, i2);
+    } else {
+     i6 = i9;
+    }
+   } else {
+    i6 = i9;
+   }
+   i10 = i5 + 28 | 0;
+   i9 = i8 - (HEAP32[i10 >> 2] | 0) | 0;
+   i8 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i8 + 16;
+   i13 = i6;
+   i11 = HEAP32[i13 + 4 >> 2] | 0;
+   i12 = i8;
+   HEAP32[i12 >> 2] = HEAP32[i13 >> 2];
+   HEAP32[i12 + 4 >> 2] = i11;
+   HEAP32[i8 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+   i8 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i8 + 16;
+   i12 = i2;
+   i11 = HEAP32[i12 + 4 >> 2] | 0;
+   i6 = i8;
+   HEAP32[i6 >> 2] = HEAP32[i12 >> 2];
+   HEAP32[i6 + 4 >> 2] = i11;
+   HEAP32[i8 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+   i2 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i2 + 16;
+   i8 = i3;
+   i6 = HEAP32[i8 + 4 >> 2] | 0;
+   i3 = i2;
+   HEAP32[i3 >> 2] = HEAP32[i8 >> 2];
+   HEAP32[i3 + 4 >> 2] = i6;
+   HEAP32[i2 + 8 >> 2] = HEAP32[i4 >> 2];
+   _luaD_call(i5, (HEAP32[i7 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i5 + 16 >> 2] | 0) + 18 | 0] & 1);
+   i3 = HEAP32[i10 >> 2] | 0;
+   i2 = HEAP32[i7 >> 2] | 0;
+   i5 = i2 + -16 | 0;
+   HEAP32[i7 >> 2] = i5;
+   i6 = HEAP32[i5 + 4 >> 2] | 0;
+   i8 = i3 + i9 | 0;
+   HEAP32[i8 >> 2] = HEAP32[i5 >> 2];
+   HEAP32[i8 + 4 >> 2] = i6;
+   HEAP32[i3 + (i9 + 8) >> 2] = HEAP32[i2 + -8 >> 2];
+   i3 = HEAP32[i7 >> 2] | 0;
+   i2 = HEAP32[i3 + 8 >> 2] | 0;
+   if ((i2 | 0) != 0) {
+    if ((i2 | 0) == 1) {
+     i2 = (HEAP32[i3 >> 2] | 0) != 0;
+    } else {
+     i2 = 1;
+    }
+   } else {
+    i2 = 0;
+   }
+   i13 = i2 & 1 ^ 1;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+ }
+ i10 = i5 + 28 | 0;
+ i13 = i8 - (HEAP32[i10 >> 2] | 0) | 0;
+ i11 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i11 + 16;
+ i6 = i9;
+ i8 = HEAP32[i6 + 4 >> 2] | 0;
+ i12 = i11;
+ HEAP32[i12 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i12 + 4 >> 2] = i8;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+ i9 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i9 + 16;
+ i11 = i3;
+ i12 = HEAP32[i11 + 4 >> 2] | 0;
+ i3 = i9;
+ HEAP32[i3 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i3 + 4 >> 2] = i12;
+ HEAP32[i9 + 8 >> 2] = HEAP32[i4 >> 2];
+ i3 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i3 + 16;
+ i9 = i2;
+ i12 = HEAP32[i9 + 4 >> 2] | 0;
+ i11 = i3;
+ HEAP32[i11 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i11 + 4 >> 2] = i12;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+ _luaD_call(i5, (HEAP32[i7 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i5 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i2 = HEAP32[i10 >> 2] | 0;
+ i3 = HEAP32[i7 >> 2] | 0;
+ i10 = i3 + -16 | 0;
+ HEAP32[i7 >> 2] = i10;
+ i11 = HEAP32[i10 + 4 >> 2] | 0;
+ i12 = i2 + i13 | 0;
+ HEAP32[i12 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i12 + 4 >> 2] = i11;
+ HEAP32[i2 + (i13 + 8) >> 2] = HEAP32[i3 + -8 >> 2];
+ i2 = HEAP32[i7 >> 2] | 0;
+ i3 = HEAP32[i2 + 8 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  if ((i3 | 0) == 1) {
+   i2 = (HEAP32[i2 >> 2] | 0) != 0;
+  } else {
+   i2 = 1;
+  }
+ } else {
+  i2 = 0;
+ }
+ i13 = i2 & 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function ___udivmoddi4(i6, i8, i2, i4, i1) {
+ i6 = i6 | 0;
+ i8 = i8 | 0;
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i5 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i5 = i6;
+ i9 = i8;
+ i7 = i9;
+ i10 = i2;
+ i3 = i4;
+ i11 = i3;
+ if ((i7 | 0) == 0) {
+  i2 = (i1 | 0) != 0;
+  if ((i11 | 0) == 0) {
+   if (i2) {
+    HEAP32[i1 >> 2] = (i5 >>> 0) % (i10 >>> 0);
+    HEAP32[i1 + 4 >> 2] = 0;
+   }
+   i11 = 0;
+   i12 = (i5 >>> 0) / (i10 >>> 0) >>> 0;
+   return (tempRet0 = i11, i12) | 0;
+  } else {
+   if (!i2) {
+    i11 = 0;
+    i12 = 0;
+    return (tempRet0 = i11, i12) | 0;
+   }
+   HEAP32[i1 >> 2] = i6 | 0;
+   HEAP32[i1 + 4 >> 2] = i8 & 0;
+   i11 = 0;
+   i12 = 0;
+   return (tempRet0 = i11, i12) | 0;
+  }
+ }
+ i12 = (i11 | 0) == 0;
+ do {
+  if ((i10 | 0) != 0) {
+   if (!i12) {
+    i10 = (_llvm_ctlz_i32(i11 | 0) | 0) - (_llvm_ctlz_i32(i7 | 0) | 0) | 0;
+    if (i10 >>> 0 <= 31) {
+     i11 = i10 + 1 | 0;
+     i12 = 31 - i10 | 0;
+     i8 = i10 - 31 >> 31;
+     i9 = i11;
+     i6 = i5 >>> (i11 >>> 0) & i8 | i7 << i12;
+     i8 = i7 >>> (i11 >>> 0) & i8;
+     i11 = 0;
+     i7 = i5 << i12;
+     break;
+    }
+    if ((i1 | 0) == 0) {
+     i11 = 0;
+     i12 = 0;
+     return (tempRet0 = i11, i12) | 0;
+    }
+    HEAP32[i1 >> 2] = i6 | 0;
+    HEAP32[i1 + 4 >> 2] = i9 | i8 & 0;
+    i11 = 0;
+    i12 = 0;
+    return (tempRet0 = i11, i12) | 0;
+   }
+   i11 = i10 - 1 | 0;
+   if ((i11 & i10 | 0) != 0) {
+    i12 = (_llvm_ctlz_i32(i10 | 0) | 0) + 33 - (_llvm_ctlz_i32(i7 | 0) | 0) | 0;
+    i15 = 64 - i12 | 0;
+    i10 = 32 - i12 | 0;
+    i13 = i10 >> 31;
+    i14 = i12 - 32 | 0;
+    i8 = i14 >> 31;
+    i9 = i12;
+    i6 = i10 - 1 >> 31 & i7 >>> (i14 >>> 0) | (i7 << i10 | i5 >>> (i12 >>> 0)) & i8;
+    i8 = i8 & i7 >>> (i12 >>> 0);
+    i11 = i5 << i15 & i13;
+    i7 = (i7 << i15 | i5 >>> (i14 >>> 0)) & i13 | i5 << i10 & i12 - 33 >> 31;
+    break;
+   }
+   if ((i1 | 0) != 0) {
+    HEAP32[i1 >> 2] = i11 & i5;
+    HEAP32[i1 + 4 >> 2] = 0;
+   }
+   if ((i10 | 0) == 1) {
+    i14 = i9 | i8 & 0;
+    i15 = i6 | 0 | 0;
+    return (tempRet0 = i14, i15) | 0;
+   } else {
+    i15 = _llvm_cttz_i32(i10 | 0) | 0;
+    i14 = i7 >>> (i15 >>> 0) | 0;
+    i15 = i7 << 32 - i15 | i5 >>> (i15 >>> 0) | 0;
+    return (tempRet0 = i14, i15) | 0;
+   }
+  } else {
+   if (i12) {
+    if ((i1 | 0) != 0) {
+     HEAP32[i1 >> 2] = (i7 >>> 0) % (i10 >>> 0);
+     HEAP32[i1 + 4 >> 2] = 0;
+    }
+    i14 = 0;
+    i15 = (i7 >>> 0) / (i10 >>> 0) >>> 0;
+    return (tempRet0 = i14, i15) | 0;
+   }
+   if ((i5 | 0) == 0) {
+    if ((i1 | 0) != 0) {
+     HEAP32[i1 >> 2] = 0;
+     HEAP32[i1 + 4 >> 2] = (i7 >>> 0) % (i11 >>> 0);
+    }
+    i14 = 0;
+    i15 = (i7 >>> 0) / (i11 >>> 0) >>> 0;
+    return (tempRet0 = i14, i15) | 0;
+   }
+   i10 = i11 - 1 | 0;
+   if ((i10 & i11 | 0) == 0) {
+    if ((i1 | 0) != 0) {
+     HEAP32[i1 >> 2] = i6 | 0;
+     HEAP32[i1 + 4 >> 2] = i10 & i7 | i8 & 0;
+    }
+    i14 = 0;
+    i15 = i7 >>> ((_llvm_cttz_i32(i11 | 0) | 0) >>> 0);
+    return (tempRet0 = i14, i15) | 0;
+   }
+   i10 = (_llvm_ctlz_i32(i11 | 0) | 0) - (_llvm_ctlz_i32(i7 | 0) | 0) | 0;
+   if (i10 >>> 0 <= 30) {
+    i8 = i10 + 1 | 0;
+    i15 = 31 - i10 | 0;
+    i9 = i8;
+    i6 = i7 << i15 | i5 >>> (i8 >>> 0);
+    i8 = i7 >>> (i8 >>> 0);
+    i11 = 0;
+    i7 = i5 << i15;
+    break;
+   }
+   if ((i1 | 0) == 0) {
+    i14 = 0;
+    i15 = 0;
+    return (tempRet0 = i14, i15) | 0;
+   }
+   HEAP32[i1 >> 2] = i6 | 0;
+   HEAP32[i1 + 4 >> 2] = i9 | i8 & 0;
+   i14 = 0;
+   i15 = 0;
+   return (tempRet0 = i14, i15) | 0;
+  }
+ } while (0);
+ if ((i9 | 0) == 0) {
+  i12 = i6;
+  i2 = 0;
+  i6 = 0;
+ } else {
+  i2 = i2 | 0 | 0;
+  i3 = i3 | i4 & 0;
+  i4 = _i64Add(i2, i3, -1, -1) | 0;
+  i5 = tempRet0;
+  i10 = i8;
+  i12 = i6;
+  i6 = 0;
+  while (1) {
+   i8 = i11 >>> 31 | i7 << 1;
+   i11 = i6 | i11 << 1;
+   i7 = i12 << 1 | i7 >>> 31 | 0;
+   i10 = i12 >>> 31 | i10 << 1 | 0;
+   _i64Subtract(i4, i5, i7, i10) | 0;
+   i12 = tempRet0;
+   i15 = i12 >> 31 | ((i12 | 0) < 0 ? -1 : 0) << 1;
+   i6 = i15 & 1;
+   i12 = _i64Subtract(i7, i10, i15 & i2, (((i12 | 0) < 0 ? -1 : 0) >> 31 | ((i12 | 0) < 0 ? -1 : 0) << 1) & i3) | 0;
+   i10 = tempRet0;
+   i9 = i9 - 1 | 0;
+   if ((i9 | 0) == 0) {
+    break;
+   } else {
+    i7 = i8;
+   }
+  }
+  i7 = i8;
+  i8 = i10;
+  i2 = 0;
+ }
+ i3 = 0;
+ if ((i1 | 0) != 0) {
+  HEAP32[i1 >> 2] = i12;
+  HEAP32[i1 + 4 >> 2] = i8;
+ }
+ i14 = (i11 | 0) >>> 31 | (i7 | i3) << 1 | (i3 << 1 | i11 >>> 31) & 0 | i2;
+ i15 = (i11 << 1 | 0 >>> 31) & -2 | i6;
+ return (tempRet0 = i14, i15) | 0;
+}
+function _leaveblock(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i3;
+ i7 = i1 + 16 | 0;
+ i4 = HEAP32[i7 >> 2] | 0;
+ i2 = i1 + 12 | 0;
+ i6 = HEAP32[i2 >> 2] | 0;
+ if ((HEAP32[i4 >> 2] | 0) != 0 ? (HEAP8[i4 + 9 | 0] | 0) != 0 : 0) {
+  i16 = _luaK_jump(i1) | 0;
+  _luaK_patchclose(i1, i16, HEAPU8[i4 + 8 | 0] | 0);
+  _luaK_patchtohere(i1, i16);
+ }
+ L5 : do {
+  if ((HEAP8[i4 + 10 | 0] | 0) != 0) {
+   i15 = i6 + 52 | 0;
+   i14 = _luaS_new(HEAP32[i15 >> 2] | 0, 6304) | 0;
+   i13 = i6 + 64 | 0;
+   i16 = HEAP32[i13 >> 2] | 0;
+   i10 = i16 + 24 | 0;
+   i8 = i6 + 48 | 0;
+   i11 = HEAP32[(HEAP32[i8 >> 2] | 0) + 20 >> 2] | 0;
+   i12 = i16 + 28 | 0;
+   i9 = HEAP32[i12 >> 2] | 0;
+   i16 = i16 + 32 | 0;
+   if ((i9 | 0) < (HEAP32[i16 >> 2] | 0)) {
+    i15 = HEAP32[i10 >> 2] | 0;
+   } else {
+    i15 = _luaM_growaux_(HEAP32[i15 >> 2] | 0, HEAP32[i10 >> 2] | 0, i16, 16, 32767, 6312) | 0;
+    HEAP32[i10 >> 2] = i15;
+   }
+   HEAP32[i15 + (i9 << 4) >> 2] = i14;
+   i16 = HEAP32[i10 >> 2] | 0;
+   HEAP32[i16 + (i9 << 4) + 8 >> 2] = 0;
+   HEAP8[i16 + (i9 << 4) + 12 | 0] = HEAP8[(HEAP32[i8 >> 2] | 0) + 46 | 0] | 0;
+   HEAP32[(HEAP32[i10 >> 2] | 0) + (i9 << 4) + 4 >> 2] = i11;
+   HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + 1;
+   i10 = HEAP32[i13 >> 2] | 0;
+   i9 = (HEAP32[i10 + 24 >> 2] | 0) + (i9 << 4) | 0;
+   i11 = HEAP16[(HEAP32[(HEAP32[i8 >> 2] | 0) + 16 >> 2] | 0) + 6 >> 1] | 0;
+   i8 = i10 + 16 | 0;
+   if ((i11 | 0) < (HEAP32[i8 >> 2] | 0)) {
+    i10 = i10 + 12 | 0;
+    do {
+     while (1) {
+      if ((_luaS_eqstr(HEAP32[(HEAP32[i10 >> 2] | 0) + (i11 << 4) >> 2] | 0, HEAP32[i9 >> 2] | 0) | 0) == 0) {
+       break;
+      }
+      _closegoto(i6, i11, i9);
+      if ((i11 | 0) >= (HEAP32[i8 >> 2] | 0)) {
+       break L5;
+      }
+     }
+     i11 = i11 + 1 | 0;
+    } while ((i11 | 0) < (HEAP32[i8 >> 2] | 0));
+   }
+  }
+ } while (0);
+ HEAP32[i7 >> 2] = HEAP32[i4 >> 2];
+ i7 = i4 + 8 | 0;
+ i9 = HEAP8[i7] | 0;
+ i10 = i1 + 46 | 0;
+ i8 = (HEAP32[i2 >> 2] | 0) + 64 | 0;
+ i14 = (HEAP32[i8 >> 2] | 0) + 4 | 0;
+ HEAP32[i14 >> 2] = (i9 & 255) - (HEAPU8[i10] | 0) + (HEAP32[i14 >> 2] | 0);
+ i14 = HEAP8[i10] | 0;
+ if ((i14 & 255) > (i9 & 255)) {
+  i13 = i1 + 20 | 0;
+  i11 = i1 + 40 | 0;
+  i12 = (HEAP32[i1 >> 2] | 0) + 24 | 0;
+  do {
+   i16 = HEAP32[i13 >> 2] | 0;
+   i14 = i14 + -1 << 24 >> 24;
+   HEAP8[i10] = i14;
+   HEAP32[(HEAP32[i12 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[i8 >> 2] >> 2] | 0) + ((HEAP32[i11 >> 2] | 0) + (i14 & 255) << 1) >> 1] | 0) * 12 | 0) + 8 >> 2] = i16;
+   i14 = HEAP8[i10] | 0;
+  } while ((i14 & 255) > (i9 & 255));
+ }
+ HEAP8[i1 + 48 | 0] = i14;
+ i10 = HEAP32[i6 + 64 >> 2] | 0;
+ HEAP32[i10 + 28 >> 2] = HEAP16[i4 + 4 >> 1] | 0;
+ i9 = HEAP16[i4 + 6 >> 1] | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  if ((i9 | 0) >= (HEAP32[i10 + 16 >> 2] | 0)) {
+   STACKTOP = i3;
+   return;
+  }
+  i10 = HEAP32[i10 + 12 >> 2] | 0;
+  i11 = HEAP32[i10 + (i9 << 4) >> 2] | 0;
+  if ((HEAP8[i11 + 4 | 0] | 0) != 4) {
+   i16 = 6200;
+   i15 = i6 + 52 | 0;
+   i15 = HEAP32[i15 >> 2] | 0;
+   i14 = i11 + 16 | 0;
+   i13 = i10 + (i9 << 4) + 8 | 0;
+   i13 = HEAP32[i13 >> 2] | 0;
+   HEAP32[i5 >> 2] = i14;
+   i14 = i5 + 4 | 0;
+   HEAP32[i14 >> 2] = i13;
+   i16 = _luaO_pushfstring(i15, i16, i5) | 0;
+   _semerror(i6, i16);
+  }
+  i16 = (HEAP8[i11 + 6 | 0] | 0) != 0 ? 6160 : 6200;
+  i15 = i6 + 52 | 0;
+  i15 = HEAP32[i15 >> 2] | 0;
+  i14 = i11 + 16 | 0;
+  i13 = i10 + (i9 << 4) + 8 | 0;
+  i13 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i5 >> 2] = i14;
+  i14 = i5 + 4 | 0;
+  HEAP32[i14 >> 2] = i13;
+  i16 = _luaO_pushfstring(i15, i16, i5) | 0;
+  _semerror(i6, i16);
+ }
+ i6 = HEAP32[i8 >> 2] | 0;
+ i5 = i6 + 16 | 0;
+ if ((i9 | 0) >= (HEAP32[i5 >> 2] | 0)) {
+  STACKTOP = i3;
+  return;
+ }
+ i6 = i6 + 12 | 0;
+ i4 = i4 + 9 | 0;
+ do {
+  i10 = HEAP32[i6 >> 2] | 0;
+  i8 = i10 + (i9 << 4) + 12 | 0;
+  i11 = HEAP8[i7] | 0;
+  i12 = i11 & 255;
+  if ((HEAPU8[i8] | 0) > (i11 & 255)) {
+   if ((HEAP8[i4] | 0) != 0) {
+    _luaK_patchclose(i1, HEAP32[i10 + (i9 << 4) + 4 >> 2] | 0, i12);
+    i11 = HEAP8[i7] | 0;
+   }
+   HEAP8[i8] = i11;
+  }
+  i9 = ((_findlabel(HEAP32[i2 >> 2] | 0, i9) | 0) == 0) + i9 | 0;
+ } while ((i9 | 0) < (HEAP32[i5 >> 2] | 0));
+ STACKTOP = i3;
+ return;
+}
+function _getobjname(i3, i7, i9, i2) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i9 = i9 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i4 = i3 + 12 | 0;
+ L1 : while (1) {
+  i13 = _luaF_getlocalname(i3, i9 + 1 | 0, i7) | 0;
+  HEAP32[i2 >> 2] = i13;
+  if ((i13 | 0) != 0) {
+   i2 = 2040;
+   i4 = 42;
+   break;
+  }
+  if ((i7 | 0) <= 0) {
+   i2 = 0;
+   i4 = 42;
+   break;
+  }
+  i6 = HEAP32[i4 >> 2] | 0;
+  i8 = 0;
+  i5 = -1;
+  do {
+   i12 = HEAP32[i6 + (i8 << 2) >> 2] | 0;
+   i13 = i12 & 63;
+   i11 = i12 >>> 6 & 255;
+   switch (i13 | 0) {
+   case 27:
+    {
+     i10 = i8;
+     i5 = (i11 | 0) == (i9 | 0) ? i8 : i5;
+     break;
+    }
+   case 30:
+   case 29:
+    {
+     i10 = i8;
+     i5 = (i11 | 0) > (i9 | 0) ? i5 : i8;
+     break;
+    }
+   case 23:
+    {
+     i10 = (i12 >>> 14) + -131071 | 0;
+     i13 = i8 + 1 + i10 | 0;
+     i10 = ((i8 | 0) >= (i13 | 0) | (i13 | 0) > (i7 | 0) ? 0 : i10) + i8 | 0;
+     break;
+    }
+   case 4:
+    {
+     if ((i11 | 0) > (i9 | 0)) {
+      i10 = i8;
+     } else {
+      i10 = i8;
+      i5 = (i11 + (i12 >>> 23) | 0) < (i9 | 0) ? i5 : i8;
+     }
+     break;
+    }
+   case 34:
+    {
+     i10 = i8;
+     i5 = (i11 + 2 | 0) > (i9 | 0) ? i5 : i8;
+     break;
+    }
+   default:
+    {
+     i10 = i8;
+     i5 = (HEAP8[5584 + i13 | 0] & 64) != 0 & (i11 | 0) == (i9 | 0) ? i8 : i5;
+    }
+   }
+   i8 = i10 + 1 | 0;
+  } while ((i8 | 0) < (i7 | 0));
+  if ((i5 | 0) == -1) {
+   i2 = 0;
+   i4 = 42;
+   break;
+  }
+  i7 = HEAP32[i6 + (i5 << 2) >> 2] | 0;
+  i9 = i7 & 63;
+  switch (i9 | 0) {
+  case 0:
+   {
+    break;
+   }
+  case 7:
+  case 6:
+   {
+    i4 = 17;
+    break L1;
+   }
+  case 5:
+   {
+    i4 = 29;
+    break L1;
+   }
+  case 1:
+   {
+    i4 = 32;
+    break L1;
+   }
+  case 2:
+   {
+    i4 = 33;
+    break L1;
+   }
+  case 12:
+   {
+    i4 = 36;
+    break L1;
+   }
+  default:
+   {
+    i2 = 0;
+    i4 = 42;
+    break L1;
+   }
+  }
+  i9 = i7 >>> 23;
+  if (i9 >>> 0 < (i7 >>> 6 & 255) >>> 0) {
+   i7 = i5;
+  } else {
+   i2 = 0;
+   i4 = 42;
+   break;
+  }
+ }
+ if ((i4 | 0) == 17) {
+  i6 = i7 >>> 14;
+  i8 = i6 & 511;
+  i7 = i7 >>> 23;
+  if ((i9 | 0) != 7) {
+   i7 = HEAP32[(HEAP32[i3 + 28 >> 2] | 0) + (i7 << 3) >> 2] | 0;
+   if ((i7 | 0) == 0) {
+    i7 = 2104;
+   } else {
+    i7 = i7 + 16 | 0;
+   }
+  } else {
+   i7 = _luaF_getlocalname(i3, i7 + 1 | 0, i5) | 0;
+  }
+  if ((i6 & 256 | 0) == 0) {
+   i3 = _getobjname(i3, i5, i8, i2) | 0;
+   if (!((i3 | 0) != 0 ? (HEAP8[i3] | 0) == 99 : 0)) {
+    i4 = 26;
+   }
+  } else {
+   i5 = i6 & 255;
+   i3 = HEAP32[i3 + 8 >> 2] | 0;
+   if ((HEAP32[i3 + (i5 << 4) + 8 >> 2] & 15 | 0) == 4) {
+    HEAP32[i2 >> 2] = (HEAP32[i3 + (i5 << 4) >> 2] | 0) + 16;
+   } else {
+    i4 = 26;
+   }
+  }
+  if ((i4 | 0) == 26) {
+   HEAP32[i2 >> 2] = 2104;
+  }
+  if ((i7 | 0) == 0) {
+   i13 = 2064;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+  i13 = (_strcmp(i7, 2048) | 0) == 0;
+  i13 = i13 ? 2056 : 2064;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else if ((i4 | 0) == 29) {
+  i3 = HEAP32[(HEAP32[i3 + 28 >> 2] | 0) + (i7 >>> 23 << 3) >> 2] | 0;
+  if ((i3 | 0) == 0) {
+   i3 = 2104;
+  } else {
+   i3 = i3 + 16 | 0;
+  }
+  HEAP32[i2 >> 2] = i3;
+  i13 = 2072;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else if ((i4 | 0) == 32) {
+  i5 = i7 >>> 14;
+ } else if ((i4 | 0) == 33) {
+  i5 = (HEAP32[i6 + (i5 + 1 << 2) >> 2] | 0) >>> 6;
+ } else if ((i4 | 0) == 36) {
+  i4 = i7 >>> 14;
+  if ((i4 & 256 | 0) == 0) {
+   i3 = _getobjname(i3, i5, i4 & 511, i2) | 0;
+   if ((i3 | 0) != 0 ? (HEAP8[i3] | 0) == 99 : 0) {
+    i13 = 2096;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  } else {
+   i4 = i4 & 255;
+   i3 = HEAP32[i3 + 8 >> 2] | 0;
+   if ((HEAP32[i3 + (i4 << 4) + 8 >> 2] & 15 | 0) == 4) {
+    HEAP32[i2 >> 2] = (HEAP32[i3 + (i4 << 4) >> 2] | 0) + 16;
+    i13 = 2096;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  }
+  HEAP32[i2 >> 2] = 2104;
+  i13 = 2096;
+  STACKTOP = i1;
+  return i13 | 0;
+ } else if ((i4 | 0) == 42) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ i3 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((HEAP32[i3 + (i5 << 4) + 8 >> 2] & 15 | 0) != 4) {
+  i13 = 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ HEAP32[i2 >> 2] = (HEAP32[i3 + (i5 << 4) >> 2] | 0) + 16;
+ i13 = 2080;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _assignment(i2, i16, i5) {
+ i2 = i2 | 0;
+ i16 = i16 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 80 | 0;
+ i6 = i3 + 56 | 0;
+ i1 = i3 + 32 | 0;
+ i8 = i3;
+ i4 = i16 + 8 | 0;
+ if (!(((HEAP32[i4 >> 2] | 0) + -7 | 0) >>> 0 < 3)) {
+  _luaX_syntaxerror(i2, 6344);
+ }
+ i13 = i2 + 16 | 0;
+ i14 = HEAP32[i13 >> 2] | 0;
+ do {
+  if ((i14 | 0) == 44) {
+   _luaX_next(i2);
+   HEAP32[i8 >> 2] = i16;
+   i14 = i8 + 8 | 0;
+   _suffixedexp(i2, i14);
+   i15 = i2 + 48 | 0;
+   if ((HEAP32[i14 >> 2] | 0) != 9 ? (i10 = HEAP32[i15 >> 2] | 0, i11 = HEAP8[i10 + 48 | 0] | 0, i9 = i11 & 255, (i16 | 0) != 0) : 0) {
+    i13 = i8 + 16 | 0;
+    i12 = i11 & 255;
+    i18 = 0;
+    do {
+     if ((HEAP32[i16 + 8 >> 2] | 0) == 9) {
+      i17 = i16 + 16 | 0;
+      i19 = i17 + 3 | 0;
+      i20 = HEAPU8[i19] | 0;
+      i21 = HEAP32[i14 >> 2] | 0;
+      if ((i20 | 0) == (i21 | 0)) {
+       i21 = i17 + 2 | 0;
+       if ((HEAPU8[i21] | 0) == (HEAP32[i13 >> 2] | 0)) {
+        HEAP8[i19] = 7;
+        HEAP8[i21] = i11;
+        i20 = HEAP32[i14 >> 2] | 0;
+        i18 = 1;
+       }
+      } else {
+       i20 = i21;
+      }
+      if ((i20 | 0) == 7 ? (HEAP16[i17 >> 1] | 0) == (HEAP32[i13 >> 2] | 0) : 0) {
+       HEAP16[i17 >> 1] = i12;
+       i18 = 1;
+      }
+     }
+     i16 = HEAP32[i16 >> 2] | 0;
+    } while ((i16 | 0) != 0);
+    if ((i18 | 0) != 0) {
+     _luaK_codeABC(i10, (HEAP32[i14 >> 2] | 0) == 7 ? 0 : 5, i9, HEAP32[i13 >> 2] | 0, 0) | 0;
+     _luaK_reserveregs(i10, 1);
+    }
+   }
+   i9 = HEAP32[i15 >> 2] | 0;
+   if (((HEAPU16[(HEAP32[i2 + 52 >> 2] | 0) + 38 >> 1] | 0) + i5 | 0) <= 200) {
+    _assignment(i2, i8, i5 + 1 | 0);
+    i7 = i1;
+    break;
+   }
+   i8 = i9 + 12 | 0;
+   i5 = HEAP32[(HEAP32[i8 >> 2] | 0) + 52 >> 2] | 0;
+   i9 = HEAP32[(HEAP32[i9 >> 2] | 0) + 64 >> 2] | 0;
+   if ((i9 | 0) == 0) {
+    i20 = 6552;
+    HEAP32[i6 >> 2] = 6360;
+    i21 = i6 + 4 | 0;
+    HEAP32[i21 >> 2] = 200;
+    i21 = i6 + 8 | 0;
+    HEAP32[i21 >> 2] = i20;
+    i21 = _luaO_pushfstring(i5, 6592, i6) | 0;
+    i20 = HEAP32[i8 >> 2] | 0;
+    _luaX_syntaxerror(i20, i21);
+   }
+   HEAP32[i6 >> 2] = i9;
+   i20 = _luaO_pushfstring(i5, 6568, i6) | 0;
+   HEAP32[i6 >> 2] = 6360;
+   i21 = i6 + 4 | 0;
+   HEAP32[i21 >> 2] = 200;
+   i21 = i6 + 8 | 0;
+   HEAP32[i21 >> 2] = i20;
+   i21 = _luaO_pushfstring(i5, 6592, i6) | 0;
+   i20 = HEAP32[i8 >> 2] | 0;
+   _luaX_syntaxerror(i20, i21);
+  } else if ((i14 | 0) == 61) {
+   _luaX_next(i2);
+   _subexpr(i2, i1, 0) | 0;
+   i6 = i2 + 48 | 0;
+   if ((HEAP32[i13 >> 2] | 0) == 44) {
+    i9 = 1;
+    do {
+     _luaX_next(i2);
+     _luaK_exp2nextreg(HEAP32[i6 >> 2] | 0, i1);
+     _subexpr(i2, i1, 0) | 0;
+     i9 = i9 + 1 | 0;
+    } while ((HEAP32[i13 >> 2] | 0) == 44);
+   } else {
+    i9 = 1;
+   }
+   i8 = HEAP32[i6 >> 2] | 0;
+   if ((i9 | 0) == (i5 | 0)) {
+    _luaK_setoneret(i8, i1);
+    _luaK_storevar(HEAP32[i6 >> 2] | 0, i4, i1);
+    STACKTOP = i3;
+    return;
+   }
+   i7 = i5 - i9 | 0;
+   i10 = HEAP32[i1 >> 2] | 0;
+   if ((i10 | 0) == 13 | (i10 | 0) == 12) {
+    i10 = i7 + 1 | 0;
+    i10 = (i10 | 0) < 0 ? 0 : i10;
+    _luaK_setreturns(i8, i1, i10);
+    if ((i10 | 0) > 1) {
+     _luaK_reserveregs(i8, i10 + -1 | 0);
+    }
+   } else if ((i10 | 0) == 0) {
+    i12 = 30;
+   } else {
+    _luaK_exp2nextreg(i8, i1);
+    i12 = 30;
+   }
+   if ((i12 | 0) == 30 ? (i7 | 0) > 0 : 0) {
+    i21 = HEAPU8[i8 + 48 | 0] | 0;
+    _luaK_reserveregs(i8, i7);
+    _luaK_nil(i8, i21, i7);
+   }
+   if ((i9 | 0) > (i5 | 0)) {
+    i21 = (HEAP32[i6 >> 2] | 0) + 48 | 0;
+    HEAP8[i21] = i7 + (HEAPU8[i21] | 0);
+    i7 = i1;
+   } else {
+    i7 = i1;
+   }
+  } else {
+   _error_expected(i2, 61);
+  }
+ } while (0);
+ i21 = HEAP32[i2 + 48 >> 2] | 0;
+ i20 = (HEAPU8[i21 + 48 | 0] | 0) + -1 | 0;
+ HEAP32[i1 + 16 >> 2] = -1;
+ HEAP32[i1 + 20 >> 2] = -1;
+ HEAP32[i7 >> 2] = 6;
+ HEAP32[i1 + 8 >> 2] = i20;
+ _luaK_storevar(i21, i4, i1);
+ STACKTOP = i3;
+ return;
+}
+function _str_find_aux(i3, i7) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 288 | 0;
+ i9 = i1 + 284 | 0;
+ i5 = i1 + 280 | 0;
+ i4 = i1;
+ i2 = _luaL_checklstring(i3, 1, i9) | 0;
+ i8 = _luaL_checklstring(i3, 2, i5) | 0;
+ i12 = _luaL_optinteger(i3, 3, 1) | 0;
+ i10 = HEAP32[i9 >> 2] | 0;
+ if (!((i12 | 0) > -1)) {
+  if (i10 >>> 0 < (0 - i12 | 0) >>> 0) {
+   i12 = 1;
+  } else {
+   i12 = i12 + 1 + i10 | 0;
+   i6 = 4;
+  }
+ } else {
+  i6 = 4;
+ }
+ if ((i6 | 0) == 4) {
+  if ((i12 | 0) != 0) {
+   if (i12 >>> 0 > (i10 + 1 | 0) >>> 0) {
+    _lua_pushnil(i3);
+    i13 = 1;
+    STACKTOP = i1;
+    return i13 | 0;
+   }
+  } else {
+   i12 = 1;
+  }
+ }
+ i7 = (i7 | 0) != 0;
+ L10 : do {
+  if (i7) {
+   i13 = (_lua_toboolean(i3, 4) | 0) == 0;
+   i10 = HEAP32[i5 >> 2] | 0;
+   if (i13) {
+    i11 = 0;
+    do {
+     i13 = i8 + i11 | 0;
+     if ((_strpbrk(i13, 7512) | 0) != 0) {
+      i6 = 20;
+      break L10;
+     }
+     i11 = i11 + 1 + (_strlen(i13 | 0) | 0) | 0;
+    } while (!(i11 >>> 0 > i10 >>> 0));
+   }
+   i11 = i2 + (i12 + -1) | 0;
+   i9 = (HEAP32[i9 >> 2] | 0) - i12 + 1 | 0;
+   L17 : do {
+    if ((i10 | 0) == 0) {
+     if ((i11 | 0) == 0) {
+      break L10;
+     }
+    } else {
+     if (i10 >>> 0 > i9 >>> 0) {
+      break L10;
+     }
+     i4 = i10 + -1 | 0;
+     if ((i4 | 0) == (i9 | 0)) {
+      break L10;
+     }
+     i7 = HEAP8[i8] | 0;
+     i8 = i8 + 1 | 0;
+     i9 = i9 - i4 | 0;
+     i12 = i11;
+     while (1) {
+      i11 = _memchr(i12, i7, i9) | 0;
+      if ((i11 | 0) == 0) {
+       break L10;
+      }
+      i10 = i11 + 1 | 0;
+      if ((_memcmp(i10, i8, i4) | 0) == 0) {
+       break L17;
+      }
+      i11 = i10;
+      i9 = i12 + i9 | 0;
+      if ((i9 | 0) == (i11 | 0)) {
+       break L10;
+      } else {
+       i9 = i9 - i11 | 0;
+       i12 = i10;
+      }
+     }
+    }
+   } while (0);
+   i13 = i11 - i2 | 0;
+   _lua_pushinteger(i3, i13 + 1 | 0);
+   _lua_pushinteger(i3, i13 + (HEAP32[i5 >> 2] | 0) | 0);
+   i13 = 2;
+   STACKTOP = i1;
+   return i13 | 0;
+  } else {
+   i6 = 20;
+  }
+ } while (0);
+ L28 : do {
+  if ((i6 | 0) == 20) {
+   i6 = i2 + (i12 + -1) | 0;
+   i10 = (HEAP8[i8] | 0) == 94;
+   if (i10) {
+    i12 = (HEAP32[i5 >> 2] | 0) + -1 | 0;
+    HEAP32[i5 >> 2] = i12;
+    i8 = i8 + 1 | 0;
+   } else {
+    i12 = HEAP32[i5 >> 2] | 0;
+   }
+   i5 = i4 + 16 | 0;
+   HEAP32[i5 >> 2] = i3;
+   HEAP32[i4 >> 2] = 200;
+   HEAP32[i4 + 4 >> 2] = i2;
+   i11 = i4 + 8 | 0;
+   HEAP32[i11 >> 2] = i2 + (HEAP32[i9 >> 2] | 0);
+   HEAP32[i4 + 12 >> 2] = i8 + i12;
+   i9 = i4 + 20 | 0;
+   L34 : do {
+    if (i10) {
+     HEAP32[i9 >> 2] = 0;
+     i8 = _match(i4, i6, i8) | 0;
+     if ((i8 | 0) == 0) {
+      break L28;
+     }
+    } else {
+     while (1) {
+      HEAP32[i9 >> 2] = 0;
+      i10 = _match(i4, i6, i8) | 0;
+      if ((i10 | 0) != 0) {
+       i8 = i10;
+       break L34;
+      }
+      if (!(i6 >>> 0 < (HEAP32[i11 >> 2] | 0) >>> 0)) {
+       break L28;
+      }
+      i6 = i6 + 1 | 0;
+     }
+    }
+   } while (0);
+   if (i7) {
+    _lua_pushinteger(i3, 1 - i2 + i6 | 0);
+    _lua_pushinteger(i3, i8 - i2 | 0);
+    i2 = HEAP32[i9 >> 2] | 0;
+    _luaL_checkstack(HEAP32[i5 >> 2] | 0, i2, 7200);
+    if ((i2 | 0) > 0) {
+     i3 = 0;
+     do {
+      _push_onecapture(i4, i3, 0, 0);
+      i3 = i3 + 1 | 0;
+     } while ((i3 | 0) != (i2 | 0));
+    }
+    i13 = i2 + 2 | 0;
+    STACKTOP = i1;
+    return i13 | 0;
+   } else {
+    i3 = HEAP32[i9 >> 2] | 0;
+    i2 = (i3 | 0) != 0 | (i6 | 0) == 0 ? i3 : 1;
+    _luaL_checkstack(HEAP32[i5 >> 2] | 0, i2, 7200);
+    if ((i2 | 0) > 0) {
+     i3 = 0;
+    } else {
+     i13 = i3;
+     STACKTOP = i1;
+     return i13 | 0;
+    }
+    do {
+     _push_onecapture(i4, i3, i6, i8);
+     i3 = i3 + 1 | 0;
+    } while ((i3 | 0) != (i2 | 0));
+    STACKTOP = i1;
+    return i2 | 0;
+   }
+  }
+ } while (0);
+ _lua_pushnil(i3);
+ i13 = 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _luaO_pushvfstring(i2, i13, i10) {
+ i2 = i2 | 0;
+ i13 = i13 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, d18 = 0.0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i7 = i3;
+ i9 = i3 + 32 | 0;
+ i8 = i3 + 8 | 0;
+ i14 = _strchr(i13, 37) | 0;
+ i6 = i2 + 24 | 0;
+ i4 = i2 + 8 | 0;
+ i15 = HEAP32[i4 >> 2] | 0;
+ i17 = (HEAP32[i6 >> 2] | 0) - i15 | 0;
+ L1 : do {
+  if ((i14 | 0) == 0) {
+   i5 = i13;
+   i11 = i17;
+   i12 = i15;
+   i1 = 0;
+  } else {
+   i16 = 0;
+   L3 : while (1) {
+    if ((i17 | 0) < 48) {
+     _luaD_growstack(i2, 2);
+     i15 = HEAP32[i4 >> 2] | 0;
+    }
+    HEAP32[i4 >> 2] = i15 + 16;
+    i13 = _luaS_newlstr(i2, i13, i14 - i13 | 0) | 0;
+    HEAP32[i15 >> 2] = i13;
+    HEAP32[i15 + 8 >> 2] = HEAPU8[i13 + 4 | 0] | 64;
+    i13 = HEAP8[i14 + 1 | 0] | 0;
+    switch (i13 | 0) {
+    case 115:
+     {
+      i17 = HEAP32[i10 >> 2] | 0;
+      i13 = HEAP32[i17 >> 2] | 0;
+      HEAP32[i10 >> 2] = i17 + 4;
+      i13 = (i13 | 0) == 0 ? 5480 : i13;
+      i15 = _strlen(i13 | 0) | 0;
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = _luaS_newlstr(i2, i13, i15) | 0;
+      HEAP32[i17 >> 2] = i15;
+      HEAP32[i17 + 8 >> 2] = HEAPU8[i15 + 4 | 0] | 64;
+      break;
+     }
+    case 100:
+     {
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i13 = HEAP32[i10 >> 2] | 0;
+      i15 = HEAP32[i13 >> 2] | 0;
+      HEAP32[i10 >> 2] = i13 + 4;
+      HEAPF64[i17 >> 3] = +(i15 | 0);
+      HEAP32[i17 + 8 >> 2] = 3;
+      break;
+     }
+    case 37:
+     {
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = _luaS_newlstr(i2, 5496, 1) | 0;
+      HEAP32[i17 >> 2] = i15;
+      HEAP32[i17 + 8 >> 2] = HEAPU8[i15 + 4 | 0] | 64;
+      break;
+     }
+    case 99:
+     {
+      i15 = HEAP32[i10 >> 2] | 0;
+      i17 = HEAP32[i15 >> 2] | 0;
+      HEAP32[i10 >> 2] = i15 + 4;
+      HEAP8[i9] = i17;
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = _luaS_newlstr(i2, i9, 1) | 0;
+      HEAP32[i17 >> 2] = i15;
+      HEAP32[i17 + 8 >> 2] = HEAPU8[i15 + 4 | 0] | 64;
+      break;
+     }
+    case 102:
+     {
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = HEAP32[i10 >> 2] | 0;
+      d18 = +HEAPF64[i15 >> 3];
+      HEAP32[i10 >> 2] = i15 + 8;
+      HEAPF64[i17 >> 3] = d18;
+      HEAP32[i17 + 8 >> 2] = 3;
+      break;
+     }
+    case 112:
+     {
+      i17 = HEAP32[i10 >> 2] | 0;
+      i15 = HEAP32[i17 >> 2] | 0;
+      HEAP32[i10 >> 2] = i17 + 4;
+      HEAP32[i7 >> 2] = i15;
+      i15 = _sprintf(i8 | 0, 5488, i7 | 0) | 0;
+      i17 = HEAP32[i4 >> 2] | 0;
+      HEAP32[i4 >> 2] = i17 + 16;
+      i15 = _luaS_newlstr(i2, i8, i15) | 0;
+      HEAP32[i17 >> 2] = i15;
+      HEAP32[i17 + 8 >> 2] = HEAPU8[i15 + 4 | 0] | 64;
+      break;
+     }
+    default:
+     {
+      break L3;
+     }
+    }
+    i16 = i16 + 2 | 0;
+    i13 = i14 + 2 | 0;
+    i14 = _strchr(i13, 37) | 0;
+    i15 = HEAP32[i4 >> 2] | 0;
+    i17 = (HEAP32[i6 >> 2] | 0) - i15 | 0;
+    if ((i14 | 0) == 0) {
+     i5 = i13;
+     i11 = i17;
+     i12 = i15;
+     i1 = i16;
+     break L1;
+    }
+   }
+   HEAP32[i7 >> 2] = i13;
+   _luaG_runerror(i2, 5504, i7);
+  }
+ } while (0);
+ if ((i11 | 0) < 32) {
+  _luaD_growstack(i2, 1);
+  i12 = HEAP32[i4 >> 2] | 0;
+ }
+ i17 = _strlen(i5 | 0) | 0;
+ HEAP32[i4 >> 2] = i12 + 16;
+ i17 = _luaS_newlstr(i2, i5, i17) | 0;
+ HEAP32[i12 >> 2] = i17;
+ HEAP32[i12 + 8 >> 2] = HEAPU8[i17 + 4 | 0] | 64;
+ if ((i1 | 0) <= 0) {
+  i17 = HEAP32[i4 >> 2] | 0;
+  i17 = i17 + -16 | 0;
+  i17 = HEAP32[i17 >> 2] | 0;
+  i17 = i17 + 16 | 0;
+  STACKTOP = i3;
+  return i17 | 0;
+ }
+ _luaV_concat(i2, i1 | 1);
+ i17 = HEAP32[i4 >> 2] | 0;
+ i17 = i17 + -16 | 0;
+ i17 = HEAP32[i17 >> 2] | 0;
+ i17 = i17 + 16 | 0;
+ STACKTOP = i3;
+ return i17 | 0;
+}
+function _luaH_getn(i6) {
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d11 = 0.0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ i3 = i6 + 28 | 0;
+ i12 = HEAP32[i3 >> 2] | 0;
+ if ((i12 | 0) != 0 ? (i4 = HEAP32[i6 + 12 >> 2] | 0, (HEAP32[i4 + (i12 + -1 << 4) + 8 >> 2] | 0) == 0) : 0) {
+  if (i12 >>> 0 > 1) {
+   i10 = 0;
+  } else {
+   i13 = 0;
+   STACKTOP = i1;
+   return i13 | 0;
+  }
+  do {
+   i2 = (i10 + i12 | 0) >>> 1;
+   i3 = (HEAP32[i4 + (i2 + -1 << 4) + 8 >> 2] | 0) == 0;
+   i12 = i3 ? i2 : i12;
+   i10 = i3 ? i10 : i2;
+  } while ((i12 - i10 | 0) >>> 0 > 1);
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i4 = i6 + 16 | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 8016) {
+  i13 = i12;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i5 = i6 + 12 | 0;
+ i6 = i6 + 7 | 0;
+ i9 = i2 + 4 | 0;
+ i8 = i12 + 1 | 0;
+ i13 = i12;
+ i10 = i12;
+ while (1) {
+  i12 = i8 + -1 | 0;
+  L15 : do {
+   if (i12 >>> 0 < i13 >>> 0) {
+    i12 = (HEAP32[i5 >> 2] | 0) + (i12 << 4) | 0;
+   } else {
+    d11 = +(i8 | 0);
+    HEAPF64[i2 >> 3] = d11 + 1.0;
+    i13 = (HEAP32[i9 >> 2] | 0) + (HEAP32[i2 >> 2] | 0) | 0;
+    if ((i13 | 0) < 0) {
+     i12 = 0 - i13 | 0;
+     i13 = (i13 | 0) == (i12 | 0) ? 0 : i12;
+    }
+    i12 = (HEAP32[i4 >> 2] | 0) + (((i13 | 0) % ((1 << (HEAPU8[i6] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+    while (1) {
+     if ((HEAP32[i12 + 24 >> 2] | 0) == 3 ? +HEAPF64[i12 + 16 >> 3] == d11 : 0) {
+      break;
+     }
+     i12 = HEAP32[i12 + 28 >> 2] | 0;
+     if ((i12 | 0) == 0) {
+      i12 = 5192;
+      break L15;
+     }
+    }
+   }
+  } while (0);
+  if ((HEAP32[i12 + 8 >> 2] | 0) == 0) {
+   break;
+  }
+  i10 = i8 << 1;
+  if (i10 >>> 0 > 2147483645) {
+   i7 = 21;
+   break;
+  }
+  i12 = i8;
+  i8 = i10;
+  i13 = HEAP32[i3 >> 2] | 0;
+  i10 = i12;
+ }
+ if ((i7 | 0) == 21) {
+  i8 = i2 + 4 | 0;
+  i7 = 1;
+  while (1) {
+   i10 = i7 + -1 | 0;
+   L34 : do {
+    if (i10 >>> 0 < (HEAP32[i3 >> 2] | 0) >>> 0) {
+     i9 = (HEAP32[i5 >> 2] | 0) + (i10 << 4) | 0;
+    } else {
+     d11 = +(i7 | 0);
+     HEAPF64[i2 >> 3] = d11 + 1.0;
+     i9 = (HEAP32[i8 >> 2] | 0) + (HEAP32[i2 >> 2] | 0) | 0;
+     if ((i9 | 0) < 0) {
+      i12 = 0 - i9 | 0;
+      i9 = (i9 | 0) == (i12 | 0) ? 0 : i12;
+     }
+     i9 = (HEAP32[i4 >> 2] | 0) + (((i9 | 0) % ((1 << (HEAPU8[i6] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+     while (1) {
+      if ((HEAP32[i9 + 24 >> 2] | 0) == 3 ? +HEAPF64[i9 + 16 >> 3] == d11 : 0) {
+       break;
+      }
+      i9 = HEAP32[i9 + 28 >> 2] | 0;
+      if ((i9 | 0) == 0) {
+       i9 = 5192;
+       break L34;
+      }
+     }
+    }
+   } while (0);
+   if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+    break;
+   }
+   i7 = i7 + 1 | 0;
+  }
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ if (!((i8 - i10 | 0) >>> 0 > 1)) {
+  i13 = i10;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i7 = i2 + 4 | 0;
+ do {
+  i9 = (i8 + i10 | 0) >>> 1;
+  i12 = i9 + -1 | 0;
+  L55 : do {
+   if (i12 >>> 0 < (HEAP32[i3 >> 2] | 0) >>> 0) {
+    i12 = (HEAP32[i5 >> 2] | 0) + (i12 << 4) | 0;
+   } else {
+    d11 = +(i9 | 0);
+    HEAPF64[i2 >> 3] = d11 + 1.0;
+    i13 = (HEAP32[i7 >> 2] | 0) + (HEAP32[i2 >> 2] | 0) | 0;
+    if ((i13 | 0) < 0) {
+     i12 = 0 - i13 | 0;
+     i13 = (i13 | 0) == (i12 | 0) ? 0 : i12;
+    }
+    i12 = (HEAP32[i4 >> 2] | 0) + (((i13 | 0) % ((1 << (HEAPU8[i6] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+    while (1) {
+     if ((HEAP32[i12 + 24 >> 2] | 0) == 3 ? +HEAPF64[i12 + 16 >> 3] == d11 : 0) {
+      break;
+     }
+     i12 = HEAP32[i12 + 28 >> 2] | 0;
+     if ((i12 | 0) == 0) {
+      i12 = 5192;
+      break L55;
+     }
+    }
+   }
+  } while (0);
+  i12 = (HEAP32[i12 + 8 >> 2] | 0) == 0;
+  i8 = i12 ? i9 : i8;
+  i10 = i12 ? i10 : i9;
+ } while ((i8 - i10 | 0) >>> 0 > 1);
+ STACKTOP = i1;
+ return i10 | 0;
+}
+function _lua_resume(i4, i3, i7) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i3 | 0) == 0) {
+  i5 = 1;
+ } else {
+  i5 = (HEAPU16[i3 + 38 >> 1] | 0) + 1 & 65535;
+ }
+ i3 = i4 + 38 | 0;
+ HEAP16[i3 >> 1] = i5;
+ i5 = i4 + 36 | 0;
+ HEAP16[i5 >> 1] = 0;
+ i6 = i4 + 8 | 0;
+ i13 = _luaD_rawrunprotected(i4, 4, (HEAP32[i6 >> 2] | 0) + (0 - i7 << 4) | 0) | 0;
+ if ((i13 | 0) == -1) {
+  i18 = 2;
+  HEAP16[i5 >> 1] = 1;
+  i17 = HEAP16[i3 >> 1] | 0;
+  i17 = i17 + -1 << 16 >> 16;
+  HEAP16[i3 >> 1] = i17;
+  STACKTOP = i1;
+  return i18 | 0;
+ }
+ if (!(i13 >>> 0 > 1)) {
+  i18 = i13;
+  HEAP16[i5 >> 1] = 1;
+  i17 = HEAP16[i3 >> 1] | 0;
+  i17 = i17 + -1 << 16 >> 16;
+  HEAP16[i3 >> 1] = i17;
+  STACKTOP = i1;
+  return i18 | 0;
+ }
+ i7 = i4 + 16 | 0;
+ i12 = i4 + 28 | 0;
+ i11 = i4 + 41 | 0;
+ i10 = i4 + 68 | 0;
+ i9 = i4 + 32 | 0;
+ i8 = i4 + 12 | 0;
+ L10 : while (1) {
+  i15 = HEAP32[i7 >> 2] | 0;
+  if ((i15 | 0) == 0) {
+   break;
+  }
+  while (1) {
+   i14 = i15 + 18 | 0;
+   if (!((HEAP8[i14] & 16) == 0)) {
+    break;
+   }
+   i15 = HEAP32[i15 + 8 >> 2] | 0;
+   if ((i15 | 0) == 0) {
+    break L10;
+   }
+  }
+  i16 = HEAP32[i12 >> 2] | 0;
+  i17 = HEAP32[i15 + 20 >> 2] | 0;
+  i18 = i16 + i17 | 0;
+  _luaF_close(i4, i18);
+  if ((i13 | 0) == 4) {
+   i19 = HEAP32[(HEAP32[i8 >> 2] | 0) + 180 >> 2] | 0;
+   HEAP32[i18 >> 2] = i19;
+   HEAP32[i16 + (i17 + 8) >> 2] = HEAPU8[i19 + 4 | 0] | 0 | 64;
+  } else if ((i13 | 0) == 6) {
+   i19 = _luaS_newlstr(i4, 2424, 23) | 0;
+   HEAP32[i18 >> 2] = i19;
+   HEAP32[i16 + (i17 + 8) >> 2] = HEAPU8[i19 + 4 | 0] | 0 | 64;
+  } else {
+   i19 = HEAP32[i6 >> 2] | 0;
+   i21 = i19 + -16 | 0;
+   i20 = HEAP32[i21 + 4 >> 2] | 0;
+   HEAP32[i18 >> 2] = HEAP32[i21 >> 2];
+   HEAP32[i18 + 4 >> 2] = i20;
+   HEAP32[i16 + (i17 + 8) >> 2] = HEAP32[i19 + -8 >> 2];
+  }
+  i17 = i16 + (i17 + 16) | 0;
+  HEAP32[i6 >> 2] = i17;
+  HEAP32[i7 >> 2] = i15;
+  HEAP8[i11] = HEAP8[i15 + 36 | 0] | 0;
+  HEAP16[i5 >> 1] = 0;
+  if ((i15 | 0) != 0) {
+   i16 = i15;
+   do {
+    i18 = HEAP32[i16 + 4 >> 2] | 0;
+    i17 = i17 >>> 0 < i18 >>> 0 ? i18 : i17;
+    i16 = HEAP32[i16 + 8 >> 2] | 0;
+   } while ((i16 | 0) != 0);
+  }
+  i16 = i17 - (HEAP32[i12 >> 2] | 0) | 0;
+  i17 = (i16 >> 4) + 1 | 0;
+  i17 = ((i17 | 0) / 8 | 0) + 10 + i17 | 0;
+  i17 = (i17 | 0) > 1e6 ? 1e6 : i17;
+  if ((i16 | 0) <= 15999984 ? (i17 | 0) < (HEAP32[i9 >> 2] | 0) : 0) {
+   _luaD_reallocstack(i4, i17);
+  }
+  HEAP32[i10 >> 2] = HEAP32[i15 + 32 >> 2];
+  HEAP8[i14] = HEAPU8[i14] | 0 | 32;
+  HEAP8[i15 + 37 | 0] = i13;
+  i13 = _luaD_rawrunprotected(i4, 5, 0) | 0;
+  if (!(i13 >>> 0 > 1)) {
+   i2 = 24;
+   break;
+  }
+ }
+ if ((i2 | 0) == 24) {
+  HEAP16[i5 >> 1] = 1;
+  i21 = HEAP16[i3 >> 1] | 0;
+  i21 = i21 + -1 << 16 >> 16;
+  HEAP16[i3 >> 1] = i21;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ HEAP8[i4 + 6 | 0] = i13;
+ i2 = HEAP32[i6 >> 2] | 0;
+ if ((i13 | 0) == 4) {
+  i21 = HEAP32[(HEAP32[i8 >> 2] | 0) + 180 >> 2] | 0;
+  HEAP32[i2 >> 2] = i21;
+  HEAP32[i2 + 8 >> 2] = HEAPU8[i21 + 4 | 0] | 0 | 64;
+ } else if ((i13 | 0) == 6) {
+  i21 = _luaS_newlstr(i4, 2424, 23) | 0;
+  HEAP32[i2 >> 2] = i21;
+  HEAP32[i2 + 8 >> 2] = HEAPU8[i21 + 4 | 0] | 0 | 64;
+ } else {
+  i19 = i2 + -16 | 0;
+  i20 = HEAP32[i19 + 4 >> 2] | 0;
+  i21 = i2;
+  HEAP32[i21 >> 2] = HEAP32[i19 >> 2];
+  HEAP32[i21 + 4 >> 2] = i20;
+  HEAP32[i2 + 8 >> 2] = HEAP32[i2 + -8 >> 2];
+ }
+ i21 = i2 + 16 | 0;
+ HEAP32[i6 >> 2] = i21;
+ HEAP32[(HEAP32[i7 >> 2] | 0) + 4 >> 2] = i21;
+ i21 = i13;
+ HEAP16[i5 >> 1] = 1;
+ i20 = HEAP16[i3 >> 1] | 0;
+ i20 = i20 + -1 << 16 >> 16;
+ HEAP16[i3 >> 1] = i20;
+ STACKTOP = i1;
+ return i21 | 0;
+}
+function _luaK_goiftrue(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i2 = STACKTOP;
+ _luaK_dischargevars(i1, i3);
+ i12 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i12 | 0) == 10) {
+   i9 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+   i5 = i3 + 8 | 0;
+   i8 = HEAP32[i5 >> 2] | 0;
+   i7 = i9 + (i8 << 2) | 0;
+   if (!((i8 | 0) > 0 ? (i10 = i9 + (i8 + -1 << 2) | 0, i6 = HEAP32[i10 >> 2] | 0, (HEAP8[5584 + (i6 & 63) | 0] | 0) < 0) : 0)) {
+    i10 = i7;
+    i6 = HEAP32[i7 >> 2] | 0;
+   }
+   HEAP32[i10 >> 2] = ((i6 & 16320 | 0) == 0) << 6 | i6 & -16321;
+   i5 = HEAP32[i5 >> 2] | 0;
+   i8 = 18;
+  } else if (!((i12 | 0) == 2 | (i12 | 0) == 5 | (i12 | 0) == 4)) {
+   i5 = i3 + 8 | 0;
+   if ((i12 | 0) == 6) {
+    i8 = 14;
+   } else if ((i12 | 0) == 11 ? (i11 = HEAP32[(HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i5 >> 2] << 2) >> 2] | 0, (i11 & 63 | 0) == 20) : 0) {
+    i5 = i1 + 20 | 0;
+    HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + -1;
+    i5 = _condjump(i1, 27, i11 >>> 23, 0, 1) | 0;
+    i8 = 18;
+    break;
+   } else {
+    i8 = 9;
+   }
+   if ((i8 | 0) == 9) {
+    i12 = i1 + 48 | 0;
+    i10 = HEAP8[i12] | 0;
+    i11 = (i10 & 255) + 1 | 0;
+    i6 = (HEAP32[i1 >> 2] | 0) + 78 | 0;
+    do {
+     if (i11 >>> 0 > (HEAPU8[i6] | 0) >>> 0) {
+      if (i11 >>> 0 > 249) {
+       _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10536);
+      } else {
+       HEAP8[i6] = i11;
+       i9 = HEAP8[i12] | 0;
+       break;
+      }
+     } else {
+      i9 = i10;
+     }
+    } while (0);
+    i11 = (i9 & 255) + 1 | 0;
+    HEAP8[i12] = i11;
+    _discharge2reg(i1, i3, (i11 & 255) + -1 | 0);
+    if ((HEAP32[i3 >> 2] | 0) == 6) {
+     i8 = 14;
+    }
+   }
+   if (((i8 | 0) == 14 ? (i7 = HEAP32[i5 >> 2] | 0, (i7 & 256 | 0) == 0) : 0) ? (HEAPU8[i1 + 46 | 0] | 0) <= (i7 | 0) : 0) {
+    i12 = i1 + 48 | 0;
+    HEAP8[i12] = (HEAP8[i12] | 0) + -1 << 24 >> 24;
+   }
+   i5 = _condjump(i1, 28, 255, HEAP32[i5 >> 2] | 0, 0) | 0;
+   i8 = 18;
+  }
+ } while (0);
+ do {
+  if ((i8 | 0) == 18 ? (i4 = i3 + 20 | 0, !((i5 | 0) == -1)) : 0) {
+   i8 = HEAP32[i4 >> 2] | 0;
+   if ((i8 | 0) == -1) {
+    HEAP32[i4 >> 2] = i5;
+    break;
+   }
+   i4 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i7 = i4 + (i8 << 2) | 0;
+    i6 = HEAP32[i7 >> 2] | 0;
+    i9 = (i6 >>> 14) + -131071 | 0;
+    if ((i9 | 0) == -1) {
+     break;
+    }
+    i9 = i8 + 1 + i9 | 0;
+    if ((i9 | 0) == -1) {
+     break;
+    } else {
+     i8 = i9;
+    }
+   }
+   i4 = i5 + ~i8 | 0;
+   if ((((i4 | 0) > -1 ? i4 : 0 - i4 | 0) | 0) > 131071) {
+    _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+   } else {
+    HEAP32[i7 >> 2] = (i4 << 14) + 2147467264 | i6 & 16383;
+    break;
+   }
+  }
+ } while (0);
+ i3 = i3 + 16 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i1 + 24 >> 2] = HEAP32[i1 + 20 >> 2];
+ i5 = i1 + 28 | 0;
+ if ((i4 | 0) == -1) {
+  HEAP32[i3 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i8 = HEAP32[i5 >> 2] | 0;
+ if ((i8 | 0) == -1) {
+  HEAP32[i5 >> 2] = i4;
+  HEAP32[i3 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ while (1) {
+  i5 = i7 + (i8 << 2) | 0;
+  i6 = HEAP32[i5 >> 2] | 0;
+  i9 = (i6 >>> 14) + -131071 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  }
+  i9 = i8 + 1 + i9 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  } else {
+   i8 = i9;
+  }
+ }
+ i4 = i4 + ~i8 | 0;
+ if ((((i4 | 0) > -1 ? i4 : 0 - i4 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i5 >> 2] = (i4 << 14) + 2147467264 | i6 & 16383;
+ HEAP32[i3 >> 2] = -1;
+ STACKTOP = i2;
+ return;
+}
+function _luaO_str2d(i1, i3, i5) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, d9 = 0.0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ if ((_strpbrk(i1, 5464) | 0) != 0) {
+  i13 = 0;
+  STACKTOP = i2;
+  return i13 | 0;
+ }
+ do {
+  if ((_strpbrk(i1, 5472) | 0) == 0) {
+   d9 = +_strtod(i1, i4);
+   i10 = HEAP32[i4 >> 2] | 0;
+  } else {
+   HEAP32[i4 >> 2] = i1;
+   i8 = i1;
+   while (1) {
+    i6 = HEAP8[i8] | 0;
+    i10 = i8 + 1 | 0;
+    if ((HEAP8[(i6 & 255) + 10913 | 0] & 8) == 0) {
+     break;
+    } else {
+     i8 = i10;
+    }
+   }
+   if (i6 << 24 >> 24 == 43) {
+    i6 = 0;
+    i8 = i10;
+   } else if (i6 << 24 >> 24 == 45) {
+    i6 = 1;
+    i8 = i10;
+   } else {
+    i6 = 0;
+   }
+   if ((HEAP8[i8] | 0) == 48 ? (i13 = HEAP8[i8 + 1 | 0] | 0, i13 << 24 >> 24 == 88 | i13 << 24 >> 24 == 120) : 0) {
+    i10 = i8 + 2 | 0;
+    i8 = HEAP8[i10] | 0;
+    i12 = i8 & 255;
+    i11 = HEAP8[i12 + 10913 | 0] | 0;
+    if ((i11 & 16) == 0) {
+     d9 = 0.0;
+     i11 = i8;
+     i8 = 0;
+    } else {
+     d9 = 0.0;
+     i8 = 0;
+     while (1) {
+      if ((i11 & 2) == 0) {
+       i11 = (i12 | 32) + -87 | 0;
+      } else {
+       i11 = i12 + -48 | 0;
+      }
+      d9 = d9 * 16.0 + +(i11 | 0);
+      i8 = i8 + 1 | 0;
+      i10 = i10 + 1 | 0;
+      i13 = HEAP8[i10] | 0;
+      i12 = i13 & 255;
+      i11 = HEAP8[i12 + 10913 | 0] | 0;
+      if ((i11 & 16) == 0) {
+       i11 = i13;
+       break;
+      }
+     }
+    }
+    if (i11 << 24 >> 24 == 46) {
+     i10 = i10 + 1 | 0;
+     i13 = HEAPU8[i10] | 0;
+     i11 = HEAP8[i13 + 10913 | 0] | 0;
+     if ((i11 & 16) == 0) {
+      i12 = 0;
+     } else {
+      i12 = 0;
+      do {
+       if ((i11 & 2) == 0) {
+        i11 = (i13 | 32) + -87 | 0;
+       } else {
+        i11 = i13 + -48 | 0;
+       }
+       d9 = d9 * 16.0 + +(i11 | 0);
+       i12 = i12 + 1 | 0;
+       i10 = i10 + 1 | 0;
+       i13 = HEAPU8[i10] | 0;
+       i11 = HEAP8[i13 + 10913 | 0] | 0;
+      } while (!((i11 & 16) == 0));
+     }
+    } else {
+     i12 = 0;
+    }
+    if ((i12 | i8 | 0) != 0) {
+     i8 = Math_imul(i12, -4) | 0;
+     HEAP32[i4 >> 2] = i10;
+     i13 = HEAP8[i10] | 0;
+     if (i13 << 24 >> 24 == 80 | i13 << 24 >> 24 == 112) {
+      i13 = i10 + 1 | 0;
+      i11 = HEAP8[i13] | 0;
+      if (i11 << 24 >> 24 == 45) {
+       i11 = 1;
+       i13 = i10 + 2 | 0;
+      } else if (i11 << 24 >> 24 == 43) {
+       i11 = 0;
+       i13 = i10 + 2 | 0;
+      } else {
+       i11 = 0;
+      }
+      i12 = HEAP8[i13] | 0;
+      if (!((HEAP8[(i12 & 255) + 10913 | 0] & 2) == 0)) {
+       i10 = i13;
+       i7 = 0;
+       do {
+        i10 = i10 + 1 | 0;
+        i7 = (i12 << 24 >> 24) + -48 + (i7 * 10 | 0) | 0;
+        i12 = HEAP8[i10] | 0;
+       } while (!((HEAP8[(i12 & 255) + 10913 | 0] & 2) == 0));
+       i8 = ((i11 | 0) == 0 ? i7 : 0 - i7 | 0) + i8 | 0;
+       i7 = 29;
+      }
+     } else {
+      i7 = 29;
+     }
+     if ((i7 | 0) == 29) {
+      HEAP32[i4 >> 2] = i10;
+     }
+     if ((i6 | 0) != 0) {
+      d9 = -d9;
+     }
+     d9 = +_ldexp(d9, i8);
+     break;
+    }
+   }
+   HEAPF64[i5 >> 3] = 0.0;
+   i13 = 0;
+   STACKTOP = i2;
+   return i13 | 0;
+  }
+ } while (0);
+ HEAPF64[i5 >> 3] = d9;
+ if ((i10 | 0) == (i1 | 0)) {
+  i13 = 0;
+  STACKTOP = i2;
+  return i13 | 0;
+ }
+ if (!((HEAP8[(HEAPU8[i10] | 0) + 10913 | 0] & 8) == 0)) {
+  do {
+   i10 = i10 + 1 | 0;
+  } while (!((HEAP8[(HEAPU8[i10] | 0) + 10913 | 0] & 8) == 0));
+  HEAP32[i4 >> 2] = i10;
+ }
+ i13 = (i10 | 0) == (i1 + i3 | 0) | 0;
+ STACKTOP = i2;
+ return i13 | 0;
+}
+function _luaV_equalobj_(i2, i4, i5) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i3 = i4 + 8 | 0;
+ L1 : do {
+  switch (HEAP32[i3 >> 2] & 63 | 0) {
+  case 7:
+   {
+    i6 = HEAP32[i4 >> 2] | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    if ((i6 | 0) == (i7 | 0)) {
+     i7 = 1;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+    if ((i2 | 0) == 0) {
+     i7 = 0;
+     STACKTOP = i1;
+     return i7 | 0;
+    } else {
+     i6 = _get_equalTM(i2, HEAP32[i6 + 8 >> 2] | 0, HEAP32[i7 + 8 >> 2] | 0) | 0;
+     break L1;
+    }
+   }
+  case 5:
+   {
+    i7 = HEAP32[i4 >> 2] | 0;
+    i6 = HEAP32[i5 >> 2] | 0;
+    if ((i7 | 0) == (i6 | 0)) {
+     i7 = 1;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+    if ((i2 | 0) == 0) {
+     i7 = 0;
+     STACKTOP = i1;
+     return i7 | 0;
+    } else {
+     i6 = _get_equalTM(i2, HEAP32[i7 + 8 >> 2] | 0, HEAP32[i6 + 8 >> 2] | 0) | 0;
+     break L1;
+    }
+   }
+  case 4:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 20:
+   {
+    i7 = _luaS_eqlngstr(HEAP32[i4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 3:
+   {
+    i7 = +HEAPF64[i4 >> 3] == +HEAPF64[i5 >> 3] | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 1:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 22:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 2:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  case 0:
+   {
+    i7 = 1;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  default:
+   {
+    i7 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0) | 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+  }
+ } while (0);
+ if ((i6 | 0) == 0) {
+  i7 = 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i7 = i2 + 8 | 0;
+ i10 = HEAP32[i7 >> 2] | 0;
+ i9 = i2 + 28 | 0;
+ i8 = i10 - (HEAP32[i9 >> 2] | 0) | 0;
+ HEAP32[i7 >> 2] = i10 + 16;
+ i13 = i6;
+ i12 = HEAP32[i13 + 4 >> 2] | 0;
+ i11 = i10;
+ HEAP32[i11 >> 2] = HEAP32[i13 >> 2];
+ HEAP32[i11 + 4 >> 2] = i12;
+ HEAP32[i10 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+ i10 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i10 + 16;
+ i11 = i4;
+ i4 = HEAP32[i11 + 4 >> 2] | 0;
+ i6 = i10;
+ HEAP32[i6 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i6 + 4 >> 2] = i4;
+ HEAP32[i10 + 8 >> 2] = HEAP32[i3 >> 2];
+ i3 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i3 + 16;
+ i10 = i5;
+ i6 = HEAP32[i10 + 4 >> 2] | 0;
+ i4 = i3;
+ HEAP32[i4 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i4 + 4 >> 2] = i6;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ _luaD_call(i2, (HEAP32[i7 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i2 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i2 = HEAP32[i9 >> 2] | 0;
+ i3 = HEAP32[i7 >> 2] | 0;
+ i4 = i3 + -16 | 0;
+ HEAP32[i7 >> 2] = i4;
+ i5 = HEAP32[i4 + 4 >> 2] | 0;
+ i6 = i2 + i8 | 0;
+ HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i6 + 4 >> 2] = i5;
+ HEAP32[i2 + (i8 + 8) >> 2] = HEAP32[i3 + -8 >> 2];
+ i2 = HEAP32[i7 >> 2] | 0;
+ i3 = HEAP32[i2 + 8 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  if ((i3 | 0) == 1) {
+   i2 = (HEAP32[i2 >> 2] | 0) != 0;
+  } else {
+   i2 = 1;
+  }
+ } else {
+  i2 = 0;
+ }
+ i13 = i2 & 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _forbody(i1, i5, i6, i4, i9) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i8 = i3 + 12 | 0;
+ i19 = i3;
+ i11 = i1 + 48 | 0;
+ i7 = HEAP32[i11 >> 2] | 0;
+ i18 = i7 + 46 | 0;
+ i22 = (HEAPU8[i18] | 0) + 3 | 0;
+ HEAP8[i18] = i22;
+ i21 = i7 + 20 | 0;
+ i17 = i7 + 12 | 0;
+ i2 = i7 + 40 | 0;
+ i20 = HEAP32[(HEAP32[i7 >> 2] | 0) + 24 >> 2] | 0;
+ i10 = HEAP32[HEAP32[(HEAP32[i17 >> 2] | 0) + 64 >> 2] >> 2] | 0;
+ HEAP32[i20 + ((HEAP16[i10 + ((i22 & 255) + -3 + (HEAP32[i2 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i21 >> 2];
+ HEAP32[i20 + ((HEAP16[i10 + ((HEAPU8[i18] | 0) + -2 + (HEAP32[i2 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i21 >> 2];
+ HEAP32[i20 + ((HEAP16[i10 + ((HEAPU8[i18] | 0) + -1 + (HEAP32[i2 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i21 >> 2];
+ i2 = i1 + 16 | 0;
+ if ((HEAP32[i2 >> 2] | 0) != 259) {
+  _error_expected(i1, 259);
+ }
+ _luaX_next(i1);
+ i10 = (i9 | 0) != 0;
+ if (i10) {
+  i9 = _luaK_codeABx(i7, 33, i5, 131070) | 0;
+ } else {
+  i9 = _luaK_jump(i7) | 0;
+ }
+ HEAP8[i19 + 10 | 0] = 0;
+ HEAP8[i19 + 8 | 0] = HEAP8[i18] | 0;
+ i17 = HEAP32[(HEAP32[i17 >> 2] | 0) + 64 >> 2] | 0;
+ HEAP16[i19 + 4 >> 1] = HEAP32[i17 + 28 >> 2];
+ HEAP16[i19 + 6 >> 1] = HEAP32[i17 + 16 >> 2];
+ HEAP8[i19 + 9 | 0] = 0;
+ i17 = i7 + 16 | 0;
+ HEAP32[i19 >> 2] = HEAP32[i17 >> 2];
+ HEAP32[i17 >> 2] = i19;
+ i19 = HEAP32[i11 >> 2] | 0;
+ i17 = i19 + 46 | 0;
+ i18 = (HEAPU8[i17] | 0) + i4 | 0;
+ HEAP8[i17] = i18;
+ if ((i4 | 0) != 0 ? (i13 = i19 + 20 | 0, i12 = i19 + 40 | 0, i14 = HEAP32[(HEAP32[i19 >> 2] | 0) + 24 >> 2] | 0, i15 = HEAP32[HEAP32[(HEAP32[i19 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0, HEAP32[i14 + ((HEAP16[i15 + ((i18 & 255) - i4 + (HEAP32[i12 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i13 >> 2], i16 = i4 + -1 | 0, (i16 | 0) != 0) : 0) {
+  do {
+   HEAP32[i14 + ((HEAP16[i15 + ((HEAPU8[i17] | 0) - i16 + (HEAP32[i12 >> 2] | 0) << 1) >> 1] | 0) * 12 | 0) + 4 >> 2] = HEAP32[i13 >> 2];
+   i16 = i16 + -1 | 0;
+  } while ((i16 | 0) != 0);
+ }
+ _luaK_reserveregs(i7, i4);
+ i11 = HEAP32[i11 >> 2] | 0;
+ HEAP8[i8 + 10 | 0] = 0;
+ HEAP8[i8 + 8 | 0] = HEAP8[i11 + 46 | 0] | 0;
+ i22 = HEAP32[(HEAP32[i11 + 12 >> 2] | 0) + 64 >> 2] | 0;
+ HEAP16[i8 + 4 >> 1] = HEAP32[i22 + 28 >> 2];
+ HEAP16[i8 + 6 >> 1] = HEAP32[i22 + 16 >> 2];
+ HEAP8[i8 + 9 | 0] = 0;
+ i22 = i11 + 16 | 0;
+ HEAP32[i8 >> 2] = HEAP32[i22 >> 2];
+ HEAP32[i22 >> 2] = i8;
+ L13 : do {
+  i8 = HEAP32[i2 >> 2] | 0;
+  switch (i8 | 0) {
+  case 277:
+  case 286:
+  case 262:
+  case 261:
+  case 260:
+   {
+    break L13;
+   }
+  default:
+   {}
+  }
+  _statement(i1);
+ } while ((i8 | 0) != 274);
+ _leaveblock(i11);
+ _leaveblock(i7);
+ _luaK_patchtohere(i7, i9);
+ if (i10) {
+  i21 = _luaK_codeABx(i7, 32, i5, 131070) | 0;
+  i22 = i9 + 1 | 0;
+  _luaK_patchlist(i7, i21, i22);
+  _luaK_fixline(i7, i6);
+  STACKTOP = i3;
+  return;
+ } else {
+  _luaK_codeABC(i7, 34, i5, 0, i4) | 0;
+  _luaK_fixline(i7, i6);
+  i21 = _luaK_codeABx(i7, 35, i5 + 2 | 0, 131070) | 0;
+  i22 = i9 + 1 | 0;
+  _luaK_patchlist(i7, i21, i22);
+  _luaK_fixline(i7, i6);
+  STACKTOP = i3;
+  return;
+ }
+}
+function _dotty(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i6;
+ i4 = i6 + 4 | 0;
+ i2 = HEAP32[20] | 0;
+ HEAP32[20] = 0;
+ _lua_settop(i1, 0);
+ if ((_pushline(i1, 1) | 0) == 0) {
+  _lua_settop(i1, 0);
+  i10 = HEAP32[_stdout >> 2] | 0;
+  _fputc(10, i10 | 0) | 0;
+  _fflush(i10 | 0) | 0;
+  HEAP32[20] = i2;
+  STACKTOP = i6;
+  return;
+ }
+ i5 = HEAP32[_stderr >> 2] | 0;
+ L4 : while (1) {
+  i8 = _lua_tolstring(i1, 1, i4) | 0;
+  i8 = _luaL_loadbufferx(i1, i8, HEAP32[i4 >> 2] | 0, 256, 0) | 0;
+  L6 : do {
+   if ((i8 | 0) == 3) {
+    while (1) {
+     i8 = _lua_tolstring(i1, -1, i3) | 0;
+     i7 = HEAP32[i3 >> 2] | 0;
+     if (!(i7 >>> 0 > 4)) {
+      break;
+     }
+     if ((_strcmp(i8 + (i7 + -5) | 0, 264) | 0) != 0) {
+      break;
+     }
+     _lua_settop(i1, -2);
+     if ((_pushline(i1, 0) | 0) == 0) {
+      i7 = 23;
+      break L4;
+     }
+     _lua_pushlstring(i1, 184, 1) | 0;
+     _lua_insert(i1, -2);
+     _lua_concat(i1, 3);
+     i8 = _lua_tolstring(i1, 1, i4) | 0;
+     i8 = _luaL_loadbufferx(i1, i8, HEAP32[i4 >> 2] | 0, 256, 0) | 0;
+     if ((i8 | 0) != 3) {
+      i7 = 9;
+      break L6;
+     }
+    }
+    _lua_remove(i1, 1);
+    i8 = 3;
+    i7 = 10;
+   } else {
+    i7 = 9;
+   }
+  } while (0);
+  do {
+   if ((i7 | 0) == 9) {
+    _lua_remove(i1, 1);
+    if ((i8 | 0) == -1) {
+     i7 = 23;
+     break L4;
+    } else if ((i8 | 0) != 0) {
+     i7 = 10;
+     break;
+    }
+    i9 = _lua_gettop(i1) | 0;
+    _lua_pushcclosure(i1, 142, 0);
+    _lua_insert(i1, i9);
+    HEAP32[48] = i1;
+    _signal(2, 1) | 0;
+    i10 = _lua_pcallk(i1, 0, -1, i9, 0, 0) | 0;
+    _signal(2, 0) | 0;
+    _lua_remove(i1, i9);
+    if ((i10 | 0) == 0) {
+     i7 = 17;
+    } else {
+     i9 = 0;
+     i7 = 12;
+    }
+   }
+  } while (0);
+  if ((i7 | 0) == 10) {
+   i9 = (i8 | 0) == 0;
+   i7 = 12;
+  }
+  do {
+   if ((i7 | 0) == 12) {
+    i7 = 0;
+    if ((_lua_type(i1, -1) | 0) == 0) {
+     if (i9) {
+      i7 = 17;
+      break;
+     } else {
+      break;
+     }
+    }
+    i10 = _lua_tolstring(i1, -1, 0) | 0;
+    i8 = HEAP32[20] | 0;
+    if ((i8 | 0) != 0) {
+     HEAP32[i3 >> 2] = i8;
+     _fprintf(i5 | 0, 496, i3 | 0) | 0;
+     _fflush(i5 | 0) | 0;
+    }
+    HEAP32[i3 >> 2] = (i10 | 0) == 0 ? 48 : i10;
+    _fprintf(i5 | 0, 912, i3 | 0) | 0;
+    _fflush(i5 | 0) | 0;
+    _lua_settop(i1, -2);
+    _lua_gc(i1, 2, 0) | 0;
+    if (i9) {
+     i7 = 17;
+    }
+   }
+  } while (0);
+  if (((i7 | 0) == 17 ? (0, (_lua_gettop(i1) | 0) > 0) : 0) ? (_luaL_checkstack(i1, 20, 112), _lua_getglobal(i1, 144), _lua_insert(i1, 1), (_lua_pcallk(i1, (_lua_gettop(i1) | 0) + -1 | 0, 0, 0, 0, 0) | 0) != 0) : 0) {
+   i7 = HEAP32[20] | 0;
+   HEAP32[i3 >> 2] = _lua_tolstring(i1, -1, 0) | 0;
+   i8 = _lua_pushfstring(i1, 152, i3) | 0;
+   if ((i7 | 0) != 0) {
+    HEAP32[i3 >> 2] = i7;
+    _fprintf(i5 | 0, 496, i3 | 0) | 0;
+    _fflush(i5 | 0) | 0;
+   }
+   HEAP32[i3 >> 2] = i8;
+   _fprintf(i5 | 0, 912, i3 | 0) | 0;
+   _fflush(i5 | 0) | 0;
+  }
+  _lua_settop(i1, 0);
+  if ((_pushline(i1, 1) | 0) == 0) {
+   i7 = 23;
+   break;
+  }
+ }
+ if ((i7 | 0) == 23) {
+  _lua_settop(i1, 0);
+  i10 = HEAP32[_stdout >> 2] | 0;
+  _fputc(10, i10 | 0) | 0;
+  _fflush(i10 | 0) | 0;
+  HEAP32[20] = i2;
+  STACKTOP = i6;
+  return;
+ }
+}
+function _test_then_block(i5, i1) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i10 = i2 + 24 | 0;
+ i9 = i2;
+ i8 = i5 + 48 | 0;
+ i4 = HEAP32[i8 >> 2] | 0;
+ _luaX_next(i5);
+ _subexpr(i5, i9, 0) | 0;
+ i3 = i5 + 16 | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 275) {
+  _error_expected(i5, 275);
+ }
+ _luaX_next(i5);
+ i14 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i14 | 0) == 258 | (i14 | 0) == 266) {
+   _luaK_goiffalse(HEAP32[i8 >> 2] | 0, i9);
+   HEAP8[i10 + 10 | 0] = 0;
+   HEAP8[i10 + 8 | 0] = HEAP8[i4 + 46 | 0] | 0;
+   i11 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 64 >> 2] | 0;
+   HEAP16[i10 + 4 >> 1] = HEAP32[i11 + 28 >> 2];
+   HEAP16[i10 + 6 >> 1] = HEAP32[i11 + 16 >> 2];
+   HEAP8[i10 + 9 | 0] = 0;
+   i11 = i4 + 16 | 0;
+   HEAP32[i10 >> 2] = HEAP32[i11 >> 2];
+   HEAP32[i11 >> 2] = i10;
+   i11 = HEAP32[i9 + 16 >> 2] | 0;
+   i10 = HEAP32[i5 + 4 >> 2] | 0;
+   i14 = (HEAP32[i3 >> 2] | 0) == 266;
+   _luaX_next(i5);
+   do {
+    if (i14) {
+     if ((HEAP32[i3 >> 2] | 0) == 288) {
+      i7 = HEAP32[i5 + 24 >> 2] | 0;
+      _luaX_next(i5);
+      break;
+     } else {
+      _error_expected(i5, 288);
+     }
+    } else {
+     i7 = _luaS_new(HEAP32[i5 + 52 >> 2] | 0, 6304) | 0;
+    }
+   } while (0);
+   i14 = HEAP32[i5 + 64 >> 2] | 0;
+   i12 = i14 + 12 | 0;
+   i13 = i14 + 16 | 0;
+   i9 = HEAP32[i13 >> 2] | 0;
+   i14 = i14 + 20 | 0;
+   if ((i9 | 0) < (HEAP32[i14 >> 2] | 0)) {
+    i14 = HEAP32[i12 >> 2] | 0;
+   } else {
+    i14 = _luaM_growaux_(HEAP32[i5 + 52 >> 2] | 0, HEAP32[i12 >> 2] | 0, i14, 16, 32767, 6312) | 0;
+    HEAP32[i12 >> 2] = i14;
+   }
+   HEAP32[i14 + (i9 << 4) >> 2] = i7;
+   i14 = HEAP32[i12 >> 2] | 0;
+   HEAP32[i14 + (i9 << 4) + 8 >> 2] = i10;
+   HEAP8[i14 + (i9 << 4) + 12 | 0] = HEAP8[(HEAP32[i8 >> 2] | 0) + 46 | 0] | 0;
+   HEAP32[(HEAP32[i12 >> 2] | 0) + (i9 << 4) + 4 >> 2] = i11;
+   HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + 1;
+   _findlabel(i5, i9) | 0;
+   L18 : while (1) {
+    switch (HEAP32[i3 >> 2] | 0) {
+    case 286:
+    case 262:
+    case 261:
+    case 260:
+     {
+      break L18;
+     }
+    case 285:
+    case 59:
+     {
+      break;
+     }
+    default:
+     {
+      i6 = 16;
+      break L18;
+     }
+    }
+    _statement(i5);
+   }
+   if ((i6 | 0) == 16) {
+    i6 = _luaK_jump(i4) | 0;
+    break;
+   }
+   _leaveblock(i4);
+   STACKTOP = i2;
+   return;
+  } else {
+   _luaK_goiftrue(HEAP32[i8 >> 2] | 0, i9);
+   HEAP8[i10 + 10 | 0] = 0;
+   HEAP8[i10 + 8 | 0] = HEAP8[i4 + 46 | 0] | 0;
+   i6 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 64 >> 2] | 0;
+   HEAP16[i10 + 4 >> 1] = HEAP32[i6 + 28 >> 2];
+   HEAP16[i10 + 6 >> 1] = HEAP32[i6 + 16 >> 2];
+   HEAP8[i10 + 9 | 0] = 0;
+   i6 = i4 + 16 | 0;
+   HEAP32[i10 >> 2] = HEAP32[i6 >> 2];
+   HEAP32[i6 >> 2] = i10;
+   i6 = HEAP32[i9 + 20 >> 2] | 0;
+  }
+ } while (0);
+ L26 : do {
+  i7 = HEAP32[i3 >> 2] | 0;
+  switch (i7 | 0) {
+  case 277:
+  case 286:
+  case 262:
+  case 261:
+  case 260:
+   {
+    break L26;
+   }
+  default:
+   {}
+  }
+  _statement(i5);
+ } while ((i7 | 0) != 274);
+ _leaveblock(i4);
+ if (((HEAP32[i3 >> 2] | 0) + -260 | 0) >>> 0 < 2) {
+  _luaK_concat(i4, i1, _luaK_jump(i4) | 0);
+ }
+ _luaK_patchtohere(i4, i6);
+ STACKTOP = i2;
+ return;
+}
+function _luaL_gsub(i2, i13, i11, i10) {
+ i2 = i2 | 0;
+ i13 = i13 | 0;
+ i11 = i11 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i8 = i1;
+ i4 = i1 + 8 | 0;
+ i9 = _strlen(i11 | 0) | 0;
+ i6 = i4 + 12 | 0;
+ HEAP32[i6 >> 2] = i2;
+ i3 = i4 + 16 | 0;
+ HEAP32[i4 >> 2] = i3;
+ i5 = i4 + 8 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i7 = i4 + 4 | 0;
+ HEAP32[i7 >> 2] = 1024;
+ i12 = _strstr(i13, i11) | 0;
+ if ((i12 | 0) == 0) {
+  i14 = 0;
+  i17 = 1024;
+  i16 = i2;
+ } else {
+  i14 = 0;
+  i17 = 1024;
+  i16 = i2;
+  do {
+   i15 = i12 - i13 | 0;
+   if ((i17 - i14 | 0) >>> 0 < i15 >>> 0) {
+    i17 = i17 << 1;
+    i17 = (i17 - i14 | 0) >>> 0 < i15 >>> 0 ? i14 + i15 | 0 : i17;
+    if (i17 >>> 0 < i14 >>> 0 | (i17 - i14 | 0) >>> 0 < i15 >>> 0) {
+     _luaL_error(i16, 1272, i8) | 0;
+    }
+    i14 = _lua_newuserdata(i16, i17) | 0;
+    _memcpy(i14 | 0, HEAP32[i4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+    if ((HEAP32[i4 >> 2] | 0) != (i3 | 0)) {
+     _lua_remove(i16, -2);
+    }
+    HEAP32[i4 >> 2] = i14;
+    HEAP32[i7 >> 2] = i17;
+    i16 = i14;
+    i14 = HEAP32[i5 >> 2] | 0;
+   } else {
+    i16 = HEAP32[i4 >> 2] | 0;
+   }
+   _memcpy(i16 + i14 | 0, i13 | 0, i15 | 0) | 0;
+   i15 = (HEAP32[i5 >> 2] | 0) + i15 | 0;
+   HEAP32[i5 >> 2] = i15;
+   i13 = _strlen(i10 | 0) | 0;
+   i14 = HEAP32[i6 >> 2] | 0;
+   i16 = HEAP32[i7 >> 2] | 0;
+   if ((i16 - i15 | 0) >>> 0 < i13 >>> 0) {
+    i16 = i16 << 1;
+    i16 = (i16 - i15 | 0) >>> 0 < i13 >>> 0 ? i15 + i13 | 0 : i16;
+    if (i16 >>> 0 < i15 >>> 0 | (i16 - i15 | 0) >>> 0 < i13 >>> 0) {
+     _luaL_error(i14, 1272, i8) | 0;
+    }
+    i15 = _lua_newuserdata(i14, i16) | 0;
+    _memcpy(i15 | 0, HEAP32[i4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+    if ((HEAP32[i4 >> 2] | 0) != (i3 | 0)) {
+     _lua_remove(i14, -2);
+    }
+    HEAP32[i4 >> 2] = i15;
+    HEAP32[i7 >> 2] = i16;
+    i14 = i15;
+    i15 = HEAP32[i5 >> 2] | 0;
+   } else {
+    i14 = HEAP32[i4 >> 2] | 0;
+   }
+   _memcpy(i14 + i15 | 0, i10 | 0, i13 | 0) | 0;
+   i14 = (HEAP32[i5 >> 2] | 0) + i13 | 0;
+   HEAP32[i5 >> 2] = i14;
+   i13 = i12 + i9 | 0;
+   i12 = _strstr(i13, i11) | 0;
+   i16 = HEAP32[i6 >> 2] | 0;
+   i17 = HEAP32[i7 >> 2] | 0;
+  } while ((i12 | 0) != 0);
+ }
+ i9 = _strlen(i13 | 0) | 0;
+ if ((i17 - i14 | 0) >>> 0 < i9 >>> 0) {
+  i10 = i17 << 1;
+  i10 = (i10 - i14 | 0) >>> 0 < i9 >>> 0 ? i14 + i9 | 0 : i10;
+  if (i10 >>> 0 < i14 >>> 0 | (i10 - i14 | 0) >>> 0 < i9 >>> 0) {
+   _luaL_error(i16, 1272, i8) | 0;
+  }
+  i8 = _lua_newuserdata(i16, i10) | 0;
+  _memcpy(i8 | 0, HEAP32[i4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+  if ((HEAP32[i4 >> 2] | 0) != (i3 | 0)) {
+   _lua_remove(i16, -2);
+  }
+  HEAP32[i4 >> 2] = i8;
+  HEAP32[i7 >> 2] = i10;
+  i14 = HEAP32[i5 >> 2] | 0;
+ } else {
+  i8 = HEAP32[i4 >> 2] | 0;
+ }
+ _memcpy(i8 + i14 | 0, i13 | 0, i9 | 0) | 0;
+ i17 = (HEAP32[i5 >> 2] | 0) + i9 | 0;
+ HEAP32[i5 >> 2] = i17;
+ i5 = HEAP32[i6 >> 2] | 0;
+ _lua_pushlstring(i5, HEAP32[i4 >> 2] | 0, i17) | 0;
+ if ((HEAP32[i4 >> 2] | 0) == (i3 | 0)) {
+  i17 = _lua_tolstring(i2, -1, 0) | 0;
+  STACKTOP = i1;
+  return i17 | 0;
+ }
+ _lua_remove(i5, -2);
+ i17 = _lua_tolstring(i2, -1, 0) | 0;
+ STACKTOP = i1;
+ return i17 | 0;
+}
+function _luaK_goiffalse(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i2 = STACKTOP;
+ _luaK_dischargevars(i1, i3);
+ i9 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i9 | 0) == 10) {
+   i4 = HEAP32[i3 + 8 >> 2] | 0;
+   i8 = 15;
+  } else if (!((i9 | 0) == 3 | (i9 | 0) == 1)) {
+   i4 = i3 + 8 | 0;
+   if ((i9 | 0) == 6) {
+    i8 = 11;
+   } else if ((i9 | 0) == 11 ? (i10 = HEAP32[(HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i4 >> 2] << 2) >> 2] | 0, (i10 & 63 | 0) == 20) : 0) {
+    i4 = i1 + 20 | 0;
+    HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -1;
+    i4 = _condjump(i1, 27, i10 >>> 23, 0, 0) | 0;
+    i8 = 15;
+    break;
+   } else {
+    i8 = 6;
+   }
+   if ((i8 | 0) == 6) {
+    i9 = i1 + 48 | 0;
+    i11 = HEAP8[i9] | 0;
+    i10 = (i11 & 255) + 1 | 0;
+    i12 = (HEAP32[i1 >> 2] | 0) + 78 | 0;
+    do {
+     if (i10 >>> 0 > (HEAPU8[i12] | 0) >>> 0) {
+      if (i10 >>> 0 > 249) {
+       _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10536);
+      } else {
+       HEAP8[i12] = i10;
+       i7 = HEAP8[i9] | 0;
+       break;
+      }
+     } else {
+      i7 = i11;
+     }
+    } while (0);
+    i12 = (i7 & 255) + 1 | 0;
+    HEAP8[i9] = i12;
+    _discharge2reg(i1, i3, (i12 & 255) + -1 | 0);
+    if ((HEAP32[i3 >> 2] | 0) == 6) {
+     i8 = 11;
+    }
+   }
+   if (((i8 | 0) == 11 ? (i6 = HEAP32[i4 >> 2] | 0, (i6 & 256 | 0) == 0) : 0) ? (HEAPU8[i1 + 46 | 0] | 0 | 0) <= (i6 | 0) : 0) {
+    i12 = i1 + 48 | 0;
+    HEAP8[i12] = (HEAP8[i12] | 0) + -1 << 24 >> 24;
+   }
+   i4 = _condjump(i1, 28, 255, HEAP32[i4 >> 2] | 0, 1) | 0;
+   i8 = 15;
+  }
+ } while (0);
+ do {
+  if ((i8 | 0) == 15 ? (i5 = i3 + 16 | 0, !((i4 | 0) == -1)) : 0) {
+   i8 = HEAP32[i5 >> 2] | 0;
+   if ((i8 | 0) == -1) {
+    HEAP32[i5 >> 2] = i4;
+    break;
+   }
+   i5 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+   while (1) {
+    i7 = i5 + (i8 << 2) | 0;
+    i6 = HEAP32[i7 >> 2] | 0;
+    i9 = (i6 >>> 14) + -131071 | 0;
+    if ((i9 | 0) == -1) {
+     break;
+    }
+    i9 = i8 + 1 + i9 | 0;
+    if ((i9 | 0) == -1) {
+     break;
+    } else {
+     i8 = i9;
+    }
+   }
+   i4 = i4 + ~i8 | 0;
+   if ((((i4 | 0) > -1 ? i4 : 0 - i4 | 0) | 0) > 131071) {
+    _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+   } else {
+    HEAP32[i7 >> 2] = (i4 << 14) + 2147467264 | i6 & 16383;
+    break;
+   }
+  }
+ } while (0);
+ i3 = i3 + 20 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i1 + 24 >> 2] = HEAP32[i1 + 20 >> 2];
+ i5 = i1 + 28 | 0;
+ if ((i4 | 0) == -1) {
+  HEAP32[i3 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i8 = HEAP32[i5 >> 2] | 0;
+ if ((i8 | 0) == -1) {
+  HEAP32[i5 >> 2] = i4;
+  HEAP32[i3 >> 2] = -1;
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ while (1) {
+  i5 = i7 + (i8 << 2) | 0;
+  i6 = HEAP32[i5 >> 2] | 0;
+  i9 = (i6 >>> 14) + -131071 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  }
+  i9 = i8 + 1 + i9 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  } else {
+   i8 = i9;
+  }
+ }
+ i4 = i4 + ~i8 | 0;
+ if ((((i4 | 0) > -1 ? i4 : 0 - i4 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i5 >> 2] = (i4 << 14) + 2147467264 | i6 & 16383;
+ HEAP32[i3 >> 2] = -1;
+ STACKTOP = i2;
+ return;
+}
+function _luaV_settable(i2, i11, i7, i9) {
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ i7 = i7 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i6;
+ i4 = i2 + 12 | 0;
+ i3 = i11;
+ i13 = HEAP32[i11 + 8 >> 2] | 0;
+ i12 = 0;
+ while (1) {
+  i11 = i3 + 8 | 0;
+  if ((i13 | 0) != 69) {
+   i14 = _luaT_gettmbyobj(i2, i3, 1) | 0;
+   i13 = HEAP32[i14 + 8 >> 2] | 0;
+   if ((i13 | 0) == 0) {
+    i1 = 16;
+    break;
+   }
+  } else {
+   i8 = HEAP32[i3 >> 2] | 0;
+   i13 = _luaH_get(i8, i7) | 0;
+   if ((HEAP32[i13 + 8 >> 2] | 0) != 0) {
+    i10 = i13;
+    break;
+   }
+   i14 = HEAP32[i8 + 8 >> 2] | 0;
+   if ((i14 | 0) == 0) {
+    i1 = 9;
+    break;
+   }
+   if (!((HEAP8[i14 + 6 | 0] & 2) == 0)) {
+    i1 = 9;
+    break;
+   }
+   i14 = _luaT_gettm(i14, 1, HEAP32[(HEAP32[i4 >> 2] | 0) + 188 >> 2] | 0) | 0;
+   if ((i14 | 0) == 0) {
+    i1 = 9;
+    break;
+   }
+   i13 = HEAP32[i14 + 8 >> 2] | 0;
+  }
+  i12 = i12 + 1 | 0;
+  if ((i13 & 15 | 0) == 6) {
+   i1 = 18;
+   break;
+  }
+  if ((i12 | 0) < 100) {
+   i3 = i14;
+  } else {
+   i1 = 19;
+   break;
+  }
+ }
+ if ((i1 | 0) == 9) {
+  if ((i13 | 0) == 5192) {
+   i10 = _luaH_newkey(i2, i8, i7) | 0;
+  } else {
+   i10 = i13;
+  }
+ } else if ((i1 | 0) == 16) {
+  _luaG_typeerror(i2, i3, 8944);
+ } else if ((i1 | 0) == 18) {
+  i13 = i2 + 8 | 0;
+  i8 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i8 + 16;
+  i5 = i14;
+  i12 = HEAP32[i5 + 4 >> 2] | 0;
+  i10 = i8;
+  HEAP32[i10 >> 2] = HEAP32[i5 >> 2];
+  HEAP32[i10 + 4 >> 2] = i12;
+  HEAP32[i8 + 8 >> 2] = HEAP32[i14 + 8 >> 2];
+  i14 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i14 + 16;
+  i8 = i3;
+  i10 = HEAP32[i8 + 4 >> 2] | 0;
+  i12 = i14;
+  HEAP32[i12 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i12 + 4 >> 2] = i10;
+  HEAP32[i14 + 8 >> 2] = HEAP32[i11 >> 2];
+  i14 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i14 + 16;
+  i12 = i7;
+  i11 = HEAP32[i12 + 4 >> 2] | 0;
+  i10 = i14;
+  HEAP32[i10 >> 2] = HEAP32[i12 >> 2];
+  HEAP32[i10 + 4 >> 2] = i11;
+  HEAP32[i14 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+  i14 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i14 + 16;
+  i10 = i9;
+  i11 = HEAP32[i10 + 4 >> 2] | 0;
+  i12 = i14;
+  HEAP32[i12 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i12 + 4 >> 2] = i11;
+  HEAP32[i14 + 8 >> 2] = HEAP32[i9 + 8 >> 2];
+  _luaD_call(i2, (HEAP32[i13 >> 2] | 0) + -64 | 0, 0, HEAP8[(HEAP32[i2 + 16 >> 2] | 0) + 18 | 0] & 1);
+  STACKTOP = i6;
+  return;
+ } else if ((i1 | 0) == 19) {
+  _luaG_runerror(i2, 8976, i5);
+ }
+ i12 = i9;
+ i13 = HEAP32[i12 + 4 >> 2] | 0;
+ i14 = i10;
+ HEAP32[i14 >> 2] = HEAP32[i12 >> 2];
+ HEAP32[i14 + 4 >> 2] = i13;
+ i14 = i9 + 8 | 0;
+ HEAP32[i10 + 8 >> 2] = HEAP32[i14 >> 2];
+ HEAP8[i8 + 6 | 0] = 0;
+ if ((HEAP32[i14 >> 2] & 64 | 0) == 0) {
+  STACKTOP = i6;
+  return;
+ }
+ if ((HEAP8[(HEAP32[i9 >> 2] | 0) + 5 | 0] & 3) == 0) {
+  STACKTOP = i6;
+  return;
+ }
+ if ((HEAP8[i8 + 5 | 0] & 4) == 0) {
+  STACKTOP = i6;
+  return;
+ }
+ _luaC_barrierback_(i2, i8);
+ STACKTOP = i6;
+ return;
+}
+function _luaK_code(i4, i5) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0;
+ i2 = STACKTOP;
+ i1 = HEAP32[i4 >> 2] | 0;
+ i7 = i4 + 28 | 0;
+ i15 = HEAP32[i7 >> 2] | 0;
+ i3 = i4 + 20 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ do {
+  if (!((i15 | 0) == -1)) {
+   i11 = HEAP32[i1 + 12 >> 2] | 0;
+   while (1) {
+    i12 = i11 + (i15 << 2) | 0;
+    i14 = HEAP32[i12 >> 2] | 0;
+    i13 = (i14 >>> 14) + -131071 | 0;
+    if ((i13 | 0) == -1) {
+     i13 = -1;
+    } else {
+     i13 = i15 + 1 + i13 | 0;
+    }
+    if ((i15 | 0) > 0 ? (i9 = i11 + (i15 + -1 << 2) | 0, i10 = HEAP32[i9 >> 2] | 0, (HEAP8[5584 + (i10 & 63) | 0] | 0) < 0) : 0) {
+     i17 = i9;
+     i16 = i10;
+    } else {
+     i17 = i12;
+     i16 = i14;
+    }
+    if ((i16 & 63 | 0) == 28) {
+     HEAP32[i17 >> 2] = i16 & 8372224 | i16 >>> 23 << 6 | 27;
+     i14 = i8 + ~i15 | 0;
+     if ((((i14 | 0) > -1 ? i14 : 0 - i14 | 0) | 0) > 131071) {
+      i8 = 10;
+      break;
+     }
+     i14 = HEAP32[i12 >> 2] & 16383 | (i14 << 14) + 2147467264;
+    } else {
+     i15 = i8 + ~i15 | 0;
+     if ((((i15 | 0) > -1 ? i15 : 0 - i15 | 0) | 0) > 131071) {
+      i8 = 13;
+      break;
+     }
+     i14 = (i15 << 14) + 2147467264 | i14 & 16383;
+    }
+    HEAP32[i12 >> 2] = i14;
+    if ((i13 | 0) == -1) {
+     i8 = 16;
+     break;
+    } else {
+     i15 = i13;
+    }
+   }
+   if ((i8 | 0) == 10) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   } else if ((i8 | 0) == 13) {
+    _luaX_syntaxerror(HEAP32[i4 + 12 >> 2] | 0, 10624);
+   } else if ((i8 | 0) == 16) {
+    i6 = HEAP32[i3 >> 2] | 0;
+    break;
+   }
+  } else {
+   i6 = i8;
+  }
+ } while (0);
+ HEAP32[i7 >> 2] = -1;
+ i7 = i1 + 48 | 0;
+ if ((i6 | 0) < (HEAP32[i7 >> 2] | 0)) {
+  i7 = i1 + 12 | 0;
+ } else {
+  i6 = i1 + 12 | 0;
+  HEAP32[i6 >> 2] = _luaM_growaux_(HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 52 >> 2] | 0, HEAP32[i6 >> 2] | 0, i7, 4, 2147483645, 10616) | 0;
+  i7 = i6;
+  i6 = HEAP32[i3 >> 2] | 0;
+ }
+ HEAP32[(HEAP32[i7 >> 2] | 0) + (i6 << 2) >> 2] = i5;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i6 = i1 + 52 | 0;
+ i4 = i4 + 12 | 0;
+ if ((i5 | 0) < (HEAP32[i6 >> 2] | 0)) {
+  i15 = i1 + 20 | 0;
+  i17 = i5;
+  i16 = HEAP32[i4 >> 2] | 0;
+  i16 = i16 + 8 | 0;
+  i16 = HEAP32[i16 >> 2] | 0;
+  i15 = HEAP32[i15 >> 2] | 0;
+  i17 = i15 + (i17 << 2) | 0;
+  HEAP32[i17 >> 2] = i16;
+  i17 = HEAP32[i3 >> 2] | 0;
+  i16 = i17 + 1 | 0;
+  HEAP32[i3 >> 2] = i16;
+  STACKTOP = i2;
+  return i17 | 0;
+ } else {
+  i15 = i1 + 20 | 0;
+  HEAP32[i15 >> 2] = _luaM_growaux_(HEAP32[(HEAP32[i4 >> 2] | 0) + 52 >> 2] | 0, HEAP32[i15 >> 2] | 0, i6, 4, 2147483645, 10616) | 0;
+  i17 = HEAP32[i3 >> 2] | 0;
+  i16 = HEAP32[i4 >> 2] | 0;
+  i16 = i16 + 8 | 0;
+  i16 = HEAP32[i16 >> 2] | 0;
+  i15 = HEAP32[i15 >> 2] | 0;
+  i17 = i15 + (i17 << 2) | 0;
+  HEAP32[i17 >> 2] = i16;
+  i17 = HEAP32[i3 >> 2] | 0;
+  i16 = i17 + 1 | 0;
+  HEAP32[i3 >> 2] = i16;
+  STACKTOP = i2;
+  return i17 | 0;
+ }
+ return 0;
+}
+function _luaH_next(i9, i5, i2) {
+ i9 = i9 | 0;
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, d14 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i8 = i1 + 8 | 0;
+ i11 = i1;
+ i3 = i2 + 8 | 0;
+ i10 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i10 | 0) != 0) {
+   if ((((i10 | 0) == 3 ? (d14 = +HEAPF64[i2 >> 3], HEAPF64[i11 >> 3] = d14 + 6755399441055744.0, i12 = HEAP32[i11 >> 2] | 0, +(i12 | 0) == d14) : 0) ? (i12 | 0) > 0 : 0) ? (i13 = HEAP32[i5 + 28 >> 2] | 0, (i12 | 0) <= (i13 | 0)) : 0) {
+    i6 = i13;
+    i7 = i12 + -1 | 0;
+    break;
+   }
+   i10 = _mainposition(i5, i2) | 0;
+   while (1) {
+    i4 = i10 + 16 | 0;
+    i11 = i10 + 24 | 0;
+    i12 = HEAP32[i11 >> 2] | 0;
+    if ((i12 | 0) == (HEAP32[i3 >> 2] | 0)) {
+     if ((_luaV_equalobj_(0, i4, i2) | 0) != 0) {
+      i4 = 15;
+      break;
+     }
+     i12 = HEAP32[i11 >> 2] | 0;
+    }
+    if (((i12 | 0) == 11 ? (HEAP32[i3 >> 2] & 64 | 0) != 0 : 0) ? (HEAP32[i4 >> 2] | 0) == (HEAP32[i2 >> 2] | 0) : 0) {
+     i4 = 15;
+     break;
+    }
+    i10 = HEAP32[i10 + 28 >> 2] | 0;
+    if ((i10 | 0) == 0) {
+     i4 = 18;
+     break;
+    }
+   }
+   if ((i4 | 0) == 15) {
+    i7 = HEAP32[i5 + 28 >> 2] | 0;
+    i6 = i7;
+    i7 = (i10 - (HEAP32[i5 + 16 >> 2] | 0) >> 5) + i7 | 0;
+    break;
+   } else if ((i4 | 0) == 18) {
+    _luaG_runerror(i9, 8064, i8);
+   }
+  } else {
+   i6 = HEAP32[i5 + 28 >> 2] | 0;
+   i7 = -1;
+  }
+ } while (0);
+ i8 = i5 + 12 | 0;
+ while (1) {
+  i9 = i7 + 1 | 0;
+  if ((i9 | 0) >= (i6 | 0)) {
+   break;
+  }
+  i11 = HEAP32[i8 >> 2] | 0;
+  i10 = i11 + (i9 << 4) + 8 | 0;
+  if ((HEAP32[i10 >> 2] | 0) == 0) {
+   i7 = i9;
+  } else {
+   i4 = 21;
+   break;
+  }
+ }
+ if ((i4 | 0) == 21) {
+  HEAPF64[i2 >> 3] = +(i7 + 2 | 0);
+  HEAP32[i3 >> 2] = 3;
+  i11 = i11 + (i9 << 4) | 0;
+  i12 = HEAP32[i11 + 4 >> 2] | 0;
+  i13 = i2 + 16 | 0;
+  HEAP32[i13 >> 2] = HEAP32[i11 >> 2];
+  HEAP32[i13 + 4 >> 2] = i12;
+  HEAP32[i2 + 24 >> 2] = HEAP32[i10 >> 2];
+  i13 = 1;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i8 = i9 - i6 | 0;
+ i6 = 1 << (HEAPU8[i5 + 7 | 0] | 0);
+ if ((i8 | 0) >= (i6 | 0)) {
+  i13 = 0;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i7 = i5 + 16 | 0;
+ i5 = HEAP32[i7 >> 2] | 0;
+ while (1) {
+  i9 = i8 + 1 | 0;
+  if ((HEAP32[i5 + (i8 << 5) + 8 >> 2] | 0) != 0) {
+   break;
+  }
+  if ((i9 | 0) < (i6 | 0)) {
+   i8 = i9;
+  } else {
+   i2 = 0;
+   i4 = 27;
+   break;
+  }
+ }
+ if ((i4 | 0) == 27) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ i11 = i5 + (i8 << 5) + 16 | 0;
+ i10 = HEAP32[i11 + 4 >> 2] | 0;
+ i13 = i2;
+ HEAP32[i13 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i13 + 4 >> 2] = i10;
+ HEAP32[i3 >> 2] = HEAP32[i5 + (i8 << 5) + 24 >> 2];
+ i13 = HEAP32[i7 >> 2] | 0;
+ i10 = i13 + (i8 << 5) | 0;
+ i11 = HEAP32[i10 + 4 >> 2] | 0;
+ i12 = i2 + 16 | 0;
+ HEAP32[i12 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i12 + 4 >> 2] = i11;
+ HEAP32[i2 + 24 >> 2] = HEAP32[i13 + (i8 << 5) + 8 >> 2];
+ i13 = 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _g_read(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i7 = i4 + 8 | 0;
+ i9 = i4;
+ i10 = _lua_gettop(i1) | 0;
+ _clearerr(i3 | 0);
+ L1 : do {
+  if ((i10 | 0) == 1) {
+   i11 = i2 + 1 | 0;
+   i12 = _read_line(i1, i3, 1) | 0;
+  } else {
+   _luaL_checkstack(i1, i10 + 19 | 0, 3256);
+   i6 = i7 + 8 | 0;
+   i5 = i7 + 8 | 0;
+   i10 = i10 + -2 | 0;
+   i11 = i2;
+   L4 : while (1) {
+    do {
+     if ((_lua_type(i1, i11) | 0) == 3) {
+      i12 = _lua_tointegerx(i1, i11, 0) | 0;
+      if ((i12 | 0) == 0) {
+       i12 = _fgetc(i3 | 0) | 0;
+       _ungetc(i12 | 0, i3 | 0) | 0;
+       _lua_pushlstring(i1, 0, 0) | 0;
+       i12 = (i12 | 0) != -1 | 0;
+       break;
+      } else {
+       _luaL_buffinit(i1, i7);
+       i12 = _fread(_luaL_prepbuffsize(i7, i12) | 0, 1, i12 | 0, i3 | 0) | 0;
+       HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i12;
+       _luaL_pushresult(i7);
+       i12 = (i12 | 0) != 0 | 0;
+       break;
+      }
+     } else {
+      i12 = _lua_tolstring(i1, i11, 0) | 0;
+      if (!((i12 | 0) != 0 ? (HEAP8[i12] | 0) == 42 : 0)) {
+       _luaL_argerror(i1, i11, 3280) | 0;
+      }
+      i12 = HEAP8[i12 + 1 | 0] | 0;
+      if ((i12 | 0) == 110) {
+       HEAP32[i7 >> 2] = i9;
+       if ((_fscanf(i3 | 0, 3312, i7 | 0) | 0) != 1) {
+        i8 = 14;
+        break L4;
+       }
+       _lua_pushnumber(i1, +HEAPF64[i9 >> 3]);
+       i12 = 1;
+       break;
+      } else if ((i12 | 0) == 108) {
+       i12 = _read_line(i1, i3, 1) | 0;
+       break;
+      } else if ((i12 | 0) == 76) {
+       i12 = _read_line(i1, i3, 0) | 0;
+       break;
+      } else if ((i12 | 0) == 97) {
+       _luaL_buffinit(i1, i7);
+       i12 = _fread(_luaL_prepbuffsize(i7, 1024) | 0, 1, 1024, i3 | 0) | 0;
+       HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i12;
+       if (!(i12 >>> 0 < 1024)) {
+        i12 = 1024;
+        do {
+         i12 = i12 << (i12 >>> 0 < 1073741824);
+         i13 = _fread(_luaL_prepbuffsize(i7, i12) | 0, 1, i12 | 0, i3 | 0) | 0;
+         HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i13;
+        } while (!(i13 >>> 0 < i12 >>> 0));
+       }
+       _luaL_pushresult(i7);
+       i12 = 1;
+       break;
+      } else {
+       break L4;
+      }
+     }
+    } while (0);
+    i11 = i11 + 1 | 0;
+    if ((i10 | 0) == 0 | (i12 | 0) == 0) {
+     break L1;
+    } else {
+     i10 = i10 + -1 | 0;
+    }
+   }
+   if ((i8 | 0) == 14) {
+    _lua_pushnil(i1);
+    i11 = i11 + 1 | 0;
+    i12 = 0;
+    break;
+   }
+   i13 = _luaL_argerror(i1, i11, 3296) | 0;
+   STACKTOP = i4;
+   return i13 | 0;
+  }
+ } while (0);
+ if ((_ferror(i3 | 0) | 0) != 0) {
+  i13 = _luaL_fileresult(i1, 0, 0) | 0;
+  STACKTOP = i4;
+  return i13 | 0;
+ }
+ if ((i12 | 0) == 0) {
+  _lua_settop(i1, -2);
+  _lua_pushnil(i1);
+ }
+ i13 = i11 - i2 | 0;
+ STACKTOP = i4;
+ return i13 | 0;
+}
+function _luaY_parser(i8, i12, i10, i11, i9, i13) {
+ i8 = i8 | 0;
+ i12 = i12 | 0;
+ i10 = i10 | 0;
+ i11 = i11 | 0;
+ i9 = i9 | 0;
+ i13 = i13 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i14 = 0, i15 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 176 | 0;
+ i5 = i2 + 156 | 0;
+ i7 = i2 + 80 | 0;
+ i4 = i2;
+ i6 = i2 + 104 | 0;
+ i3 = _luaF_newLclosure(i8, 1) | 0;
+ i15 = i8 + 8 | 0;
+ i14 = HEAP32[i15 >> 2] | 0;
+ HEAP32[i14 >> 2] = i3;
+ HEAP32[i14 + 8 >> 2] = 70;
+ i14 = (HEAP32[i15 >> 2] | 0) + 16 | 0;
+ HEAP32[i15 >> 2] = i14;
+ if (((HEAP32[i8 + 24 >> 2] | 0) - i14 | 0) < 16) {
+  _luaD_growstack(i8, 0);
+ }
+ i14 = _luaF_newproto(i8) | 0;
+ HEAP32[i3 + 12 >> 2] = i14;
+ HEAP32[i6 >> 2] = i14;
+ i9 = _luaS_new(i8, i9) | 0;
+ HEAP32[(HEAP32[i6 >> 2] | 0) + 36 >> 2] = i9;
+ HEAP32[i4 + 60 >> 2] = i10;
+ i9 = i4 + 64 | 0;
+ HEAP32[i9 >> 2] = i11;
+ HEAP32[i11 + 28 >> 2] = 0;
+ HEAP32[i11 + 16 >> 2] = 0;
+ HEAP32[i11 + 4 >> 2] = 0;
+ _luaX_setinput(i8, i4, i12, HEAP32[(HEAP32[i6 >> 2] | 0) + 36 >> 2] | 0, i13);
+ i10 = HEAP32[i4 + 52 >> 2] | 0;
+ i13 = i4 + 48 | 0;
+ HEAP32[i6 + 8 >> 2] = HEAP32[i13 >> 2];
+ i8 = i6 + 12 | 0;
+ HEAP32[i8 >> 2] = i4;
+ HEAP32[i13 >> 2] = i6;
+ HEAP32[i6 + 20 >> 2] = 0;
+ HEAP32[i6 + 24 >> 2] = 0;
+ HEAP32[i6 + 28 >> 2] = -1;
+ HEAP32[i6 + 32 >> 2] = 0;
+ HEAP32[i6 + 36 >> 2] = 0;
+ i13 = i6 + 44 | 0;
+ HEAP32[i13 + 0 >> 2] = 0;
+ HEAP8[i13 + 4 | 0] = 0;
+ HEAP32[i6 + 40 >> 2] = HEAP32[(HEAP32[i9 >> 2] | 0) + 4 >> 2];
+ i9 = i6 + 16 | 0;
+ HEAP32[i9 >> 2] = 0;
+ i13 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i13 + 36 >> 2] = HEAP32[i4 + 68 >> 2];
+ HEAP8[i13 + 78 | 0] = 2;
+ i13 = _luaH_new(i10) | 0;
+ HEAP32[i6 + 4 >> 2] = i13;
+ i14 = i10 + 8 | 0;
+ i15 = HEAP32[i14 >> 2] | 0;
+ HEAP32[i15 >> 2] = i13;
+ HEAP32[i15 + 8 >> 2] = 69;
+ i15 = (HEAP32[i14 >> 2] | 0) + 16 | 0;
+ HEAP32[i14 >> 2] = i15;
+ if (((HEAP32[i10 + 24 >> 2] | 0) - i15 | 0) < 16) {
+  _luaD_growstack(i10, 0);
+ }
+ HEAP8[i5 + 10 | 0] = 0;
+ HEAP8[i5 + 8 | 0] = HEAP8[i6 + 46 | 0] | 0;
+ i15 = HEAP32[(HEAP32[i8 >> 2] | 0) + 64 >> 2] | 0;
+ HEAP16[i5 + 4 >> 1] = HEAP32[i15 + 28 >> 2];
+ HEAP16[i5 + 6 >> 1] = HEAP32[i15 + 16 >> 2];
+ HEAP8[i5 + 9 | 0] = 0;
+ HEAP32[i5 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i9 >> 2] = i5;
+ HEAP8[(HEAP32[i6 >> 2] | 0) + 77 | 0] = 1;
+ HEAP32[i7 + 16 >> 2] = -1;
+ HEAP32[i7 + 20 >> 2] = -1;
+ HEAP32[i7 >> 2] = 7;
+ HEAP32[i7 + 8 >> 2] = 0;
+ _newupvalue(i6, HEAP32[i4 + 72 >> 2] | 0, i7) | 0;
+ _luaX_next(i4);
+ i5 = i4 + 16 | 0;
+ L7 : while (1) {
+  i6 = HEAP32[i5 >> 2] | 0;
+  switch (i6 | 0) {
+  case 277:
+  case 286:
+  case 262:
+  case 261:
+  case 260:
+   {
+    break L7;
+   }
+  default:
+   {}
+  }
+  _statement(i4);
+  if ((i6 | 0) == 274) {
+   i1 = 8;
+   break;
+  }
+ }
+ if ((i1 | 0) == 8) {
+  i6 = HEAP32[i5 >> 2] | 0;
+ }
+ if ((i6 | 0) == 286) {
+  _close_func(i4);
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _error_expected(i4, 286);
+ }
+ return 0;
+}
+function _luaV_lessthan(i5, i4, i2) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i6 = i4 + 8 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ if ((i7 | 0) == 3) {
+  if ((HEAP32[i2 + 8 >> 2] | 0) == 3) {
+   i9 = +HEAPF64[i4 >> 3] < +HEAPF64[i2 >> 3] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ } else {
+  if ((i7 & 15 | 0) == 4 ? (HEAP32[i2 + 8 >> 2] & 15 | 0) == 4 : 0) {
+   i6 = HEAP32[i4 >> 2] | 0;
+   i4 = HEAP32[i2 >> 2] | 0;
+   i3 = i6 + 16 | 0;
+   i5 = i4 + 16 | 0;
+   i7 = _strcmp(i3, i5) | 0;
+   L8 : do {
+    if ((i7 | 0) == 0) {
+     i2 = HEAP32[i6 + 12 >> 2] | 0;
+     i4 = HEAP32[i4 + 12 >> 2] | 0;
+     while (1) {
+      i7 = _strlen(i3 | 0) | 0;
+      i6 = (i7 | 0) == (i2 | 0);
+      if ((i7 | 0) == (i4 | 0)) {
+       break;
+      }
+      if (i6) {
+       i7 = -1;
+       break L8;
+      }
+      i6 = i7 + 1 | 0;
+      i3 = i3 + i6 | 0;
+      i5 = i5 + i6 | 0;
+      i7 = _strcmp(i3, i5) | 0;
+      if ((i7 | 0) == 0) {
+       i2 = i2 - i6 | 0;
+       i4 = i4 - i6 | 0;
+      } else {
+       break L8;
+      }
+     }
+     i7 = i6 & 1 ^ 1;
+    }
+   } while (0);
+   i9 = i7 >>> 31;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ }
+ i8 = i5 + 8 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ i9 = _luaT_gettmbyobj(i5, i4, 13) | 0;
+ if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+  i9 = _luaT_gettmbyobj(i5, i2, 13) | 0;
+  if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+   _luaG_ordererror(i5, i4, i2);
+  } else {
+   i3 = i9;
+  }
+ } else {
+  i3 = i9;
+ }
+ i10 = i5 + 28 | 0;
+ i9 = i7 - (HEAP32[i10 >> 2] | 0) | 0;
+ i11 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i11 + 16;
+ i13 = i3;
+ i12 = HEAP32[i13 + 4 >> 2] | 0;
+ i7 = i11;
+ HEAP32[i7 >> 2] = HEAP32[i13 >> 2];
+ HEAP32[i7 + 4 >> 2] = i12;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ i3 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i3 + 16;
+ i11 = i4;
+ i7 = HEAP32[i11 + 4 >> 2] | 0;
+ i4 = i3;
+ HEAP32[i4 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i4 + 4 >> 2] = i7;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i6 >> 2];
+ i3 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i3 + 16;
+ i4 = i2;
+ i7 = HEAP32[i4 + 4 >> 2] | 0;
+ i6 = i3;
+ HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i6 + 4 >> 2] = i7;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i2 + 8 >> 2];
+ _luaD_call(i5, (HEAP32[i8 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i5 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i2 = HEAP32[i10 >> 2] | 0;
+ i3 = HEAP32[i8 >> 2] | 0;
+ i5 = i3 + -16 | 0;
+ HEAP32[i8 >> 2] = i5;
+ i6 = HEAP32[i5 + 4 >> 2] | 0;
+ i7 = i2 + i9 | 0;
+ HEAP32[i7 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i7 + 4 >> 2] = i6;
+ HEAP32[i2 + (i9 + 8) >> 2] = HEAP32[i3 + -8 >> 2];
+ i2 = HEAP32[i8 >> 2] | 0;
+ i3 = HEAP32[i2 + 8 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  if ((i3 | 0) == 1) {
+   i2 = (HEAP32[i2 >> 2] | 0) != 0;
+  } else {
+   i2 = 1;
+  }
+ } else {
+  i2 = 0;
+ }
+ i13 = i2 & 1;
+ STACKTOP = i1;
+ return i13 | 0;
+}
+function _discharge2reg(i4, i3, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d11 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i9 = i2 + 16 | 0;
+ i8 = i2;
+ _luaK_dischargevars(i4, i3);
+ i10 = HEAP32[i3 >> 2] | 0;
+ L1 : do {
+  switch (i10 | 0) {
+  case 5:
+   {
+    d11 = +HEAPF64[i3 + 8 >> 3];
+    HEAPF64[i9 >> 3] = d11;
+    i5 = HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 52 >> 2] | 0;
+    HEAPF64[i8 >> 3] = d11;
+    HEAP32[i8 + 8 >> 2] = 3;
+    if (d11 != d11 | 0.0 != 0.0 | d11 == 0.0) {
+     i10 = i5 + 8 | 0;
+     i7 = HEAP32[i10 >> 2] | 0;
+     HEAP32[i10 >> 2] = i7 + 16;
+     i5 = _luaS_newlstr(i5, i9, 8) | 0;
+     HEAP32[i7 >> 2] = i5;
+     HEAP32[i7 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 0 | 64;
+     i5 = _addk(i4, (HEAP32[i10 >> 2] | 0) + -16 | 0, i8) | 0;
+     HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -16;
+    } else {
+     i5 = _addk(i4, i8, i8) | 0;
+    }
+    i6 = i1 << 6;
+    if ((i5 | 0) < 262144) {
+     _luaK_code(i4, i6 | i5 << 14 | 1) | 0;
+     break L1;
+    } else {
+     _luaK_code(i4, i6 | 2) | 0;
+     _luaK_code(i4, i5 << 6 | 39) | 0;
+     break L1;
+    }
+   }
+  case 2:
+  case 3:
+   {
+    _luaK_code(i4, i1 << 6 | ((i10 | 0) == 2) << 23 | 3) | 0;
+    break;
+   }
+  case 4:
+   {
+    i6 = HEAP32[i3 + 8 >> 2] | 0;
+    i5 = i1 << 6;
+    if ((i6 | 0) < 262144) {
+     _luaK_code(i4, i5 | i6 << 14 | 1) | 0;
+     break L1;
+    } else {
+     _luaK_code(i4, i5 | 2) | 0;
+     _luaK_code(i4, i6 << 6 | 39) | 0;
+     break L1;
+    }
+   }
+  case 1:
+   {
+    i9 = i1 + 1 | 0;
+    i8 = HEAP32[i4 + 20 >> 2] | 0;
+    do {
+     if ((i8 | 0) > (HEAP32[i4 + 24 >> 2] | 0) ? (i5 = (HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0) + (i8 + -1 << 2) | 0, i6 = HEAP32[i5 >> 2] | 0, (i6 & 63 | 0) == 4) : 0) {
+      i10 = i6 >>> 6 & 255;
+      i8 = i10 + (i6 >>> 23) | 0;
+      if (!((i10 | 0) <= (i1 | 0) ? (i8 + 1 | 0) >= (i1 | 0) : 0)) {
+       i7 = 6;
+      }
+      if ((i7 | 0) == 6 ? (i10 | 0) < (i1 | 0) | (i10 | 0) > (i9 | 0) : 0) {
+       break;
+      }
+      i4 = (i10 | 0) < (i1 | 0) ? i10 : i1;
+      HEAP32[i5 >> 2] = i4 << 6 & 16320 | i6 & 8372287 | ((i8 | 0) > (i1 | 0) ? i8 : i1) - i4 << 23;
+      break L1;
+     }
+    } while (0);
+    _luaK_code(i4, i1 << 6 | 4) | 0;
+    break;
+   }
+  case 6:
+   {
+    i5 = HEAP32[i3 + 8 >> 2] | 0;
+    if ((i5 | 0) != (i1 | 0)) {
+     _luaK_code(i4, i5 << 23 | i1 << 6) | 0;
+    }
+    break;
+   }
+  case 11:
+   {
+    i10 = (HEAP32[(HEAP32[i4 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i3 + 8 >> 2] << 2) | 0;
+    HEAP32[i10 >> 2] = HEAP32[i10 >> 2] & -16321 | i1 << 6 & 16320;
+    break;
+   }
+  default:
+   {
+    STACKTOP = i2;
+    return;
+   }
+  }
+ } while (0);
+ HEAP32[i3 + 8 >> 2] = i1;
+ HEAP32[i3 >> 2] = 6;
+ STACKTOP = i2;
+ return;
+}
+function _unroll(i3, i4) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0;
+ i9 = STACKTOP;
+ i11 = i3 + 16 | 0;
+ i13 = HEAP32[i11 >> 2] | 0;
+ i5 = i3 + 72 | 0;
+ if ((i13 | 0) == (i5 | 0)) {
+  STACKTOP = i9;
+  return;
+ }
+ i6 = i3 + 8 | 0;
+ i10 = i3 + 40 | 0;
+ i7 = i3 + 20 | 0;
+ i8 = i3 + 28 | 0;
+ i4 = i3 + 68 | 0;
+ do {
+  i12 = i13 + 18 | 0;
+  i14 = HEAP8[i12] | 0;
+  if ((i14 & 1) == 0) {
+   i14 = i14 & 255;
+   if ((i14 & 16 | 0) != 0) {
+    HEAP8[i12] = i14 & 239;
+    HEAP32[i4 >> 2] = HEAP32[i13 + 32 >> 2];
+   }
+   if ((HEAP16[i13 + 16 >> 1] | 0) == -1 ? (i2 = (HEAP32[i11 >> 2] | 0) + 4 | 0, i1 = HEAP32[i6 >> 2] | 0, (HEAP32[i2 >> 2] | 0) >>> 0 < i1 >>> 0) : 0) {
+    HEAP32[i2 >> 2] = i1;
+   }
+   i14 = HEAP8[i12] | 0;
+   if ((i14 & 32) == 0) {
+    HEAP8[i13 + 37 | 0] = 1;
+   }
+   HEAP8[i12] = i14 & 199 | 8;
+   i14 = FUNCTION_TABLE_ii[HEAP32[i13 + 28 >> 2] & 255](i3) | 0;
+   i14 = (HEAP32[i6 >> 2] | 0) + (0 - i14 << 4) | 0;
+   i13 = HEAP32[i11 >> 2] | 0;
+   i12 = HEAPU8[i10] | 0;
+   if ((i12 & 6 | 0) == 0) {
+    i15 = i13 + 8 | 0;
+   } else {
+    if ((i12 & 2 | 0) != 0) {
+     i14 = i14 - (HEAP32[i8 >> 2] | 0) | 0;
+     _luaD_hook(i3, 1, -1);
+     i14 = (HEAP32[i8 >> 2] | 0) + i14 | 0;
+    }
+    i15 = i13 + 8 | 0;
+    HEAP32[i7 >> 2] = HEAP32[(HEAP32[i15 >> 2] | 0) + 28 >> 2];
+   }
+   i12 = HEAP32[i13 >> 2] | 0;
+   i13 = HEAP16[i13 + 16 >> 1] | 0;
+   HEAP32[i11 >> 2] = HEAP32[i15 >> 2];
+   L25 : do {
+    if (!(i13 << 16 >> 16 == 0)) {
+     i15 = i13 << 16 >> 16;
+     if (i14 >>> 0 < (HEAP32[i6 >> 2] | 0) >>> 0) {
+      i13 = i14;
+      i14 = i15;
+      i15 = i12;
+      while (1) {
+       i12 = i15 + 16 | 0;
+       i18 = i13;
+       i17 = HEAP32[i18 + 4 >> 2] | 0;
+       i16 = i15;
+       HEAP32[i16 >> 2] = HEAP32[i18 >> 2];
+       HEAP32[i16 + 4 >> 2] = i17;
+       HEAP32[i15 + 8 >> 2] = HEAP32[i13 + 8 >> 2];
+       i14 = i14 + -1 | 0;
+       i13 = i13 + 16 | 0;
+       if ((i14 | 0) == 0) {
+        break L25;
+       }
+       if (i13 >>> 0 < (HEAP32[i6 >> 2] | 0) >>> 0) {
+        i15 = i12;
+       } else {
+        i13 = i14;
+        break;
+       }
+      }
+     } else {
+      i13 = i15;
+     }
+     if ((i13 | 0) > 0) {
+      i14 = i13;
+      i15 = i12;
+      while (1) {
+       i14 = i14 + -1 | 0;
+       HEAP32[i15 + 8 >> 2] = 0;
+       if ((i14 | 0) <= 0) {
+        break;
+       } else {
+        i15 = i15 + 16 | 0;
+       }
+      }
+      i12 = i12 + (i13 << 4) | 0;
+     }
+    }
+   } while (0);
+   HEAP32[i6 >> 2] = i12;
+  } else {
+   _luaV_finishOp(i3);
+   _luaV_execute(i3);
+  }
+  i13 = HEAP32[i11 >> 2] | 0;
+ } while ((i13 | 0) != (i5 | 0));
+ STACKTOP = i9;
+ return;
+}
+function _traverseephemeron(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i3 = STACKTOP;
+ i11 = i2 + 16 | 0;
+ i9 = HEAP32[i11 >> 2] | 0;
+ i5 = i9 + (1 << (HEAPU8[i2 + 7 | 0] | 0) << 5) | 0;
+ i10 = i2 + 28 | 0;
+ i13 = HEAP32[i10 >> 2] | 0;
+ if ((i13 | 0) > 0) {
+  i9 = i2 + 12 | 0;
+  i12 = 0;
+  i8 = 0;
+  do {
+   i14 = HEAP32[i9 >> 2] | 0;
+   if ((HEAP32[i14 + (i12 << 4) + 8 >> 2] & 64 | 0) != 0 ? (i7 = HEAP32[i14 + (i12 << 4) >> 2] | 0, !((HEAP8[i7 + 5 | 0] & 3) == 0)) : 0) {
+    _reallymarkobject(i1, i7);
+    i13 = HEAP32[i10 >> 2] | 0;
+    i8 = 1;
+   }
+   i12 = i12 + 1 | 0;
+  } while ((i12 | 0) < (i13 | 0));
+  i9 = HEAP32[i11 >> 2] | 0;
+ } else {
+  i8 = 0;
+ }
+ if (i9 >>> 0 < i5 >>> 0) {
+  i7 = 0;
+  i10 = 0;
+  do {
+   i11 = i9 + 8 | 0;
+   i12 = HEAP32[i11 >> 2] | 0;
+   i14 = i9 + 24 | 0;
+   i13 = HEAP32[i14 >> 2] | 0;
+   i15 = (i13 & 64 | 0) == 0;
+   L14 : do {
+    if ((i12 | 0) == 0) {
+     if (!i15 ? !((HEAP8[(HEAP32[i9 + 16 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) {
+      HEAP32[i14 >> 2] = 11;
+     }
+    } else {
+     do {
+      if (i15) {
+       i6 = i12;
+       i4 = 18;
+      } else {
+       i14 = HEAP32[i9 + 16 >> 2] | 0;
+       if ((i13 & 15 | 0) == 4) {
+        if ((i14 | 0) == 0) {
+         i6 = i12;
+         i4 = 18;
+         break;
+        }
+        if ((HEAP8[i14 + 5 | 0] & 3) == 0) {
+         i6 = i12;
+         i4 = 18;
+         break;
+        }
+        _reallymarkobject(i1, i14);
+        i6 = HEAP32[i11 >> 2] | 0;
+        i4 = 18;
+        break;
+       }
+       i11 = (i12 & 64 | 0) == 0;
+       if ((HEAP8[i14 + 5 | 0] & 3) == 0) {
+        if (i11) {
+         break L14;
+        } else {
+         break;
+        }
+       }
+       if (i11) {
+        i7 = 1;
+        break L14;
+       }
+       i7 = 1;
+       i10 = (HEAP8[(HEAP32[i9 >> 2] | 0) + 5 | 0] & 3) == 0 ? i10 : 1;
+       break L14;
+      }
+     } while (0);
+     if ((i4 | 0) == 18 ? (i4 = 0, (i6 & 64 | 0) == 0) : 0) {
+      break;
+     }
+     i11 = HEAP32[i9 >> 2] | 0;
+     if (!((HEAP8[i11 + 5 | 0] & 3) == 0)) {
+      _reallymarkobject(i1, i11);
+      i8 = 1;
+     }
+    }
+   } while (0);
+   i9 = i9 + 32 | 0;
+  } while (i9 >>> 0 < i5 >>> 0);
+  if ((i10 | 0) != 0) {
+   i15 = i1 + 96 | 0;
+   HEAP32[i2 + 24 >> 2] = HEAP32[i15 >> 2];
+   HEAP32[i15 >> 2] = i2;
+   i15 = i8;
+   STACKTOP = i3;
+   return i15 | 0;
+  }
+  if ((i7 | 0) != 0) {
+   i15 = i1 + 100 | 0;
+   HEAP32[i2 + 24 >> 2] = HEAP32[i15 >> 2];
+   HEAP32[i15 >> 2] = i2;
+   i15 = i8;
+   STACKTOP = i3;
+   return i15 | 0;
+  }
+ }
+ i15 = i1 + 88 | 0;
+ HEAP32[i2 + 24 >> 2] = HEAP32[i15 >> 2];
+ HEAP32[i15 >> 2] = i2;
+ i15 = i8;
+ STACKTOP = i3;
+ return i15 | 0;
+}
+function _luaV_gettable(i2, i7, i5, i1) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i6;
+ i8 = i2 + 12 | 0;
+ i3 = i7;
+ i10 = HEAP32[i7 + 8 >> 2] | 0;
+ i9 = 0;
+ while (1) {
+  i7 = i3 + 8 | 0;
+  if ((i10 | 0) != 69) {
+   i12 = _luaT_gettmbyobj(i2, i3, 0) | 0;
+   i10 = HEAP32[i12 + 8 >> 2] | 0;
+   if ((i10 | 0) == 0) {
+    i8 = 11;
+    break;
+   }
+  } else {
+   i12 = HEAP32[i3 >> 2] | 0;
+   i11 = _luaH_get(i12, i5) | 0;
+   i10 = i11 + 8 | 0;
+   if ((HEAP32[i10 >> 2] | 0) != 0) {
+    i8 = 9;
+    break;
+   }
+   i12 = HEAP32[i12 + 8 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    i8 = 9;
+    break;
+   }
+   if (!((HEAP8[i12 + 6 | 0] & 1) == 0)) {
+    i8 = 9;
+    break;
+   }
+   i12 = _luaT_gettm(i12, 0, HEAP32[(HEAP32[i8 >> 2] | 0) + 184 >> 2] | 0) | 0;
+   if ((i12 | 0) == 0) {
+    i8 = 9;
+    break;
+   }
+   i10 = HEAP32[i12 + 8 >> 2] | 0;
+  }
+  i9 = i9 + 1 | 0;
+  if ((i10 & 15 | 0) == 6) {
+   i8 = 13;
+   break;
+  }
+  if ((i9 | 0) < 100) {
+   i3 = i12;
+  } else {
+   i8 = 14;
+   break;
+  }
+ }
+ if ((i8 | 0) == 9) {
+  i9 = i11;
+  i11 = HEAP32[i9 + 4 >> 2] | 0;
+  i12 = i1;
+  HEAP32[i12 >> 2] = HEAP32[i9 >> 2];
+  HEAP32[i12 + 4 >> 2] = i11;
+  HEAP32[i1 + 8 >> 2] = HEAP32[i10 >> 2];
+  STACKTOP = i6;
+  return;
+ } else if ((i8 | 0) == 11) {
+  _luaG_typeerror(i2, i3, 8944);
+ } else if ((i8 | 0) == 13) {
+  i10 = i2 + 28 | 0;
+  i11 = i1 - (HEAP32[i10 >> 2] | 0) | 0;
+  i8 = i2 + 8 | 0;
+  i9 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i9 + 16;
+  i13 = i12;
+  i1 = HEAP32[i13 + 4 >> 2] | 0;
+  i4 = i9;
+  HEAP32[i4 >> 2] = HEAP32[i13 >> 2];
+  HEAP32[i4 + 4 >> 2] = i1;
+  HEAP32[i9 + 8 >> 2] = HEAP32[i12 + 8 >> 2];
+  i12 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i12 + 16;
+  i9 = HEAP32[i3 + 4 >> 2] | 0;
+  i4 = i12;
+  HEAP32[i4 >> 2] = HEAP32[i3 >> 2];
+  HEAP32[i4 + 4 >> 2] = i9;
+  HEAP32[i12 + 8 >> 2] = HEAP32[i7 >> 2];
+  i12 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i12 + 16;
+  i4 = i5;
+  i9 = HEAP32[i4 + 4 >> 2] | 0;
+  i7 = i12;
+  HEAP32[i7 >> 2] = HEAP32[i4 >> 2];
+  HEAP32[i7 + 4 >> 2] = i9;
+  HEAP32[i12 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+  _luaD_call(i2, (HEAP32[i8 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i2 + 16 >> 2] | 0) + 18 | 0] & 1);
+  i12 = HEAP32[i10 >> 2] | 0;
+  i10 = HEAP32[i8 >> 2] | 0;
+  i7 = i10 + -16 | 0;
+  HEAP32[i8 >> 2] = i7;
+  i8 = HEAP32[i7 + 4 >> 2] | 0;
+  i9 = i12 + i11 | 0;
+  HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+  HEAP32[i9 + 4 >> 2] = i8;
+  HEAP32[i12 + (i11 + 8) >> 2] = HEAP32[i10 + -8 >> 2];
+  STACKTOP = i6;
+  return;
+ } else if ((i8 | 0) == 14) {
+  _luaG_runerror(i2, 8952, i4);
+ }
+}
+function _db_getinfo(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i3 = i2;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i4 = _lua_tothread(i1, 1) | 0;
+  i7 = 1;
+ } else {
+  i4 = i1;
+  i7 = 0;
+ }
+ i5 = i7 | 2;
+ i6 = _luaL_optlstring(i1, i5, 11784, 0) | 0;
+ i7 = i7 + 1 | 0;
+ do {
+  if ((_lua_isnumber(i1, i7) | 0) != 0) {
+   if ((_lua_getstack(i4, _lua_tointegerx(i1, i7, 0) | 0, i3) | 0) == 0) {
+    _lua_pushnil(i1);
+    i7 = 1;
+    STACKTOP = i2;
+    return i7 | 0;
+   }
+  } else {
+   if ((_lua_type(i1, i7) | 0) == 6) {
+    HEAP32[i3 >> 2] = i6;
+    _lua_pushfstring(i1, 11792, i3) | 0;
+    i6 = _lua_tolstring(i1, -1, 0) | 0;
+    _lua_pushvalue(i1, i7);
+    _lua_xmove(i1, i4, 1);
+    break;
+   }
+   i7 = _luaL_argerror(i1, i7, 11800) | 0;
+   STACKTOP = i2;
+   return i7 | 0;
+  }
+ } while (0);
+ if ((_lua_getinfo(i4, i6, i3) | 0) == 0) {
+  i7 = _luaL_argerror(i1, i5, 11832) | 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ _lua_createtable(i1, 0, 2);
+ if ((_strchr(i6, 83) | 0) != 0) {
+  _lua_pushstring(i1, HEAP32[i3 + 16 >> 2] | 0) | 0;
+  _lua_setfield(i1, -2, 11848);
+  _lua_pushstring(i1, i3 + 36 | 0) | 0;
+  _lua_setfield(i1, -2, 11856);
+  _lua_pushinteger(i1, HEAP32[i3 + 24 >> 2] | 0);
+  _lua_setfield(i1, -2, 11872);
+  _lua_pushinteger(i1, HEAP32[i3 + 28 >> 2] | 0);
+  _lua_setfield(i1, -2, 11888);
+  _lua_pushstring(i1, HEAP32[i3 + 12 >> 2] | 0) | 0;
+  _lua_setfield(i1, -2, 11904);
+ }
+ if ((_strchr(i6, 108) | 0) != 0) {
+  _lua_pushinteger(i1, HEAP32[i3 + 20 >> 2] | 0);
+  _lua_setfield(i1, -2, 11912);
+ }
+ if ((_strchr(i6, 117) | 0) != 0) {
+  _lua_pushinteger(i1, HEAPU8[i3 + 32 | 0] | 0);
+  _lua_setfield(i1, -2, 11928);
+  _lua_pushinteger(i1, HEAPU8[i3 + 33 | 0] | 0);
+  _lua_setfield(i1, -2, 11936);
+  _lua_pushboolean(i1, HEAP8[i3 + 34 | 0] | 0);
+  _lua_setfield(i1, -2, 11944);
+ }
+ if ((_strchr(i6, 110) | 0) != 0) {
+  _lua_pushstring(i1, HEAP32[i3 + 4 >> 2] | 0) | 0;
+  _lua_setfield(i1, -2, 11960);
+  _lua_pushstring(i1, HEAP32[i3 + 8 >> 2] | 0) | 0;
+  _lua_setfield(i1, -2, 11968);
+ }
+ if ((_strchr(i6, 116) | 0) != 0) {
+  _lua_pushboolean(i1, HEAP8[i3 + 35 | 0] | 0);
+  _lua_setfield(i1, -2, 11984);
+ }
+ if ((_strchr(i6, 76) | 0) != 0) {
+  if ((i4 | 0) == (i1 | 0)) {
+   _lua_pushvalue(i1, -2);
+   _lua_remove(i1, -3);
+  } else {
+   _lua_xmove(i4, i1, 1);
+  }
+  _lua_setfield(i1, -2, 12e3);
+ }
+ if ((_strchr(i6, 102) | 0) == 0) {
+  i7 = 1;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ if ((i4 | 0) == (i1 | 0)) {
+  _lua_pushvalue(i1, -2);
+  _lua_remove(i1, -3);
+ } else {
+  _lua_xmove(i4, i1, 1);
+ }
+ _lua_setfield(i1, -2, 12016);
+ i7 = 1;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _luaL_traceback(i4, i1, i9, i7) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i9 = i9 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 208 | 0;
+ i6 = i3;
+ i5 = i3 + 100 | 0;
+ i2 = _lua_gettop(i4) | 0;
+ i8 = 1;
+ i10 = 1;
+ while (1) {
+  if ((_lua_getstack(i1, i8, i6) | 0) == 0) {
+   break;
+  } else {
+   i10 = i8;
+   i8 = i8 << 1;
+  }
+ }
+ if ((i10 | 0) < (i8 | 0)) {
+  while (1) {
+   i11 = (i8 + i10 | 0) / 2 | 0;
+   i12 = (_lua_getstack(i1, i11, i6) | 0) == 0;
+   i8 = i12 ? i11 : i8;
+   i10 = i12 ? i10 : i11 + 1 | 0;
+   if ((i10 | 0) >= (i8 | 0)) {
+    i10 = i8;
+    break;
+   }
+  }
+ } else {
+  i10 = i8;
+ }
+ i8 = (i10 + -1 | 0) > 22 ? 12 : 0;
+ if ((i9 | 0) != 0) {
+  HEAP32[i6 >> 2] = i9;
+  _lua_pushfstring(i4, 944, i6) | 0;
+ }
+ _lua_pushlstring(i4, 952, 16) | 0;
+ if ((_lua_getstack(i1, i7, i5) | 0) == 0) {
+  i17 = _lua_gettop(i4) | 0;
+  i17 = i17 - i2 | 0;
+  _lua_concat(i4, i17);
+  STACKTOP = i3;
+  return;
+ }
+ i10 = i10 + -11 | 0;
+ i13 = i5 + 36 | 0;
+ i9 = i5 + 20 | 0;
+ i16 = i5 + 8 | 0;
+ i12 = i5 + 12 | 0;
+ i15 = i5 + 24 | 0;
+ i14 = i5 + 35 | 0;
+ i11 = i5 + 4 | 0;
+ do {
+  i7 = i7 + 1 | 0;
+  if ((i7 | 0) == (i8 | 0)) {
+   _lua_pushlstring(i4, 976, 5) | 0;
+   i7 = i10;
+  } else {
+   _lua_getinfo(i1, 984, i5) | 0;
+   HEAP32[i6 >> 2] = i13;
+   _lua_pushfstring(i4, 992, i6) | 0;
+   i17 = HEAP32[i9 >> 2] | 0;
+   if ((i17 | 0) > 0) {
+    HEAP32[i6 >> 2] = i17;
+    _lua_pushfstring(i4, 1e3, i6) | 0;
+   }
+   _lua_pushlstring(i4, 1008, 4) | 0;
+   do {
+    if ((HEAP8[HEAP32[i16 >> 2] | 0] | 0) == 0) {
+     i17 = HEAP8[HEAP32[i12 >> 2] | 0] | 0;
+     if (i17 << 24 >> 24 == 109) {
+      _lua_pushlstring(i4, 1800, 10) | 0;
+      break;
+     } else if (i17 << 24 >> 24 == 67) {
+      if ((_pushglobalfuncname(i4, i5) | 0) == 0) {
+       _lua_pushlstring(i4, 1112, 1) | 0;
+       break;
+      } else {
+       HEAP32[i6 >> 2] = _lua_tolstring(i4, -1, 0) | 0;
+       _lua_pushfstring(i4, 1784, i6) | 0;
+       _lua_remove(i4, -2);
+       break;
+      }
+     } else {
+      i17 = HEAP32[i15 >> 2] | 0;
+      HEAP32[i6 >> 2] = i13;
+      HEAP32[i6 + 4 >> 2] = i17;
+      _lua_pushfstring(i4, 1816, i6) | 0;
+      break;
+     }
+    } else {
+     HEAP32[i6 >> 2] = HEAP32[i11 >> 2];
+     _lua_pushfstring(i4, 1784, i6) | 0;
+    }
+   } while (0);
+   if ((HEAP8[i14] | 0) != 0) {
+    _lua_pushlstring(i4, 1016, 20) | 0;
+   }
+   _lua_concat(i4, (_lua_gettop(i4) | 0) - i2 | 0);
+  }
+ } while ((_lua_getstack(i1, i7, i5) | 0) != 0);
+ i17 = _lua_gettop(i4) | 0;
+ i17 = i17 - i2 | 0;
+ _lua_concat(i4, i17);
+ STACKTOP = i3;
+ return;
+}
+function _luaK_exp2RK(i3, i1) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d11 = 0.0, i12 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i7 = i2 + 16 | 0;
+ i6 = i2;
+ i4 = i1 + 16 | 0;
+ i5 = i1 + 20 | 0;
+ i10 = (HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0);
+ _luaK_dischargevars(i3, i1);
+ do {
+  if (!i10) {
+   if ((HEAP32[i1 >> 2] | 0) == 6) {
+    i10 = HEAP32[i1 + 8 >> 2] | 0;
+    if ((HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0)) {
+     break;
+    }
+    if ((i10 | 0) >= (HEAPU8[i3 + 46 | 0] | 0 | 0)) {
+     _exp2reg(i3, i1, i10);
+     break;
+    }
+   }
+   _luaK_exp2nextreg(i3, i1);
+  }
+ } while (0);
+ i10 = HEAP32[i1 >> 2] | 0;
+ switch (i10 | 0) {
+ case 4:
+  {
+   i8 = HEAP32[i1 + 8 >> 2] | 0;
+   i9 = 18;
+   break;
+  }
+ case 1:
+ case 3:
+ case 2:
+  {
+   if ((HEAP32[i3 + 32 >> 2] | 0) < 256) {
+    if ((i10 | 0) == 1) {
+     HEAP32[i6 + 8 >> 2] = 0;
+     HEAP32[i7 >> 2] = HEAP32[i3 + 4 >> 2];
+     HEAP32[i7 + 8 >> 2] = 69;
+     i3 = _addk(i3, i7, i6) | 0;
+    } else {
+     HEAP32[i7 >> 2] = (i10 | 0) == 2;
+     HEAP32[i7 + 8 >> 2] = 1;
+     i3 = _addk(i3, i7, i7) | 0;
+    }
+    HEAP32[i1 + 8 >> 2] = i3;
+    HEAP32[i1 >> 2] = 4;
+    i10 = i3 | 256;
+    STACKTOP = i2;
+    return i10 | 0;
+   }
+   break;
+  }
+ case 5:
+  {
+   i9 = i1 + 8 | 0;
+   d11 = +HEAPF64[i9 >> 3];
+   HEAPF64[i7 >> 3] = d11;
+   i8 = HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 52 >> 2] | 0;
+   HEAPF64[i6 >> 3] = d11;
+   HEAP32[i6 + 8 >> 2] = 3;
+   if (d11 != d11 | 0.0 != 0.0 | d11 == 0.0) {
+    i10 = i8 + 8 | 0;
+    i12 = HEAP32[i10 >> 2] | 0;
+    HEAP32[i10 >> 2] = i12 + 16;
+    i8 = _luaS_newlstr(i8, i7, 8) | 0;
+    HEAP32[i12 >> 2] = i8;
+    HEAP32[i12 + 8 >> 2] = HEAPU8[i8 + 4 | 0] | 0 | 64;
+    i8 = _addk(i3, (HEAP32[i10 >> 2] | 0) + -16 | 0, i6) | 0;
+    HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -16;
+   } else {
+    i8 = _addk(i3, i6, i6) | 0;
+   }
+   HEAP32[i9 >> 2] = i8;
+   HEAP32[i1 >> 2] = 4;
+   i9 = 18;
+   break;
+  }
+ default:
+  {}
+ }
+ if ((i9 | 0) == 18 ? (i8 | 0) < 256 : 0) {
+  i12 = i8 | 256;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ _luaK_dischargevars(i3, i1);
+ if ((HEAP32[i1 >> 2] | 0) == 6) {
+  i7 = i1 + 8 | 0;
+  i6 = HEAP32[i7 >> 2] | 0;
+  if ((HEAP32[i4 >> 2] | 0) == (HEAP32[i5 >> 2] | 0)) {
+   i12 = i6;
+   STACKTOP = i2;
+   return i12 | 0;
+  }
+  if ((i6 | 0) >= (HEAPU8[i3 + 46 | 0] | 0 | 0)) {
+   _exp2reg(i3, i1, i6);
+   i12 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i2;
+   return i12 | 0;
+  }
+ } else {
+  i7 = i1 + 8 | 0;
+ }
+ _luaK_exp2nextreg(i3, i1);
+ i12 = HEAP32[i7 >> 2] | 0;
+ STACKTOP = i2;
+ return i12 | 0;
+}
+function _os_date(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1264 | 0;
+ i4 = i2;
+ i7 = i2 + 1048 | 0;
+ i6 = i2 + 1256 | 0;
+ i3 = i2 + 8 | 0;
+ i5 = i2 + 1056 | 0;
+ i12 = _luaL_optlstring(i1, 1, 6064, 0) | 0;
+ if ((_lua_type(i1, 2) | 0) < 1) {
+  i8 = _time(0) | 0;
+ } else {
+  i8 = ~~+_luaL_checknumber(i1, 2);
+ }
+ HEAP32[i7 >> 2] = i8;
+ if ((HEAP8[i12] | 0) == 33) {
+  i12 = i12 + 1 | 0;
+  i10 = _gmtime(i7 | 0) | 0;
+ } else {
+  i10 = _localtime(i7 | 0) | 0;
+ }
+ if ((i10 | 0) == 0) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return 1;
+ }
+ if ((_strcmp(i12, 6072) | 0) == 0) {
+  _lua_createtable(i1, 0, 9);
+  _lua_pushinteger(i1, HEAP32[i10 >> 2] | 0);
+  _lua_setfield(i1, -2, 5864);
+  _lua_pushinteger(i1, HEAP32[i10 + 4 >> 2] | 0);
+  _lua_setfield(i1, -2, 5872);
+  _lua_pushinteger(i1, HEAP32[i10 + 8 >> 2] | 0);
+  _lua_setfield(i1, -2, 5880);
+  _lua_pushinteger(i1, HEAP32[i10 + 12 >> 2] | 0);
+  _lua_setfield(i1, -2, 5888);
+  _lua_pushinteger(i1, (HEAP32[i10 + 16 >> 2] | 0) + 1 | 0);
+  _lua_setfield(i1, -2, 5896);
+  _lua_pushinteger(i1, (HEAP32[i10 + 20 >> 2] | 0) + 1900 | 0);
+  _lua_setfield(i1, -2, 5904);
+  _lua_pushinteger(i1, (HEAP32[i10 + 24 >> 2] | 0) + 1 | 0);
+  _lua_setfield(i1, -2, 6080);
+  _lua_pushinteger(i1, (HEAP32[i10 + 28 >> 2] | 0) + 1 | 0);
+  _lua_setfield(i1, -2, 6088);
+  i3 = HEAP32[i10 + 32 >> 2] | 0;
+  if ((i3 | 0) < 0) {
+   STACKTOP = i2;
+   return 1;
+  }
+  _lua_pushboolean(i1, i3);
+  _lua_setfield(i1, -2, 5912);
+  STACKTOP = i2;
+  return 1;
+ }
+ HEAP8[i6] = 37;
+ _luaL_buffinit(i1, i3);
+ i11 = i3 + 8 | 0;
+ i9 = i3 + 4 | 0;
+ i8 = i6 + 1 | 0;
+ i7 = i6 + 2 | 0;
+ while (1) {
+  i14 = HEAP8[i12] | 0;
+  if (i14 << 24 >> 24 == 0) {
+   break;
+  } else if (!(i14 << 24 >> 24 == 37)) {
+   i13 = HEAP32[i11 >> 2] | 0;
+   if (!(i13 >>> 0 < (HEAP32[i9 >> 2] | 0) >>> 0)) {
+    _luaL_prepbuffsize(i3, 1) | 0;
+    i13 = HEAP32[i11 >> 2] | 0;
+    i14 = HEAP8[i12] | 0;
+   }
+   HEAP32[i11 >> 2] = i13 + 1;
+   HEAP8[(HEAP32[i3 >> 2] | 0) + i13 | 0] = i14;
+   i12 = i12 + 1 | 0;
+   continue;
+  }
+  i13 = i12 + 1 | 0;
+  i12 = i12 + 2 | 0;
+  i14 = HEAP8[i13] | 0;
+  if (!(i14 << 24 >> 24 == 0) ? (_memchr(6096, i14 << 24 >> 24, 23) | 0) != 0 : 0) {
+   HEAP8[i8] = i14;
+   HEAP8[i7] = 0;
+  } else {
+   HEAP32[i4 >> 2] = i13;
+   _luaL_argerror(i1, 1, _lua_pushfstring(i1, 6120, i4) | 0) | 0;
+   i12 = i13;
+  }
+  _luaL_addlstring(i3, i5, _strftime(i5 | 0, 200, i6 | 0, i10 | 0) | 0);
+ }
+ _luaL_pushresult(i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaV_finishOp(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ i8 = HEAP32[i3 + 16 >> 2] | 0;
+ i7 = i8 + 24 | 0;
+ i4 = HEAP32[i7 >> 2] | 0;
+ i5 = i8 + 28 | 0;
+ i2 = HEAP32[(HEAP32[i5 >> 2] | 0) + -4 >> 2] | 0;
+ i6 = i2 & 63;
+ switch (i6 | 0) {
+ case 34:
+  {
+   HEAP32[i3 + 8 >> 2] = HEAP32[i8 + 4 >> 2];
+   STACKTOP = i1;
+   return;
+  }
+ case 24:
+ case 25:
+ case 26:
+  {
+   i7 = i3 + 8 | 0;
+   i8 = HEAP32[i7 >> 2] | 0;
+   i9 = HEAP32[i8 + -8 >> 2] | 0;
+   if ((i9 | 0) != 0) {
+    if ((i9 | 0) == 1) {
+     i9 = (HEAP32[i8 + -16 >> 2] | 0) == 0;
+    } else {
+     i9 = 0;
+    }
+   } else {
+    i9 = 1;
+   }
+   i9 = i9 & 1;
+   i10 = i9 ^ 1;
+   HEAP32[i7 >> 2] = i8 + -16;
+   if ((i6 | 0) == 26) {
+    i8 = (HEAP32[(_luaT_gettmbyobj(i3, i4 + (i2 >>> 23 << 4) | 0, 14) | 0) + 8 >> 2] | 0) == 0;
+    i10 = i8 ? i9 : i10;
+   }
+   if ((i10 | 0) == (i2 >>> 6 & 255 | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 4;
+   STACKTOP = i1;
+   return;
+  }
+ case 22:
+  {
+   i5 = i3 + 8 | 0;
+   i10 = HEAP32[i5 >> 2] | 0;
+   i6 = i10 + -32 | 0;
+   i4 = i6 - (i4 + (i2 >>> 23 << 4)) | 0;
+   i12 = i10 + -16 | 0;
+   i11 = HEAP32[i12 + 4 >> 2] | 0;
+   i9 = i10 + -48 | 0;
+   HEAP32[i9 >> 2] = HEAP32[i12 >> 2];
+   HEAP32[i9 + 4 >> 2] = i11;
+   HEAP32[i10 + -40 >> 2] = HEAP32[i10 + -8 >> 2];
+   if ((i4 | 0) > 16) {
+    HEAP32[i5 >> 2] = i6;
+    _luaV_concat(i3, i4 >> 4);
+   }
+   i10 = HEAP32[i5 >> 2] | 0;
+   i11 = HEAP32[i7 >> 2] | 0;
+   i12 = i2 >>> 6 & 255;
+   i6 = i10 + -16 | 0;
+   i7 = HEAP32[i6 + 4 >> 2] | 0;
+   i9 = i11 + (i12 << 4) | 0;
+   HEAP32[i9 >> 2] = HEAP32[i6 >> 2];
+   HEAP32[i9 + 4 >> 2] = i7;
+   HEAP32[i11 + (i12 << 4) + 8 >> 2] = HEAP32[i10 + -8 >> 2];
+   HEAP32[i5 >> 2] = HEAP32[i8 + 4 >> 2];
+   STACKTOP = i1;
+   return;
+  }
+ case 12:
+ case 7:
+ case 6:
+ case 21:
+ case 19:
+ case 18:
+ case 17:
+ case 16:
+ case 15:
+ case 14:
+ case 13:
+  {
+   i12 = i3 + 8 | 0;
+   i11 = HEAP32[i12 >> 2] | 0;
+   i8 = i11 + -16 | 0;
+   HEAP32[i12 >> 2] = i8;
+   i12 = i2 >>> 6 & 255;
+   i9 = HEAP32[i8 + 4 >> 2] | 0;
+   i10 = i4 + (i12 << 4) | 0;
+   HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+   HEAP32[i10 + 4 >> 2] = i9;
+   HEAP32[i4 + (i12 << 4) + 8 >> 2] = HEAP32[i11 + -8 >> 2];
+   STACKTOP = i1;
+   return;
+  }
+ case 29:
+  {
+   if ((i2 & 8372224 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[i3 + 8 >> 2] = HEAP32[i8 + 4 >> 2];
+   STACKTOP = i1;
+   return;
+  }
+ default:
+  {
+   STACKTOP = i1;
+   return;
+  }
+ }
+}
+function _auxsort(i2, i4, i5) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((i4 | 0) >= (i5 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  _lua_rawgeti(i2, 1, i4);
+  _lua_rawgeti(i2, 1, i5);
+  if ((_sort_comp(i2, -1, -2) | 0) == 0) {
+   _lua_settop(i2, -3);
+  } else {
+   _lua_rawseti(i2, 1, i4);
+   _lua_rawseti(i2, 1, i5);
+  }
+  i6 = i5 - i4 | 0;
+  if ((i6 | 0) == 1) {
+   i2 = 24;
+   break;
+  }
+  i7 = (i5 + i4 | 0) / 2 | 0;
+  _lua_rawgeti(i2, 1, i7);
+  _lua_rawgeti(i2, 1, i4);
+  do {
+   if ((_sort_comp(i2, -2, -1) | 0) == 0) {
+    _lua_settop(i2, -2);
+    _lua_rawgeti(i2, 1, i5);
+    if ((_sort_comp(i2, -1, -2) | 0) == 0) {
+     _lua_settop(i2, -3);
+     break;
+    } else {
+     _lua_rawseti(i2, 1, i7);
+     _lua_rawseti(i2, 1, i5);
+     break;
+    }
+   } else {
+    _lua_rawseti(i2, 1, i7);
+    _lua_rawseti(i2, 1, i4);
+   }
+  } while (0);
+  if ((i6 | 0) == 2) {
+   i2 = 24;
+   break;
+  }
+  _lua_rawgeti(i2, 1, i7);
+  _lua_pushvalue(i2, -1);
+  i6 = i5 + -1 | 0;
+  _lua_rawgeti(i2, 1, i6);
+  _lua_rawseti(i2, 1, i7);
+  _lua_rawseti(i2, 1, i6);
+  i7 = i4;
+  i9 = i6;
+  while (1) {
+   i8 = i7 + 1 | 0;
+   _lua_rawgeti(i2, 1, i8);
+   if ((_sort_comp(i2, -1, -2) | 0) != 0) {
+    i7 = i8;
+    while (1) {
+     if ((i7 | 0) >= (i5 | 0)) {
+      _luaL_error(i2, 8216, i3) | 0;
+     }
+     _lua_settop(i2, -2);
+     i8 = i7 + 1 | 0;
+     _lua_rawgeti(i2, 1, i8);
+     if ((_sort_comp(i2, -1, -2) | 0) == 0) {
+      break;
+     } else {
+      i7 = i8;
+     }
+    }
+   }
+   i10 = i9 + -1 | 0;
+   _lua_rawgeti(i2, 1, i10);
+   if ((_sort_comp(i2, -3, -1) | 0) != 0) {
+    i9 = i10;
+    while (1) {
+     if ((i9 | 0) <= (i4 | 0)) {
+      _luaL_error(i2, 8216, i3) | 0;
+     }
+     _lua_settop(i2, -2);
+     i10 = i9 + -1 | 0;
+     _lua_rawgeti(i2, 1, i10);
+     if ((_sort_comp(i2, -3, -1) | 0) == 0) {
+      break;
+     } else {
+      i9 = i10;
+     }
+    }
+   }
+   if ((i9 | 0) <= (i8 | 0)) {
+    break;
+   }
+   _lua_rawseti(i2, 1, i8);
+   _lua_rawseti(i2, 1, i10);
+   i7 = i8;
+   i9 = i10;
+  }
+  _lua_settop(i2, -4);
+  _lua_rawgeti(i2, 1, i6);
+  _lua_rawgeti(i2, 1, i8);
+  _lua_rawseti(i2, 1, i6);
+  _lua_rawseti(i2, 1, i8);
+  i8 = (i8 - i4 | 0) < (i5 - i8 | 0);
+  i9 = i7 + 2 | 0;
+  i10 = i8 ? i9 : i4;
+  i6 = i8 ? i5 : i7;
+  _auxsort(i2, i8 ? i4 : i9, i8 ? i7 : i5);
+  if ((i10 | 0) < (i6 | 0)) {
+   i4 = i10;
+   i5 = i6;
+  } else {
+   i2 = 24;
+   break;
+  }
+ }
+ if ((i2 | 0) == 24) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _skip_sep(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i3 >> 2] | 0;
+ i4 = i3 + 60 | 0;
+ i10 = HEAP32[i4 >> 2] | 0;
+ i8 = i10 + 4 | 0;
+ i11 = HEAP32[i8 >> 2] | 0;
+ i7 = i10 + 8 | 0;
+ i5 = HEAP32[i7 >> 2] | 0;
+ do {
+  if ((i11 + 1 | 0) >>> 0 > i5 >>> 0) {
+   if (i5 >>> 0 > 2147483645) {
+    _lexerror(i3, 12368, 0);
+   }
+   i12 = i5 << 1;
+   i11 = HEAP32[i3 + 52 >> 2] | 0;
+   if ((i12 | 0) == -2) {
+    _luaM_toobig(i11);
+   } else {
+    i9 = _luaM_realloc_(i11, HEAP32[i10 >> 2] | 0, i5, i12) | 0;
+    HEAP32[i10 >> 2] = i9;
+    HEAP32[i7 >> 2] = i12;
+    i6 = HEAP32[i8 >> 2] | 0;
+    break;
+   }
+  } else {
+   i6 = i11;
+   i9 = HEAP32[i10 >> 2] | 0;
+  }
+ } while (0);
+ HEAP32[i8 >> 2] = i6 + 1;
+ HEAP8[i9 + i6 | 0] = i2;
+ i5 = i3 + 56 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i13 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i13 + -1;
+ if ((i13 | 0) == 0) {
+  i6 = _luaZ_fill(i6) | 0;
+ } else {
+  i13 = i6 + 4 | 0;
+  i6 = HEAP32[i13 >> 2] | 0;
+  HEAP32[i13 >> 2] = i6 + 1;
+  i6 = HEAPU8[i6] | 0;
+ }
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) != 61) {
+  i12 = i6;
+  i13 = 0;
+  i12 = (i12 | 0) != (i2 | 0);
+  i12 = i12 << 31 >> 31;
+  i13 = i12 ^ i13;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ i6 = i3 + 52 | 0;
+ i7 = 0;
+ while (1) {
+  i9 = HEAP32[i4 >> 2] | 0;
+  i8 = i9 + 4 | 0;
+  i10 = HEAP32[i8 >> 2] | 0;
+  i11 = i9 + 8 | 0;
+  i12 = HEAP32[i11 >> 2] | 0;
+  if ((i10 + 1 | 0) >>> 0 > i12 >>> 0) {
+   if (i12 >>> 0 > 2147483645) {
+    i4 = 16;
+    break;
+   }
+   i13 = i12 << 1;
+   i10 = HEAP32[i6 >> 2] | 0;
+   if ((i13 | 0) == -2) {
+    i4 = 18;
+    break;
+   }
+   i12 = _luaM_realloc_(i10, HEAP32[i9 >> 2] | 0, i12, i13) | 0;
+   HEAP32[i9 >> 2] = i12;
+   HEAP32[i11 >> 2] = i13;
+   i10 = HEAP32[i8 >> 2] | 0;
+   i9 = i12;
+  } else {
+   i9 = HEAP32[i9 >> 2] | 0;
+  }
+  HEAP32[i8 >> 2] = i10 + 1;
+  HEAP8[i9 + i10 | 0] = 61;
+  i8 = HEAP32[i5 >> 2] | 0;
+  i13 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i13 + -1;
+  if ((i13 | 0) == 0) {
+   i8 = _luaZ_fill(i8) | 0;
+  } else {
+   i13 = i8 + 4 | 0;
+   i8 = HEAP32[i13 >> 2] | 0;
+   HEAP32[i13 >> 2] = i8 + 1;
+   i8 = HEAPU8[i8] | 0;
+  }
+  HEAP32[i3 >> 2] = i8;
+  i7 = i7 + 1 | 0;
+  if ((i8 | 0) != 61) {
+   i4 = 24;
+   break;
+  }
+ }
+ if ((i4 | 0) == 16) {
+  _lexerror(i3, 12368, 0);
+ } else if ((i4 | 0) == 18) {
+  _luaM_toobig(i10);
+ } else if ((i4 | 0) == 24) {
+  i13 = (i8 | 0) != (i2 | 0);
+  i13 = i13 << 31 >> 31;
+  i13 = i13 ^ i7;
+  STACKTOP = i1;
+  return i13 | 0;
+ }
+ return 0;
+}
+function _luaV_arith(i8, i2, i3, i5, i4) {
+ i8 = i8 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, d14 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i9 = i1 + 24 | 0;
+ i13 = i1 + 16 | 0;
+ i12 = i1;
+ i6 = i3 + 8 | 0;
+ i11 = HEAP32[i6 >> 2] | 0;
+ if ((i11 | 0) != 3) {
+  if ((i11 & 15 | 0) == 4 ? (i11 = HEAP32[i3 >> 2] | 0, (_luaO_str2d(i11 + 16 | 0, HEAP32[i11 + 12 >> 2] | 0, i13) | 0) != 0) : 0) {
+   HEAPF64[i12 >> 3] = +HEAPF64[i13 >> 3];
+   HEAP32[i12 + 8 >> 2] = 3;
+   i10 = 5;
+  }
+ } else {
+  i12 = i3;
+  i10 = 5;
+ }
+ do {
+  if ((i10 | 0) == 5) {
+   i10 = HEAP32[i5 + 8 >> 2] | 0;
+   if ((i10 | 0) == 3) {
+    if ((i5 | 0) == 0) {
+     break;
+    }
+    d14 = +HEAPF64[i5 >> 3];
+   } else {
+    if ((i10 & 15 | 0) != 4) {
+     break;
+    }
+    i13 = HEAP32[i5 >> 2] | 0;
+    if ((_luaO_str2d(i13 + 16 | 0, HEAP32[i13 + 12 >> 2] | 0, i9) | 0) == 0) {
+     break;
+    }
+    d14 = +HEAPF64[i9 >> 3];
+   }
+   HEAPF64[i2 >> 3] = +_luaO_arith(i4 + -6 | 0, +HEAPF64[i12 >> 3], d14);
+   HEAP32[i2 + 8 >> 2] = 3;
+   STACKTOP = i1;
+   return;
+  }
+ } while (0);
+ i9 = _luaT_gettmbyobj(i8, i3, i4) | 0;
+ if ((HEAP32[i9 + 8 >> 2] | 0) == 0) {
+  i4 = _luaT_gettmbyobj(i8, i5, i4) | 0;
+  if ((HEAP32[i4 + 8 >> 2] | 0) == 0) {
+   _luaG_aritherror(i8, i3, i5);
+  } else {
+   i7 = i4;
+  }
+ } else {
+  i7 = i9;
+ }
+ i12 = i8 + 28 | 0;
+ i13 = i2 - (HEAP32[i12 >> 2] | 0) | 0;
+ i9 = i8 + 8 | 0;
+ i11 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = i11 + 16;
+ i2 = i7;
+ i10 = HEAP32[i2 + 4 >> 2] | 0;
+ i4 = i11;
+ HEAP32[i4 >> 2] = HEAP32[i2 >> 2];
+ HEAP32[i4 + 4 >> 2] = i10;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+ i11 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = i11 + 16;
+ i4 = i3;
+ i10 = HEAP32[i4 + 4 >> 2] | 0;
+ i7 = i11;
+ HEAP32[i7 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[i7 + 4 >> 2] = i10;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i6 >> 2];
+ i11 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = i11 + 16;
+ i6 = i5;
+ i7 = HEAP32[i6 + 4 >> 2] | 0;
+ i10 = i11;
+ HEAP32[i10 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i10 + 4 >> 2] = i7;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i5 + 8 >> 2];
+ _luaD_call(i8, (HEAP32[i9 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i8 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i12 = HEAP32[i12 >> 2] | 0;
+ i11 = HEAP32[i9 >> 2] | 0;
+ i8 = i11 + -16 | 0;
+ HEAP32[i9 >> 2] = i8;
+ i9 = HEAP32[i8 + 4 >> 2] | 0;
+ i10 = i12 + i13 | 0;
+ HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i10 + 4 >> 2] = i9;
+ HEAP32[i12 + (i13 + 8) >> 2] = HEAP32[i11 + -8 >> 2];
+ STACKTOP = i1;
+ return;
+}
+function _new_localvar(i1, i8) {
+ i1 = i1 | 0;
+ i8 = i8 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i5 = HEAP32[i1 + 48 >> 2] | 0;
+ i2 = HEAP32[i1 + 64 >> 2] | 0;
+ i7 = HEAP32[i5 >> 2] | 0;
+ i10 = i7 + 60 | 0;
+ i11 = HEAP32[i10 >> 2] | 0;
+ i6 = i5 + 44 | 0;
+ if ((HEAP16[i6 >> 1] | 0) < (i11 | 0)) {
+  i9 = i7 + 24 | 0;
+  i10 = i11;
+ } else {
+  i9 = i7 + 24 | 0;
+  HEAP32[i9 >> 2] = _luaM_growaux_(HEAP32[i1 + 52 >> 2] | 0, HEAP32[i9 >> 2] | 0, i10, 12, 32767, 6496) | 0;
+  i10 = HEAP32[i10 >> 2] | 0;
+ }
+ if ((i11 | 0) < (i10 | 0)) {
+  i12 = i11;
+  while (1) {
+   i11 = i12 + 1 | 0;
+   HEAP32[(HEAP32[i9 >> 2] | 0) + (i12 * 12 | 0) >> 2] = 0;
+   if ((i11 | 0) == (i10 | 0)) {
+    break;
+   } else {
+    i12 = i11;
+   }
+  }
+ }
+ i10 = HEAP16[i6 >> 1] | 0;
+ HEAP32[(HEAP32[i9 >> 2] | 0) + ((i10 << 16 >> 16) * 12 | 0) >> 2] = i8;
+ if (!((HEAP8[i8 + 5 | 0] & 3) == 0) ? !((HEAP8[i7 + 5 | 0] & 4) == 0) : 0) {
+  _luaC_barrier_(HEAP32[i1 + 52 >> 2] | 0, i7, i8);
+  i7 = HEAP16[i6 >> 1] | 0;
+ } else {
+  i7 = i10;
+ }
+ HEAP16[i6 >> 1] = i7 + 1 << 16 >> 16;
+ i6 = i2 + 4 | 0;
+ i8 = HEAP32[i6 >> 2] | 0;
+ if ((i8 + 1 - (HEAP32[i5 + 40 >> 2] | 0) | 0) > 200) {
+  i10 = i5 + 12 | 0;
+  i9 = HEAP32[(HEAP32[i10 >> 2] | 0) + 52 >> 2] | 0;
+  i5 = HEAP32[(HEAP32[i5 >> 2] | 0) + 64 >> 2] | 0;
+  if ((i5 | 0) == 0) {
+   i11 = 6552;
+   HEAP32[i4 >> 2] = 6496;
+   i12 = i4 + 4 | 0;
+   HEAP32[i12 >> 2] = 200;
+   i12 = i4 + 8 | 0;
+   HEAP32[i12 >> 2] = i11;
+   i12 = _luaO_pushfstring(i9, 6592, i4) | 0;
+   i11 = HEAP32[i10 >> 2] | 0;
+   _luaX_syntaxerror(i11, i12);
+  }
+  HEAP32[i4 >> 2] = i5;
+  i11 = _luaO_pushfstring(i9, 6568, i4) | 0;
+  HEAP32[i4 >> 2] = 6496;
+  i12 = i4 + 4 | 0;
+  HEAP32[i12 >> 2] = 200;
+  i12 = i4 + 8 | 0;
+  HEAP32[i12 >> 2] = i11;
+  i12 = _luaO_pushfstring(i9, 6592, i4) | 0;
+  i11 = HEAP32[i10 >> 2] | 0;
+  _luaX_syntaxerror(i11, i12);
+ }
+ i4 = i2 + 8 | 0;
+ if ((i8 + 2 | 0) > (HEAP32[i4 >> 2] | 0)) {
+  i11 = _luaM_growaux_(HEAP32[i1 + 52 >> 2] | 0, HEAP32[i2 >> 2] | 0, i4, 2, 2147483645, 6496) | 0;
+  HEAP32[i2 >> 2] = i11;
+  i12 = HEAP32[i6 >> 2] | 0;
+  i10 = i12 + 1 | 0;
+  HEAP32[i6 >> 2] = i10;
+  i12 = i11 + (i12 << 1) | 0;
+  HEAP16[i12 >> 1] = i7;
+  STACKTOP = i3;
+  return;
+ } else {
+  i12 = i8;
+  i11 = HEAP32[i2 >> 2] | 0;
+  i10 = i12 + 1 | 0;
+  HEAP32[i6 >> 2] = i10;
+  i12 = i11 + (i12 << 1) | 0;
+  HEAP16[i12 >> 1] = i7;
+  STACKTOP = i3;
+  return;
+ }
+}
+function _luaC_fullgc(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ i4 = i1 + 12 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ i6 = i3 + 62 | 0;
+ i8 = HEAP8[i6] | 0;
+ i5 = (i5 | 0) != 0;
+ if (!i5) {
+  HEAP8[i6] = 0;
+  i9 = (HEAP32[i4 >> 2] | 0) + 104 | 0;
+  i10 = HEAP32[i9 >> 2] | 0;
+  if ((i10 | 0) != 0) {
+   do {
+    i11 = i10 + 5 | 0;
+    HEAP8[i11] = HEAP8[i11] & 191;
+    _GCTM(i1, 1);
+    i10 = HEAP32[i9 >> 2] | 0;
+   } while ((i10 | 0) != 0);
+   if ((HEAP8[i6] | 0) == 2) {
+    i9 = 7;
+   } else {
+    i9 = 6;
+   }
+  } else {
+   i9 = 6;
+  }
+ } else {
+  HEAP8[i6] = 1;
+  i9 = 6;
+ }
+ if ((i9 | 0) == 6 ? (HEAPU8[i3 + 61 | 0] | 0) < 2 : 0) {
+  i9 = 7;
+ }
+ if ((i9 | 0) == 7) {
+  i9 = HEAP32[i4 >> 2] | 0;
+  HEAP8[i9 + 61 | 0] = 2;
+  HEAP32[i9 + 64 >> 2] = 0;
+  i10 = i9 + 72 | 0;
+  do {
+   i11 = _sweeplist(i1, i10, 1) | 0;
+  } while ((i11 | 0) == (i10 | 0));
+  HEAP32[i9 + 80 >> 2] = i11;
+  i11 = i9 + 68 | 0;
+  do {
+   i10 = _sweeplist(i1, i11, 1) | 0;
+  } while ((i10 | 0) == (i11 | 0));
+  HEAP32[i9 + 76 >> 2] = i10;
+ }
+ i11 = HEAP32[i4 >> 2] | 0;
+ i9 = i11 + 61 | 0;
+ if ((HEAP8[i9] | 0) == 5) {
+  i9 = 5;
+ } else {
+  do {
+   _singlestep(i1) | 0;
+  } while ((HEAP8[i9] | 0) != 5);
+  i9 = HEAP32[i4 >> 2] | 0;
+  i11 = i9;
+  i9 = HEAP8[i9 + 61 | 0] | 0;
+ }
+ i10 = i11 + 61 | 0;
+ if ((1 << (i9 & 255) & -33 | 0) == 0) {
+  do {
+   _singlestep(i1) | 0;
+  } while ((1 << HEAPU8[i10] & -33 | 0) == 0);
+  i9 = HEAP32[i4 >> 2] | 0;
+  i11 = i9;
+  i9 = HEAP8[i9 + 61 | 0] | 0;
+ }
+ i10 = i11 + 61 | 0;
+ if (!(i9 << 24 >> 24 == 5)) {
+  do {
+   _singlestep(i1) | 0;
+  } while ((HEAP8[i10] | 0) != 5);
+ }
+ if (i8 << 24 >> 24 == 2 ? (i7 = (HEAP32[i4 >> 2] | 0) + 61 | 0, (HEAP8[i7] | 0) != 0) : 0) {
+  do {
+   _singlestep(i1) | 0;
+  } while ((HEAP8[i7] | 0) != 0);
+ }
+ HEAP8[i6] = i8;
+ i6 = HEAP32[i3 + 8 >> 2] | 0;
+ i7 = HEAP32[i3 + 12 >> 2] | 0;
+ i8 = (i7 + i6 | 0) / 100 | 0;
+ i9 = HEAP32[i3 + 156 >> 2] | 0;
+ if ((i9 | 0) < (2147483644 / (i8 | 0) | 0 | 0)) {
+  i8 = Math_imul(i9, i8) | 0;
+ } else {
+  i8 = 2147483644;
+ }
+ _luaE_setdebt(i3, i6 - i8 + i7 | 0);
+ if (i5) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = (HEAP32[i4 >> 2] | 0) + 104 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  i11 = i4 + 5 | 0;
+  HEAP8[i11] = HEAP8[i11] & 191;
+  _GCTM(i1, 1);
+  i4 = HEAP32[i3 >> 2] | 0;
+ } while ((i4 | 0) != 0);
+ STACKTOP = i2;
+ return;
+}
+function _scanexp(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i2 = i3 + 4 | 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ i4 = i3 + 100 | 0;
+ if (i5 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+  HEAP32[i2 >> 2] = i5 + 1;
+  i8 = HEAPU8[i5] | 0;
+ } else {
+  i8 = ___shgetc(i3) | 0;
+ }
+ if ((i8 | 0) == 43 | (i8 | 0) == 45) {
+  i5 = (i8 | 0) == 45 | 0;
+  i7 = HEAP32[i2 >> 2] | 0;
+  if (i7 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+   HEAP32[i2 >> 2] = i7 + 1;
+   i8 = HEAPU8[i7] | 0;
+  } else {
+   i8 = ___shgetc(i3) | 0;
+  }
+  if (!((i8 + -48 | 0) >>> 0 < 10 | (i6 | 0) == 0) ? (HEAP32[i4 >> 2] | 0) != 0 : 0) {
+   HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + -1;
+  }
+ } else {
+  i5 = 0;
+ }
+ if ((i8 + -48 | 0) >>> 0 > 9) {
+  if ((HEAP32[i4 >> 2] | 0) == 0) {
+   i7 = -2147483648;
+   i8 = 0;
+   tempRet0 = i7;
+   STACKTOP = i1;
+   return i8 | 0;
+  }
+  HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + -1;
+  i7 = -2147483648;
+  i8 = 0;
+  tempRet0 = i7;
+  STACKTOP = i1;
+  return i8 | 0;
+ } else {
+  i6 = 0;
+ }
+ while (1) {
+  i6 = i8 + -48 + i6 | 0;
+  i7 = HEAP32[i2 >> 2] | 0;
+  if (i7 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+   HEAP32[i2 >> 2] = i7 + 1;
+   i8 = HEAPU8[i7] | 0;
+  } else {
+   i8 = ___shgetc(i3) | 0;
+  }
+  if (!((i8 + -48 | 0) >>> 0 < 10 & (i6 | 0) < 214748364)) {
+   break;
+  }
+  i6 = i6 * 10 | 0;
+ }
+ i7 = ((i6 | 0) < 0) << 31 >> 31;
+ if ((i8 + -48 | 0) >>> 0 < 10) {
+  do {
+   i7 = ___muldi3(i6 | 0, i7 | 0, 10, 0) | 0;
+   i6 = tempRet0;
+   i8 = _i64Add(i8 | 0, ((i8 | 0) < 0) << 31 >> 31 | 0, -48, -1) | 0;
+   i6 = _i64Add(i8 | 0, tempRet0 | 0, i7 | 0, i6 | 0) | 0;
+   i7 = tempRet0;
+   i8 = HEAP32[i2 >> 2] | 0;
+   if (i8 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+    HEAP32[i2 >> 2] = i8 + 1;
+    i8 = HEAPU8[i8] | 0;
+   } else {
+    i8 = ___shgetc(i3) | 0;
+   }
+  } while ((i8 + -48 | 0) >>> 0 < 10 & ((i7 | 0) < 21474836 | (i7 | 0) == 21474836 & i6 >>> 0 < 2061584302));
+ }
+ if ((i8 + -48 | 0) >>> 0 < 10) {
+  do {
+   i8 = HEAP32[i2 >> 2] | 0;
+   if (i8 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0) {
+    HEAP32[i2 >> 2] = i8 + 1;
+    i8 = HEAPU8[i8] | 0;
+   } else {
+    i8 = ___shgetc(i3) | 0;
+   }
+  } while ((i8 + -48 | 0) >>> 0 < 10);
+ }
+ if ((HEAP32[i4 >> 2] | 0) != 0) {
+  HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + -1;
+ }
+ i3 = (i5 | 0) != 0;
+ i2 = _i64Subtract(0, 0, i6 | 0, i7 | 0) | 0;
+ i4 = i3 ? tempRet0 : i7;
+ i8 = i3 ? i2 : i6;
+ tempRet0 = i4;
+ STACKTOP = i1;
+ return i8 | 0;
+}
+function _sweeplist(i3, i8, i9) {
+ i3 = i3 | 0;
+ i8 = i8 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ i5 = i3 + 12 | 0;
+ i7 = HEAP32[i5 >> 2] | 0;
+ i6 = HEAPU8[i7 + 60 | 0] | 0;
+ i2 = i6 ^ 3;
+ i7 = (HEAP8[i7 + 62 | 0] | 0) == 2;
+ i4 = i7 ? 255 : 184;
+ i6 = i7 ? 64 : i6 & 3;
+ i7 = i7 ? 64 : 0;
+ i10 = HEAP32[i8 >> 2] | 0;
+ L1 : do {
+  if ((i10 | 0) == 0) {
+   i10 = 0;
+  } else {
+   i11 = i9;
+   L2 : while (1) {
+    i9 = i11 + -1 | 0;
+    if ((i11 | 0) == 0) {
+     break L1;
+    }
+    i11 = i10 + 5 | 0;
+    i12 = HEAPU8[i11] | 0;
+    L5 : do {
+     if (((i12 ^ 3) & i2 | 0) == 0) {
+      HEAP32[i8 >> 2] = HEAP32[i10 >> 2];
+      switch (HEAPU8[i10 + 4 | 0] | 0) {
+      case 4:
+       {
+        i12 = (HEAP32[i5 >> 2] | 0) + 28 | 0;
+        HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + -1;
+        break;
+       }
+      case 38:
+       {
+        _luaM_realloc_(i3, i10, (HEAPU8[i10 + 6 | 0] << 4) + 16 | 0, 0) | 0;
+        break L5;
+       }
+      case 6:
+       {
+        _luaM_realloc_(i3, i10, (HEAPU8[i10 + 6 | 0] << 2) + 16 | 0, 0) | 0;
+        break L5;
+       }
+      case 20:
+       {
+        break;
+       }
+      case 5:
+       {
+        _luaH_free(i3, i10);
+        break L5;
+       }
+      case 10:
+       {
+        _luaF_freeupval(i3, i10);
+        break L5;
+       }
+      case 8:
+       {
+        _luaE_freethread(i3, i10);
+        break L5;
+       }
+      case 9:
+       {
+        _luaF_freeproto(i3, i10);
+        break L5;
+       }
+      case 7:
+       {
+        _luaM_realloc_(i3, i10, (HEAP32[i10 + 16 >> 2] | 0) + 24 | 0, 0) | 0;
+        break L5;
+       }
+      default:
+       {
+        break L5;
+       }
+      }
+      _luaM_realloc_(i3, i10, (HEAP32[i10 + 12 >> 2] | 0) + 17 | 0, 0) | 0;
+     } else {
+      if ((i12 & i7 | 0) != 0) {
+       i2 = 0;
+       break L2;
+      }
+      if (((HEAP8[i10 + 4 | 0] | 0) == 8 ? (HEAP32[i10 + 28 >> 2] | 0) != 0 : 0) ? (_sweeplist(i3, i10 + 56 | 0, -3) | 0, _luaE_freeCI(i10), (HEAP8[(HEAP32[i5 >> 2] | 0) + 62 | 0] | 0) != 1) : 0) {
+       _luaD_shrinkstack(i10);
+      }
+      HEAP8[i11] = i12 & i4 | i6;
+      i8 = i10;
+     }
+    } while (0);
+    i10 = HEAP32[i8 >> 2] | 0;
+    if ((i10 | 0) == 0) {
+     i10 = 0;
+     break L1;
+    } else {
+     i11 = i9;
+    }
+   }
+   STACKTOP = i1;
+   return i2 | 0;
+  }
+ } while (0);
+ i12 = (i10 | 0) == 0 ? 0 : i8;
+ STACKTOP = i1;
+ return i12 | 0;
+}
+function _resume(i1, i6) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 16 | 0;
+ i5 = HEAP32[i3 >> 2] | 0;
+ if ((HEAPU16[i1 + 38 >> 1] | 0) > 199) {
+  _resume_error(i1, 2240, i6);
+ }
+ i4 = i1 + 6 | 0;
+ i7 = HEAP8[i4] | 0;
+ if (i7 << 24 >> 24 == 0) {
+  if ((i5 | 0) != (i1 + 72 | 0)) {
+   _resume_error(i1, 2448, i6);
+  }
+  if ((_luaD_precall(i1, i6 + -16 | 0, -1) | 0) != 0) {
+   STACKTOP = i2;
+   return;
+  }
+  _luaV_execute(i1);
+  STACKTOP = i2;
+  return;
+ } else if (i7 << 24 >> 24 == 1) {
+  HEAP8[i4] = 0;
+  i4 = i1 + 28 | 0;
+  HEAP32[i5 >> 2] = (HEAP32[i4 >> 2] | 0) + (HEAP32[i5 + 20 >> 2] | 0);
+  i8 = i5 + 18 | 0;
+  i7 = HEAP8[i8] | 0;
+  if ((i7 & 1) == 0) {
+   i9 = HEAP32[i5 + 28 >> 2] | 0;
+   if ((i9 | 0) != 0) {
+    HEAP8[i5 + 37 | 0] = 1;
+    HEAP8[i8] = i7 & 255 | 8;
+    i6 = FUNCTION_TABLE_ii[i9 & 255](i1) | 0;
+    i6 = (HEAP32[i1 + 8 >> 2] | 0) + (0 - i6 << 4) | 0;
+   }
+   i5 = HEAP32[i3 >> 2] | 0;
+   i7 = HEAPU8[i1 + 40 | 0] | 0;
+   if ((i7 & 6 | 0) == 0) {
+    i7 = i5 + 8 | 0;
+   } else {
+    if ((i7 & 2 | 0) != 0) {
+     i6 = i6 - (HEAP32[i4 >> 2] | 0) | 0;
+     _luaD_hook(i1, 1, -1);
+     i6 = (HEAP32[i4 >> 2] | 0) + i6 | 0;
+    }
+    i7 = i5 + 8 | 0;
+    HEAP32[i1 + 20 >> 2] = HEAP32[(HEAP32[i7 >> 2] | 0) + 28 >> 2];
+   }
+   i4 = HEAP32[i5 >> 2] | 0;
+   i5 = HEAP16[i5 + 16 >> 1] | 0;
+   HEAP32[i3 >> 2] = HEAP32[i7 >> 2];
+   i3 = i1 + 8 | 0;
+   L27 : do {
+    if (!(i5 << 16 >> 16 == 0)) {
+     i5 = i5 << 16 >> 16;
+     while (1) {
+      if (!(i6 >>> 0 < (HEAP32[i3 >> 2] | 0) >>> 0)) {
+       break;
+      }
+      i7 = i4 + 16 | 0;
+      i10 = i6;
+      i8 = HEAP32[i10 + 4 >> 2] | 0;
+      i9 = i4;
+      HEAP32[i9 >> 2] = HEAP32[i10 >> 2];
+      HEAP32[i9 + 4 >> 2] = i8;
+      HEAP32[i4 + 8 >> 2] = HEAP32[i6 + 8 >> 2];
+      i5 = i5 + -1 | 0;
+      if ((i5 | 0) == 0) {
+       i4 = i7;
+       break L27;
+      }
+      i6 = i6 + 16 | 0;
+      i4 = i7;
+     }
+     if ((i5 | 0) > 0) {
+      i7 = i5;
+      i6 = i4;
+      while (1) {
+       i7 = i7 + -1 | 0;
+       HEAP32[i6 + 8 >> 2] = 0;
+       if ((i7 | 0) <= 0) {
+        break;
+       } else {
+        i6 = i6 + 16 | 0;
+       }
+      }
+      i4 = i4 + (i5 << 4) | 0;
+     }
+    }
+   } while (0);
+   HEAP32[i3 >> 2] = i4;
+  } else {
+   _luaV_execute(i1);
+  }
+  _unroll(i1, 0);
+  STACKTOP = i2;
+  return;
+ } else {
+  _resume_error(i1, 2488, i6);
+ }
+}
+function _lua_setupvalue(i1, i5, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i6 >> 2] | 0, (i5 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i4 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i6 >> 2] | 0) + (i5 << 4) | 0;
+   i5 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i4 = HEAP32[i5 + 8 >> 2] & 63;
+ do {
+  if ((i4 | 0) == 6) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   i4 = HEAP32[i5 + 12 >> 2] | 0;
+   if ((i3 | 0) <= 0) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   if ((HEAP32[i4 + 40 >> 2] | 0) < (i3 | 0)) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   i6 = i3 + -1 | 0;
+   i3 = HEAP32[i5 + 16 + (i6 << 2) >> 2] | 0;
+   i5 = HEAP32[i3 + 8 >> 2] | 0;
+   i4 = HEAP32[(HEAP32[i4 + 28 >> 2] | 0) + (i6 << 3) >> 2] | 0;
+   if ((i4 | 0) == 0) {
+    i4 = 936;
+   } else {
+    i4 = i4 + 16 | 0;
+   }
+  } else if ((i4 | 0) == 38) {
+   i6 = HEAP32[i5 >> 2] | 0;
+   if ((i3 | 0) <= 0) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   if ((HEAPU8[i6 + 6 | 0] | 0 | 0) >= (i3 | 0)) {
+    i4 = 936;
+    i5 = i6 + (i3 + -1 << 4) + 16 | 0;
+    i3 = i6;
+    break;
+   } else {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+  } else {
+   i6 = 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ } while (0);
+ i6 = i1 + 8 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ i10 = i7 + -16 | 0;
+ HEAP32[i6 >> 2] = i10;
+ i9 = HEAP32[i10 + 4 >> 2] | 0;
+ i8 = i5;
+ HEAP32[i8 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i8 + 4 >> 2] = i9;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i7 + -8 >> 2];
+ i5 = HEAP32[i6 >> 2] | 0;
+ if ((HEAP32[i5 + 8 >> 2] & 64 | 0) == 0) {
+  i10 = i4;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((HEAP8[i5 + 5 | 0] & 3) == 0) {
+  i10 = i4;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ if ((HEAP8[i3 + 5 | 0] & 4) == 0) {
+  i10 = i4;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ _luaC_barrier_(i1, i3, i5);
+ i10 = i4;
+ STACKTOP = i2;
+ return i10 | 0;
+}
+function _luaC_forcestep(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 12 >> 2] | 0;
+ do {
+  if ((HEAP8[i3 + 62 | 0] | 0) == 2) {
+   i4 = i3 + 20 | 0;
+   i6 = HEAP32[i4 >> 2] | 0;
+   do {
+    if ((i6 | 0) != 0) {
+     i5 = i3 + 61 | 0;
+     if ((HEAP8[i5] | 0) != 5) {
+      do {
+       _singlestep(i2) | 0;
+      } while ((HEAP8[i5] | 0) != 5);
+     }
+     HEAP8[i5] = 0;
+     i5 = HEAP32[i3 + 8 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     if ((i7 + i5 | 0) >>> 0 > (Math_imul(HEAP32[i3 + 160 >> 2] | 0, (i6 >>> 0) / 100 | 0) | 0) >>> 0) {
+      HEAP32[i4 >> 2] = 0;
+      break;
+     } else {
+      HEAP32[i4 >> 2] = i6;
+      break;
+     }
+    } else {
+     _luaC_fullgc(i2, 0);
+     i5 = HEAP32[i3 + 8 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     HEAP32[i4 >> 2] = i7 + i5;
+    }
+   } while (0);
+   i4 = i5 + i7 | 0;
+   i5 = (i4 | 0) / 100 | 0;
+   i6 = HEAP32[i3 + 156 >> 2] | 0;
+   if ((i6 | 0) < (2147483644 / (i5 | 0) | 0 | 0)) {
+    i5 = Math_imul(i6, i5) | 0;
+   } else {
+    i5 = 2147483644;
+   }
+   _luaE_setdebt(i3, i4 - i5 | 0);
+   i5 = i3 + 61 | 0;
+  } else {
+   i4 = i3 + 12 | 0;
+   i5 = HEAP32[i3 + 164 >> 2] | 0;
+   i7 = (i5 | 0) < 40 ? 40 : i5;
+   i5 = ((HEAP32[i4 >> 2] | 0) / 200 | 0) + 1 | 0;
+   if ((i5 | 0) < (2147483644 / (i7 | 0) | 0 | 0)) {
+    i8 = Math_imul(i5, i7) | 0;
+   } else {
+    i8 = 2147483644;
+   }
+   i5 = i3 + 61 | 0;
+   do {
+    i8 = i8 - (_singlestep(i2) | 0) | 0;
+    i9 = (HEAP8[i5] | 0) == 5;
+    if (!((i8 | 0) > -1600)) {
+     i6 = 17;
+     break;
+    }
+   } while (!i9);
+   if ((i6 | 0) == 17 ? !i9 : 0) {
+    _luaE_setdebt(i3, ((i8 | 0) / (i7 | 0) | 0) * 200 | 0);
+    break;
+   }
+   i6 = (HEAP32[i3 + 20 >> 2] | 0) / 100 | 0;
+   i7 = HEAP32[i3 + 156 >> 2] | 0;
+   if ((i7 | 0) < (2147483644 / (i6 | 0) | 0 | 0)) {
+    i6 = Math_imul(i7, i6) | 0;
+   } else {
+    i6 = 2147483644;
+   }
+   _luaE_setdebt(i3, (HEAP32[i3 + 8 >> 2] | 0) - i6 + (HEAP32[i4 >> 2] | 0) | 0);
+  }
+ } while (0);
+ i3 = i3 + 104 | 0;
+ if ((HEAP32[i3 >> 2] | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ } else {
+  i4 = 0;
+ }
+ while (1) {
+  if ((i4 | 0) >= 4 ? (HEAP8[i5] | 0) != 5 : 0) {
+   i6 = 26;
+   break;
+  }
+  _GCTM(i2, 1);
+  if ((HEAP32[i3 >> 2] | 0) == 0) {
+   i6 = 26;
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ if ((i6 | 0) == 26) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaL_loadfilex(i1, i9, i7) {
+ i1 = i1 | 0;
+ i9 = i9 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i10 = 0, i11 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i3 = i5;
+ i6 = i5 + 16 | 0;
+ i8 = i5 + 12 | 0;
+ i2 = (_lua_gettop(i1) | 0) + 1 | 0;
+ i4 = (i9 | 0) == 0;
+ if (!i4) {
+  HEAP32[i3 >> 2] = i9;
+  _lua_pushfstring(i1, 1304, i3) | 0;
+  i10 = _fopen(i9 | 0, 1312) | 0;
+  HEAP32[i6 + 4 >> 2] = i10;
+  if ((i10 | 0) == 0) {
+   i10 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+   i9 = (_lua_tolstring(i1, i2, 0) | 0) + 1 | 0;
+   HEAP32[i3 >> 2] = 1320;
+   HEAP32[i3 + 4 >> 2] = i9;
+   HEAP32[i3 + 8 >> 2] = i10;
+   _lua_pushfstring(i1, 1720, i3) | 0;
+   _lua_remove(i1, i2);
+   i10 = 7;
+   STACKTOP = i5;
+   return i10 | 0;
+  }
+ } else {
+  _lua_pushlstring(i1, 1296, 6) | 0;
+  HEAP32[i6 + 4 >> 2] = HEAP32[_stdin >> 2];
+ }
+ if ((_skipcomment(i6, i8) | 0) != 0) {
+  i10 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i10 + 1;
+  HEAP8[i6 + i10 + 8 | 0] = 10;
+ }
+ i10 = HEAP32[i8 >> 2] | 0;
+ do {
+  if (!((i10 | 0) != 27 | i4)) {
+   i11 = i6 + 4 | 0;
+   i10 = _freopen(i9 | 0, 1328, HEAP32[i11 >> 2] | 0) | 0;
+   HEAP32[i11 >> 2] = i10;
+   if ((i10 | 0) != 0) {
+    _skipcomment(i6, i8) | 0;
+    i10 = HEAP32[i8 >> 2] | 0;
+    break;
+   }
+   i11 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+   i10 = (_lua_tolstring(i1, i2, 0) | 0) + 1 | 0;
+   HEAP32[i3 >> 2] = 1336;
+   HEAP32[i3 + 4 >> 2] = i10;
+   HEAP32[i3 + 8 >> 2] = i11;
+   _lua_pushfstring(i1, 1720, i3) | 0;
+   _lua_remove(i1, i2);
+   i11 = 7;
+   STACKTOP = i5;
+   return i11 | 0;
+  }
+ } while (0);
+ if (!((i10 | 0) == -1)) {
+  i11 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i11 + 1;
+  HEAP8[i6 + i11 + 8 | 0] = i10;
+ }
+ i7 = _lua_load(i1, 1, i6, _lua_tolstring(i1, -1, 0) | 0, i7) | 0;
+ i8 = HEAP32[i6 + 4 >> 2] | 0;
+ i6 = _ferror(i8 | 0) | 0;
+ if (!i4) {
+  _fclose(i8 | 0) | 0;
+ }
+ if ((i6 | 0) == 0) {
+  _lua_remove(i1, i2);
+  i11 = i7;
+  STACKTOP = i5;
+  return i11 | 0;
+ } else {
+  _lua_settop(i1, i2);
+  i11 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+  i10 = (_lua_tolstring(i1, i2, 0) | 0) + 1 | 0;
+  HEAP32[i3 >> 2] = 1344;
+  HEAP32[i3 + 4 >> 2] = i10;
+  HEAP32[i3 + 8 >> 2] = i11;
+  _lua_pushfstring(i1, 1720, i3) | 0;
+  _lua_remove(i1, i2);
+  i11 = 7;
+  STACKTOP = i5;
+  return i11 | 0;
+ }
+ return 0;
+}
+function _newupvalue(i3, i1, i2) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i12 = i4;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i9 = i5 + 40 | 0;
+ i7 = HEAP32[i9 >> 2] | 0;
+ i6 = i3 + 47 | 0;
+ i10 = HEAPU8[i6] | 0;
+ if ((i10 + 1 | 0) >>> 0 > 255) {
+  i11 = i3 + 12 | 0;
+  i8 = HEAP32[(HEAP32[i11 >> 2] | 0) + 52 >> 2] | 0;
+  i13 = HEAP32[i5 + 64 >> 2] | 0;
+  if ((i13 | 0) == 0) {
+   i15 = 6552;
+   HEAP32[i12 >> 2] = 6880;
+   i14 = i12 + 4 | 0;
+   HEAP32[i14 >> 2] = 255;
+   i14 = i12 + 8 | 0;
+   HEAP32[i14 >> 2] = i15;
+   i14 = _luaO_pushfstring(i8, 6592, i12) | 0;
+   i15 = HEAP32[i11 >> 2] | 0;
+   _luaX_syntaxerror(i15, i14);
+  }
+  HEAP32[i12 >> 2] = i13;
+  i14 = _luaO_pushfstring(i8, 6568, i12) | 0;
+  HEAP32[i12 >> 2] = 6880;
+  i15 = i12 + 4 | 0;
+  HEAP32[i15 >> 2] = 255;
+  i15 = i12 + 8 | 0;
+  HEAP32[i15 >> 2] = i14;
+  i15 = _luaO_pushfstring(i8, 6592, i12) | 0;
+  i14 = HEAP32[i11 >> 2] | 0;
+  _luaX_syntaxerror(i14, i15);
+ }
+ if ((i10 | 0) < (i7 | 0)) {
+  i8 = i7;
+ } else {
+  i8 = i5 + 28 | 0;
+  HEAP32[i8 >> 2] = _luaM_growaux_(HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 52 >> 2] | 0, HEAP32[i8 >> 2] | 0, i9, 8, 255, 6880) | 0;
+  i8 = HEAP32[i9 >> 2] | 0;
+ }
+ i9 = i5 + 28 | 0;
+ if ((i7 | 0) < (i8 | 0)) {
+  while (1) {
+   i10 = i7 + 1 | 0;
+   HEAP32[(HEAP32[i9 >> 2] | 0) + (i7 << 3) >> 2] = 0;
+   if ((i10 | 0) < (i8 | 0)) {
+    i7 = i10;
+   } else {
+    break;
+   }
+  }
+ }
+ HEAP8[(HEAP32[i9 >> 2] | 0) + ((HEAPU8[i6] | 0) << 3) + 4 | 0] = (HEAP32[i2 >> 2] | 0) == 7 | 0;
+ HEAP8[(HEAP32[i9 >> 2] | 0) + ((HEAPU8[i6] | 0) << 3) + 5 | 0] = HEAP32[i2 + 8 >> 2];
+ HEAP32[(HEAP32[i9 >> 2] | 0) + ((HEAPU8[i6] | 0) << 3) >> 2] = i1;
+ if ((HEAP8[i1 + 5 | 0] & 3) == 0) {
+  i15 = HEAP8[i6] | 0;
+  i14 = i15 + 1 << 24 >> 24;
+  HEAP8[i6] = i14;
+  i15 = i15 & 255;
+  STACKTOP = i4;
+  return i15 | 0;
+ }
+ if ((HEAP8[i5 + 5 | 0] & 4) == 0) {
+  i15 = HEAP8[i6] | 0;
+  i14 = i15 + 1 << 24 >> 24;
+  HEAP8[i6] = i14;
+  i15 = i15 & 255;
+  STACKTOP = i4;
+  return i15 | 0;
+ }
+ _luaC_barrier_(HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 52 >> 2] | 0, i5, i1);
+ i15 = HEAP8[i6] | 0;
+ i14 = i15 + 1 << 24 >> 24;
+ HEAP8[i6] = i14;
+ i15 = i15 & 255;
+ STACKTOP = i4;
+ return i15 | 0;
+}
+function _close_func(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i6 = STACKTOP;
+ i2 = HEAP32[i1 + 52 >> 2] | 0;
+ i5 = i1 + 48 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ _luaK_ret(i4, 0, 0);
+ _leaveblock(i4);
+ i7 = i4 + 20 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i2);
+ }
+ i10 = i3 + 12 | 0;
+ i9 = i3 + 48 | 0;
+ HEAP32[i10 >> 2] = _luaM_realloc_(i2, HEAP32[i10 >> 2] | 0, HEAP32[i9 >> 2] << 2, i8 << 2) | 0;
+ HEAP32[i9 >> 2] = HEAP32[i7 >> 2];
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i2);
+ }
+ i9 = i3 + 20 | 0;
+ i10 = i3 + 52 | 0;
+ HEAP32[i9 >> 2] = _luaM_realloc_(i2, HEAP32[i9 >> 2] | 0, HEAP32[i10 >> 2] << 2, i8 << 2) | 0;
+ HEAP32[i10 >> 2] = HEAP32[i7 >> 2];
+ i8 = i4 + 32 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ if ((i7 + 1 | 0) >>> 0 > 268435455) {
+  _luaM_toobig(i2);
+ }
+ i9 = i3 + 8 | 0;
+ i10 = i3 + 44 | 0;
+ HEAP32[i9 >> 2] = _luaM_realloc_(i2, HEAP32[i9 >> 2] | 0, HEAP32[i10 >> 2] << 4, i7 << 4) | 0;
+ HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+ i8 = i4 + 36 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ if ((i7 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i2);
+ }
+ i9 = i3 + 16 | 0;
+ i10 = i3 + 56 | 0;
+ HEAP32[i9 >> 2] = _luaM_realloc_(i2, HEAP32[i9 >> 2] | 0, HEAP32[i10 >> 2] << 2, i7 << 2) | 0;
+ HEAP32[i10 >> 2] = HEAP32[i8 >> 2];
+ i7 = i4 + 44 | 0;
+ i8 = HEAP16[i7 >> 1] | 0;
+ if ((i8 + 1 | 0) >>> 0 > 357913941) {
+  _luaM_toobig(i2);
+ }
+ i10 = i3 + 24 | 0;
+ i9 = i3 + 60 | 0;
+ HEAP32[i10 >> 2] = _luaM_realloc_(i2, HEAP32[i10 >> 2] | 0, (HEAP32[i9 >> 2] | 0) * 12 | 0, i8 * 12 | 0) | 0;
+ HEAP32[i9 >> 2] = HEAP16[i7 >> 1] | 0;
+ i9 = i4 + 47 | 0;
+ i8 = i3 + 28 | 0;
+ i10 = i3 + 40 | 0;
+ HEAP32[i8 >> 2] = _luaM_realloc_(i2, HEAP32[i8 >> 2] | 0, HEAP32[i10 >> 2] << 3, HEAPU8[i9] << 3) | 0;
+ HEAP32[i10 >> 2] = HEAPU8[i9] | 0;
+ HEAP32[i5 >> 2] = HEAP32[i4 + 8 >> 2];
+ if (((HEAP32[i1 + 16 >> 2] | 0) + -288 | 0) >>> 0 < 2) {
+  i10 = HEAP32[i1 + 24 >> 2] | 0;
+  _luaX_newstring(i1, i10 + 16 | 0, HEAP32[i10 + 12 >> 2] | 0) | 0;
+ }
+ i10 = i2 + 8 | 0;
+ HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -16;
+ if ((HEAP32[(HEAP32[i2 + 12 >> 2] | 0) + 12 >> 2] | 0) <= 0) {
+  STACKTOP = i6;
+  return;
+ }
+ _luaC_step(i2);
+ STACKTOP = i6;
+ return;
+}
+function _lua_topointer(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ i5 = (i6 | 0) > 0;
+ do {
+  if (!i5) {
+   if (!((i6 | 0) < -1000999)) {
+    i7 = (HEAP32[i3 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i7 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i8 = -1001e3 - i6 | 0;
+   i9 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) != 22 ? (i7 = HEAP32[i9 >> 2] | 0, (i8 | 0) <= (HEAPU8[i7 + 6 | 0] | 0 | 0)) : 0) {
+    i7 = i7 + (i8 + -1 << 4) + 16 | 0;
+   } else {
+    i7 = 5192;
+   }
+  } else {
+   i7 = (HEAP32[i4 >> 2] | 0) + (i6 << 4) | 0;
+   i7 = i7 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i7 : 5192;
+  }
+ } while (0);
+ switch (HEAP32[i7 + 8 >> 2] & 63 | 0) {
+ case 22:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ case 2:
+ case 7:
+  {
+   do {
+    if (!i5) {
+     if (!((i6 | 0) < -1000999)) {
+      i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i6 << 4) | 0;
+      break;
+     }
+     if ((i6 | 0) == -1001e3) {
+      i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+      break;
+     }
+     i3 = -1001e3 - i6 | 0;
+     i4 = HEAP32[i4 >> 2] | 0;
+     if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+      i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+     } else {
+      i2 = 5192;
+     }
+    } else {
+     i2 = (HEAP32[i4 >> 2] | 0) + (i6 << 4) | 0;
+     i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+    }
+   } while (0);
+   i3 = HEAP32[i2 + 8 >> 2] & 15;
+   if ((i3 | 0) == 7) {
+    i9 = (HEAP32[i2 >> 2] | 0) + 24 | 0;
+    STACKTOP = i1;
+    return i9 | 0;
+   } else if ((i3 | 0) == 2) {
+    i9 = HEAP32[i2 >> 2] | 0;
+    STACKTOP = i1;
+    return i9 | 0;
+   } else {
+    i9 = 0;
+    STACKTOP = i1;
+    return i9 | 0;
+   }
+  }
+ case 8:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ case 5:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ case 38:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ case 6:
+  {
+   i9 = HEAP32[i7 >> 2] | 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ default:
+  {
+   i9 = 0;
+   STACKTOP = i1;
+   return i9 | 0;
+  }
+ }
+ return 0;
+}
+function _luaH_get(i4, i6) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, d5 = 0.0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, d11 = 0.0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i8 = i3 + 8 | 0;
+ i9 = i3;
+ i7 = i6 + 8 | 0;
+ i10 = HEAP32[i7 >> 2] & 63;
+ if ((i10 | 0) == 4) {
+  i6 = HEAP32[i6 >> 2] | 0;
+  i7 = (HEAP32[i4 + 16 >> 2] | 0) + (((1 << (HEAPU8[i4 + 7 | 0] | 0)) + -1 & HEAP32[i6 + 8 >> 2]) << 5) | 0;
+  while (1) {
+   if ((HEAP32[i7 + 24 >> 2] | 0) == 68 ? (HEAP32[i7 + 16 >> 2] | 0) == (i6 | 0) : 0) {
+    break;
+   }
+   i4 = HEAP32[i7 + 28 >> 2] | 0;
+   if ((i4 | 0) == 0) {
+    i2 = 5192;
+    i1 = 22;
+    break;
+   } else {
+    i7 = i4;
+   }
+  }
+  if ((i1 | 0) == 22) {
+   STACKTOP = i3;
+   return i2 | 0;
+  }
+  i10 = i7;
+  STACKTOP = i3;
+  return i10 | 0;
+ } else if ((i10 | 0) == 3) {
+  d11 = +HEAPF64[i6 >> 3];
+  HEAPF64[i9 >> 3] = d11 + 6755399441055744.0;
+  i9 = HEAP32[i9 >> 2] | 0;
+  d5 = +(i9 | 0);
+  if (d5 == d11) {
+   i6 = i9 + -1 | 0;
+   if (i6 >>> 0 < (HEAP32[i4 + 28 >> 2] | 0) >>> 0) {
+    i10 = (HEAP32[i4 + 12 >> 2] | 0) + (i6 << 4) | 0;
+    STACKTOP = i3;
+    return i10 | 0;
+   }
+   HEAPF64[i8 >> 3] = d5 + 1.0;
+   i6 = (HEAP32[i8 + 4 >> 2] | 0) + (HEAP32[i8 >> 2] | 0) | 0;
+   if ((i6 | 0) < 0) {
+    i7 = 0 - i6 | 0;
+    i6 = (i6 | 0) == (i7 | 0) ? 0 : i7;
+   }
+   i4 = (HEAP32[i4 + 16 >> 2] | 0) + (((i6 | 0) % ((1 << (HEAPU8[i4 + 7 | 0] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+   while (1) {
+    if ((HEAP32[i4 + 24 >> 2] | 0) == 3 ? +HEAPF64[i4 + 16 >> 3] == d5 : 0) {
+     break;
+    }
+    i6 = HEAP32[i4 + 28 >> 2] | 0;
+    if ((i6 | 0) == 0) {
+     i2 = 5192;
+     i1 = 22;
+     break;
+    } else {
+     i4 = i6;
+    }
+   }
+   if ((i1 | 0) == 22) {
+    STACKTOP = i3;
+    return i2 | 0;
+   }
+   i10 = i4;
+   STACKTOP = i3;
+   return i10 | 0;
+  }
+ } else if ((i10 | 0) == 0) {
+  i10 = 5192;
+  STACKTOP = i3;
+  return i10 | 0;
+ }
+ i8 = _mainposition(i4, i6) | 0;
+ while (1) {
+  if ((HEAP32[i8 + 24 >> 2] | 0) == (HEAP32[i7 >> 2] | 0) ? (_luaV_equalobj_(0, i8 + 16 | 0, i6) | 0) != 0 : 0) {
+   break;
+  }
+  i4 = HEAP32[i8 + 28 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   i2 = 5192;
+   i1 = 22;
+   break;
+  } else {
+   i8 = i4;
+  }
+ }
+ if ((i1 | 0) == 22) {
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ i10 = i8;
+ STACKTOP = i3;
+ return i10 | 0;
+}
+function _suffixedexp(i1, i8) {
+ i1 = i1 | 0;
+ i8 = i8 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 80 | 0;
+ i10 = i2 + 48 | 0;
+ i3 = i2 + 24 | 0;
+ i6 = i2;
+ i4 = i1 + 48 | 0;
+ i9 = HEAP32[i4 >> 2] | 0;
+ i5 = HEAP32[i1 + 4 >> 2] | 0;
+ i7 = i1 + 16 | 0;
+ i12 = HEAP32[i7 >> 2] | 0;
+ if ((i12 | 0) == 40) {
+  _luaX_next(i1);
+  _subexpr(i1, i8, 0) | 0;
+  _check_match(i1, 41, 40, i5);
+  _luaK_dischargevars(HEAP32[i4 >> 2] | 0, i8);
+  i11 = i1 + 24 | 0;
+ } else if ((i12 | 0) == 288) {
+  i11 = i1 + 24 | 0;
+  i13 = HEAP32[i11 >> 2] | 0;
+  _luaX_next(i1);
+  i12 = HEAP32[i4 >> 2] | 0;
+  if ((_singlevaraux(i12, i13, i8, 1) | 0) == 0) {
+   _singlevaraux(i12, HEAP32[i1 + 72 >> 2] | 0, i8, 1) | 0;
+   i13 = _luaK_stringK(HEAP32[i4 >> 2] | 0, i13) | 0;
+   HEAP32[i10 + 16 >> 2] = -1;
+   HEAP32[i10 + 20 >> 2] = -1;
+   HEAP32[i10 >> 2] = 4;
+   HEAP32[i10 + 8 >> 2] = i13;
+   _luaK_indexed(i12, i8, i10);
+  }
+ } else {
+  _luaX_syntaxerror(i1, 6656);
+ }
+ i10 = i6 + 16 | 0;
+ i12 = i6 + 20 | 0;
+ i13 = i6 + 8 | 0;
+ L7 : while (1) {
+  switch (HEAP32[i7 >> 2] | 0) {
+  case 46:
+   {
+    _fieldsel(i1, i8);
+    continue L7;
+   }
+  case 91:
+   {
+    _luaK_exp2anyregup(i9, i8);
+    _luaX_next(i1);
+    _subexpr(i1, i3, 0) | 0;
+    _luaK_exp2val(HEAP32[i4 >> 2] | 0, i3);
+    if ((HEAP32[i7 >> 2] | 0) != 93) {
+     i3 = 10;
+     break L7;
+    }
+    _luaX_next(i1);
+    _luaK_indexed(i9, i8, i3);
+    continue L7;
+   }
+  case 58:
+   {
+    _luaX_next(i1);
+    if ((HEAP32[i7 >> 2] | 0) != 288) {
+     i3 = 13;
+     break L7;
+    }
+    i14 = HEAP32[i11 >> 2] | 0;
+    _luaX_next(i1);
+    i14 = _luaK_stringK(HEAP32[i4 >> 2] | 0, i14) | 0;
+    HEAP32[i10 >> 2] = -1;
+    HEAP32[i12 >> 2] = -1;
+    HEAP32[i6 >> 2] = 4;
+    HEAP32[i13 >> 2] = i14;
+    _luaK_self(i9, i8, i6);
+    _funcargs(i1, i8, i5);
+    continue L7;
+   }
+  case 123:
+  case 289:
+  case 40:
+   {
+    _luaK_exp2nextreg(i9, i8);
+    _funcargs(i1, i8, i5);
+    continue L7;
+   }
+  default:
+   {
+    i3 = 16;
+    break L7;
+   }
+  }
+ }
+ if ((i3 | 0) == 10) {
+  _error_expected(i1, 93);
+ } else if ((i3 | 0) == 13) {
+  _error_expected(i1, 288);
+ } else if ((i3 | 0) == 16) {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaK_patchlist(i2, i7, i3) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i2 + 20 >> 2] | 0) == (i3 | 0)) {
+  HEAP32[i2 + 24 >> 2] = i3;
+  i3 = i2 + 28 | 0;
+  if ((i7 | 0) == -1) {
+   STACKTOP = i1;
+   return;
+  }
+  i6 = HEAP32[i3 >> 2] | 0;
+  if ((i6 | 0) == -1) {
+   HEAP32[i3 >> 2] = i7;
+   STACKTOP = i1;
+   return;
+  }
+  i5 = HEAP32[(HEAP32[i2 >> 2] | 0) + 12 >> 2] | 0;
+  while (1) {
+   i3 = i5 + (i6 << 2) | 0;
+   i4 = HEAP32[i3 >> 2] | 0;
+   i8 = (i4 >>> 14) + -131071 | 0;
+   if ((i8 | 0) == -1) {
+    break;
+   }
+   i8 = i6 + 1 + i8 | 0;
+   if ((i8 | 0) == -1) {
+    break;
+   } else {
+    i6 = i8;
+   }
+  }
+  i5 = ~i6 + i7 | 0;
+  if ((((i5 | 0) > -1 ? i5 : 0 - i5 | 0) | 0) > 131071) {
+   _luaX_syntaxerror(HEAP32[i2 + 12 >> 2] | 0, 10624);
+  }
+  HEAP32[i3 >> 2] = (i5 << 14) + 2147467264 | i4 & 16383;
+  STACKTOP = i1;
+  return;
+ }
+ if ((i7 | 0) == -1) {
+  STACKTOP = i1;
+  return;
+ }
+ i6 = HEAP32[(HEAP32[i2 >> 2] | 0) + 12 >> 2] | 0;
+ i10 = i7;
+ while (1) {
+  i7 = i6 + (i10 << 2) | 0;
+  i9 = HEAP32[i7 >> 2] | 0;
+  i8 = (i9 >>> 14) + -131071 | 0;
+  if ((i8 | 0) == -1) {
+   i8 = -1;
+  } else {
+   i8 = i10 + 1 + i8 | 0;
+  }
+  if ((i10 | 0) > 0 ? (i4 = i6 + (i10 + -1 << 2) | 0, i5 = HEAP32[i4 >> 2] | 0, (HEAP8[5584 + (i5 & 63) | 0] | 0) < 0) : 0) {
+   i12 = i4;
+   i11 = i5;
+  } else {
+   i12 = i7;
+   i11 = i9;
+  }
+  if ((i11 & 63 | 0) == 28) {
+   HEAP32[i12 >> 2] = i11 & 8372224 | i11 >>> 23 << 6 | 27;
+   i9 = ~i10 + i3 | 0;
+   if ((((i9 | 0) > -1 ? i9 : 0 - i9 | 0) | 0) > 131071) {
+    i3 = 20;
+    break;
+   }
+   i9 = HEAP32[i7 >> 2] & 16383 | (i9 << 14) + 2147467264;
+  } else {
+   i10 = ~i10 + i3 | 0;
+   if ((((i10 | 0) > -1 ? i10 : 0 - i10 | 0) | 0) > 131071) {
+    i3 = 23;
+    break;
+   }
+   i9 = i9 & 16383 | (i10 << 14) + 2147467264;
+  }
+  HEAP32[i7 >> 2] = i9;
+  if ((i8 | 0) == -1) {
+   i3 = 26;
+   break;
+  } else {
+   i10 = i8;
+  }
+ }
+ if ((i3 | 0) == 20) {
+  _luaX_syntaxerror(HEAP32[i2 + 12 >> 2] | 0, 10624);
+ } else if ((i3 | 0) == 23) {
+  _luaX_syntaxerror(HEAP32[i2 + 12 >> 2] | 0, 10624);
+ } else if ((i3 | 0) == 26) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaG_typeerror(i5, i6, i1) {
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i2;
+ i2 = i2 + 16 | 0;
+ i8 = HEAP32[i5 + 16 >> 2] | 0;
+ HEAP32[i2 >> 2] = 0;
+ i4 = HEAP32[8528 + ((HEAP32[i6 + 8 >> 2] & 15) + 1 << 2) >> 2] | 0;
+ L1 : do {
+  if (!((HEAP8[i8 + 18 | 0] & 1) == 0)) {
+   i7 = HEAP32[HEAP32[i8 >> 2] >> 2] | 0;
+   i10 = HEAP8[i7 + 6 | 0] | 0;
+   L3 : do {
+    if (!(i10 << 24 >> 24 == 0)) {
+     i9 = i7 + 16 | 0;
+     i11 = i10 & 255;
+     i10 = 0;
+     while (1) {
+      i12 = i10 + 1 | 0;
+      if ((HEAP32[(HEAP32[i9 + (i10 << 2) >> 2] | 0) + 8 >> 2] | 0) == (i6 | 0)) {
+       break;
+      }
+      if ((i12 | 0) < (i11 | 0)) {
+       i10 = i12;
+      } else {
+       break L3;
+      }
+     }
+     i9 = HEAP32[(HEAP32[(HEAP32[i7 + 12 >> 2] | 0) + 28 >> 2] | 0) + (i10 << 3) >> 2] | 0;
+     if ((i9 | 0) == 0) {
+      i9 = 2104;
+     } else {
+      i9 = i9 + 16 | 0;
+     }
+     HEAP32[i2 >> 2] = i9;
+     i11 = i9;
+     i10 = 2072;
+     HEAP32[i3 >> 2] = i1;
+     i12 = i3 + 4 | 0;
+     HEAP32[i12 >> 2] = i10;
+     i12 = i3 + 8 | 0;
+     HEAP32[i12 >> 2] = i11;
+     i12 = i3 + 12 | 0;
+     HEAP32[i12 >> 2] = i4;
+     _luaG_runerror(i5, 1840, i3);
+    }
+   } while (0);
+   i9 = HEAP32[i8 + 24 >> 2] | 0;
+   i10 = HEAP32[i8 + 4 >> 2] | 0;
+   if (i9 >>> 0 < i10 >>> 0) {
+    i12 = i9;
+    while (1) {
+     i11 = i12 + 16 | 0;
+     if ((i12 | 0) == (i6 | 0)) {
+      break;
+     }
+     if (i11 >>> 0 < i10 >>> 0) {
+      i12 = i11;
+     } else {
+      break L1;
+     }
+    }
+    i12 = HEAP32[i7 + 12 >> 2] | 0;
+    i6 = _getobjname(i12, ((HEAP32[i8 + 28 >> 2] | 0) - (HEAP32[i12 + 12 >> 2] | 0) >> 2) + -1 | 0, i6 - i9 >> 4, i2) | 0;
+    if ((i6 | 0) != 0) {
+     i11 = HEAP32[i2 >> 2] | 0;
+     i10 = i6;
+     HEAP32[i3 >> 2] = i1;
+     i12 = i3 + 4 | 0;
+     HEAP32[i12 >> 2] = i10;
+     i12 = i3 + 8 | 0;
+     HEAP32[i12 >> 2] = i11;
+     i12 = i3 + 12 | 0;
+     HEAP32[i12 >> 2] = i4;
+     _luaG_runerror(i5, 1840, i3);
+    }
+   }
+  }
+ } while (0);
+ HEAP32[i3 >> 2] = i1;
+ HEAP32[i3 + 4 >> 2] = i4;
+ _luaG_runerror(i5, 1880, i3);
+}
+function _lua_setmetatable(i1, i7) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i4 = STACKTOP;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i7 | 0) <= 0) {
+   if (!((i7 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i7 = -1001e3 - i7 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i5 = HEAP32[i6 >> 2] | 0, (i7 | 0) <= (HEAPU8[i5 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i5 + (i7 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i5 = (HEAP32[i6 >> 2] | 0) + (i7 << 4) | 0;
+   i5 = i5 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i5 : 5192;
+  }
+ } while (0);
+ i6 = i1 + 8 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ if ((HEAP32[i7 + -8 >> 2] | 0) == 0) {
+  i7 = 0;
+ } else {
+  i7 = HEAP32[i7 + -16 >> 2] | 0;
+ }
+ i8 = HEAP32[i5 + 8 >> 2] & 15;
+ if ((i8 | 0) == 5) {
+  HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] = i7;
+  if ((i7 | 0) == 0) {
+   i8 = HEAP32[i6 >> 2] | 0;
+   i8 = i8 + -16 | 0;
+   HEAP32[i6 >> 2] = i8;
+   STACKTOP = i4;
+   return 1;
+  }
+  if (!((HEAP8[i7 + 5 | 0] & 3) == 0) ? (i2 = HEAP32[i5 >> 2] | 0, !((HEAP8[i2 + 5 | 0] & 4) == 0)) : 0) {
+   _luaC_barrierback_(i1, i2);
+  }
+  _luaC_checkfinalizer(i1, HEAP32[i5 >> 2] | 0, i7);
+  i8 = HEAP32[i6 >> 2] | 0;
+  i8 = i8 + -16 | 0;
+  HEAP32[i6 >> 2] = i8;
+  STACKTOP = i4;
+  return 1;
+ } else if ((i8 | 0) == 7) {
+  HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] = i7;
+  if ((i7 | 0) == 0) {
+   i8 = HEAP32[i6 >> 2] | 0;
+   i8 = i8 + -16 | 0;
+   HEAP32[i6 >> 2] = i8;
+   STACKTOP = i4;
+   return 1;
+  }
+  if (!((HEAP8[i7 + 5 | 0] & 3) == 0) ? (i3 = HEAP32[i5 >> 2] | 0, !((HEAP8[i3 + 5 | 0] & 4) == 0)) : 0) {
+   _luaC_barrier_(i1, i3, i7);
+  }
+  _luaC_checkfinalizer(i1, HEAP32[i5 >> 2] | 0, i7);
+  i8 = HEAP32[i6 >> 2] | 0;
+  i8 = i8 + -16 | 0;
+  HEAP32[i6 >> 2] = i8;
+  STACKTOP = i4;
+  return 1;
+ } else {
+  HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + (i8 << 2) + 252 >> 2] = i7;
+  i8 = HEAP32[i6 >> 2] | 0;
+  i8 = i8 + -16 | 0;
+  HEAP32[i6 >> 2] = i8;
+  STACKTOP = i4;
+  return 1;
+ }
+ return 0;
+}
+function _recfield(i2, i10) {
+ i2 = i2 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i9 = i1 + 48 | 0;
+ i6 = i1 + 24 | 0;
+ i3 = i1;
+ i13 = i2 + 48 | 0;
+ i8 = HEAP32[i13 >> 2] | 0;
+ i5 = i8 + 48 | 0;
+ i4 = HEAP8[i5] | 0;
+ i7 = i2 + 16 | 0;
+ do {
+  if ((HEAP32[i7 >> 2] | 0) != 288) {
+   _luaX_next(i2);
+   _subexpr(i2, i6, 0) | 0;
+   _luaK_exp2val(HEAP32[i13 >> 2] | 0, i6);
+   if ((HEAP32[i7 >> 2] | 0) == 93) {
+    _luaX_next(i2);
+    i11 = i10 + 28 | 0;
+    break;
+   } else {
+    _error_expected(i2, 93);
+   }
+  } else {
+   i12 = i10 + 28 | 0;
+   if ((HEAP32[i12 >> 2] | 0) <= 2147483645) {
+    i11 = HEAP32[i2 + 24 >> 2] | 0;
+    _luaX_next(i2);
+    i11 = _luaK_stringK(HEAP32[i13 >> 2] | 0, i11) | 0;
+    HEAP32[i6 + 16 >> 2] = -1;
+    HEAP32[i6 + 20 >> 2] = -1;
+    HEAP32[i6 >> 2] = 4;
+    HEAP32[i6 + 8 >> 2] = i11;
+    i11 = i12;
+    break;
+   }
+   i14 = i8 + 12 | 0;
+   i13 = HEAP32[(HEAP32[i14 >> 2] | 0) + 52 >> 2] | 0;
+   i12 = HEAP32[(HEAP32[i8 >> 2] | 0) + 64 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    i16 = 6552;
+    HEAP32[i9 >> 2] = 6528;
+    i15 = i9 + 4 | 0;
+    HEAP32[i15 >> 2] = 2147483645;
+    i15 = i9 + 8 | 0;
+    HEAP32[i15 >> 2] = i16;
+    i15 = _luaO_pushfstring(i13, 6592, i9) | 0;
+    i16 = HEAP32[i14 >> 2] | 0;
+    _luaX_syntaxerror(i16, i15);
+   }
+   HEAP32[i9 >> 2] = i12;
+   i15 = _luaO_pushfstring(i13, 6568, i9) | 0;
+   HEAP32[i9 >> 2] = 6528;
+   i16 = i9 + 4 | 0;
+   HEAP32[i16 >> 2] = 2147483645;
+   i16 = i9 + 8 | 0;
+   HEAP32[i16 >> 2] = i15;
+   i16 = _luaO_pushfstring(i13, 6592, i9) | 0;
+   i15 = HEAP32[i14 >> 2] | 0;
+   _luaX_syntaxerror(i15, i16);
+  }
+ } while (0);
+ HEAP32[i11 >> 2] = (HEAP32[i11 >> 2] | 0) + 1;
+ if ((HEAP32[i7 >> 2] | 0) == 61) {
+  _luaX_next(i2);
+  i16 = _luaK_exp2RK(i8, i6) | 0;
+  _subexpr(i2, i3, 0) | 0;
+  i15 = HEAP32[(HEAP32[i10 + 24 >> 2] | 0) + 8 >> 2] | 0;
+  _luaK_codeABC(i8, 10, i15, i16, _luaK_exp2RK(i8, i3) | 0) | 0;
+  HEAP8[i5] = i4;
+  STACKTOP = i1;
+  return;
+ } else {
+  _error_expected(i2, 61);
+ }
+}
+function _lua_newstate(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i5 = i1 + 8 | 0;
+ i4 = i1;
+ i2 = FUNCTION_TABLE_iiiii[i3 & 3](i6, 0, 8, 400) | 0;
+ if ((i2 | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ i7 = i2 + 112 | 0;
+ HEAP32[i2 >> 2] = 0;
+ HEAP8[i2 + 4 | 0] = 8;
+ HEAP8[i2 + 172 | 0] = 33;
+ HEAP8[i2 + 5 | 0] = 1;
+ HEAP8[i2 + 174 | 0] = 0;
+ HEAP32[i2 + 12 >> 2] = i7;
+ HEAP32[i2 + 28 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ HEAP32[i2 + 32 >> 2] = 0;
+ HEAP32[i2 + 64 >> 2] = 0;
+ HEAP16[i2 + 38 >> 1] = 0;
+ HEAP32[i2 + 52 >> 2] = 0;
+ HEAP8[i2 + 40 | 0] = 0;
+ HEAP32[i2 + 44 >> 2] = 0;
+ HEAP8[i2 + 41 | 0] = 1;
+ HEAP32[i2 + 48 >> 2] = 0;
+ HEAP32[i2 + 56 >> 2] = 0;
+ HEAP16[i2 + 36 >> 1] = 1;
+ HEAP8[i2 + 6 | 0] = 0;
+ HEAP32[i2 + 68 >> 2] = 0;
+ HEAP32[i7 >> 2] = i3;
+ HEAP32[i2 + 116 >> 2] = i6;
+ HEAP32[i2 + 284 >> 2] = i2;
+ i3 = _time(0) | 0;
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i5 >> 2] = i2;
+ HEAP32[i5 + 4 >> 2] = i4;
+ HEAP32[i5 + 8 >> 2] = 5192;
+ HEAP32[i5 + 12 >> 2] = 1;
+ HEAP32[i2 + 168 >> 2] = _luaS_hash(i5, 16, i3) | 0;
+ i4 = i2 + 224 | 0;
+ HEAP32[i2 + 240 >> 2] = i4;
+ HEAP32[i2 + 244 >> 2] = i4;
+ HEAP8[i2 + 175 | 0] = 0;
+ i4 = i2 + 132 | 0;
+ HEAP32[i2 + 160 >> 2] = 0;
+ HEAP32[i2 + 256 >> 2] = 0;
+ HEAP32[i2 + 264 >> 2] = 0;
+ HEAP32[i2 + 280 >> 2] = 0;
+ HEAP32[i4 + 0 >> 2] = 0;
+ HEAP32[i4 + 4 >> 2] = 0;
+ HEAP32[i4 + 8 >> 2] = 0;
+ HEAP32[i4 + 12 >> 2] = 0;
+ HEAP32[i2 + 288 >> 2] = _lua_version(0) | 0;
+ HEAP8[i2 + 173 | 0] = 5;
+ i4 = i2 + 120 | 0;
+ i5 = i2 + 180 | 0;
+ i3 = i5 + 40 | 0;
+ do {
+  HEAP32[i5 >> 2] = 0;
+  i5 = i5 + 4 | 0;
+ } while ((i5 | 0) < (i3 | 0));
+ HEAP32[i4 >> 2] = 400;
+ HEAP32[i2 + 124 >> 2] = 0;
+ HEAP32[i2 + 268 >> 2] = 200;
+ HEAP32[i2 + 272 >> 2] = 200;
+ HEAP32[i2 + 276 >> 2] = 200;
+ i5 = i2 + 364 | 0;
+ i3 = i5 + 36 | 0;
+ do {
+  HEAP32[i5 >> 2] = 0;
+  i5 = i5 + 4 | 0;
+ } while ((i5 | 0) < (i3 | 0));
+ if ((_luaD_rawrunprotected(i2, 8, 0) | 0) == 0) {
+  i7 = i2;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ _close_state(i2);
+ i7 = 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaU_undump(i1, i7, i8, i9) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i4 = i2 + 16 | 0;
+ i5 = i2 + 34 | 0;
+ i3 = i2;
+ i6 = HEAP8[i9] | 0;
+ if (i6 << 24 >> 24 == 27) {
+  HEAP32[i3 + 12 >> 2] = 8800;
+ } else if (i6 << 24 >> 24 == 61 | i6 << 24 >> 24 == 64) {
+  HEAP32[i3 + 12 >> 2] = i9 + 1;
+ } else {
+  HEAP32[i3 + 12 >> 2] = i9;
+ }
+ HEAP32[i3 >> 2] = i1;
+ HEAP32[i3 + 4 >> 2] = i7;
+ HEAP32[i3 + 8 >> 2] = i8;
+ HEAP32[i4 >> 2] = 1635077147;
+ HEAP8[i4 + 4 | 0] = 82;
+ HEAP8[i4 + 5 | 0] = 0;
+ HEAP8[i4 + 6 | 0] = 1;
+ HEAP8[i4 + 7 | 0] = 4;
+ HEAP8[i4 + 8 | 0] = 4;
+ HEAP8[i4 + 9 | 0] = 4;
+ HEAP8[i4 + 10 | 0] = 8;
+ i9 = i4 + 12 | 0;
+ HEAP8[i4 + 11 | 0] = 0;
+ HEAP8[i9 + 0 | 0] = HEAP8[8816 | 0] | 0;
+ HEAP8[i9 + 1 | 0] = HEAP8[8817 | 0] | 0;
+ HEAP8[i9 + 2 | 0] = HEAP8[8818 | 0] | 0;
+ HEAP8[i9 + 3 | 0] = HEAP8[8819 | 0] | 0;
+ HEAP8[i9 + 4 | 0] = HEAP8[8820 | 0] | 0;
+ HEAP8[i9 + 5 | 0] = HEAP8[8821 | 0] | 0;
+ HEAP8[i5] = 27;
+ if ((_luaZ_read(i7, i5 + 1 | 0, 17) | 0) != 0) {
+  _error(i3, 8824);
+ }
+ if ((_memcmp(i4, i5, 18) | 0) == 0) {
+  i4 = _luaF_newLclosure(i1, 1) | 0;
+  i5 = i1 + 8 | 0;
+  i9 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i9 >> 2] = i4;
+  HEAP32[i9 + 8 >> 2] = 70;
+  i9 = (HEAP32[i5 >> 2] | 0) + 16 | 0;
+  HEAP32[i5 >> 2] = i9;
+  if (((HEAP32[i1 + 24 >> 2] | 0) - i9 | 0) < 16) {
+   _luaD_growstack(i1, 0);
+  }
+  i9 = _luaF_newproto(i1) | 0;
+  i6 = i4 + 12 | 0;
+  HEAP32[i6 >> 2] = i9;
+  _LoadFunction(i3, i9);
+  i6 = HEAP32[i6 >> 2] | 0;
+  i3 = HEAP32[i6 + 40 >> 2] | 0;
+  if ((i3 | 0) == 1) {
+   i9 = i4;
+   STACKTOP = i2;
+   return i9 | 0;
+  }
+  i9 = _luaF_newLclosure(i1, i3) | 0;
+  HEAP32[i9 + 12 >> 2] = i6;
+  i8 = HEAP32[i5 >> 2] | 0;
+  HEAP32[i8 + -16 >> 2] = i9;
+  HEAP32[i8 + -8 >> 2] = 70;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ if ((_memcmp(i4, i5, 4) | 0) != 0) {
+  _error(i3, 8888);
+ }
+ if ((_memcmp(i4, i5, 6) | 0) != 0) {
+  _error(i3, 8896);
+ }
+ if ((_memcmp(i4, i5, 12) | 0) == 0) {
+  _error(i3, 8872);
+ } else {
+  _error(i3, 8920);
+ }
+ return 0;
+}
+function _lua_compare(i2, i7, i5, i3) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i6 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i7 | 0) <= 0) {
+   if (!((i7 | 0) < -1000999)) {
+    i6 = (HEAP32[i2 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i6 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i7 = -1001e3 - i7 | 0;
+   i8 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i8 + 8 >> 2] | 0) != 22 ? (i6 = HEAP32[i8 >> 2] | 0, (i7 | 0) <= (HEAPU8[i6 + 6 | 0] | 0 | 0)) : 0) {
+    i6 = i6 + (i7 + -1 << 4) + 16 | 0;
+   } else {
+    i6 = 5192;
+   }
+  } else {
+   i6 = (HEAP32[i4 >> 2] | 0) + (i7 << 4) | 0;
+   i6 = i6 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i6 : 5192;
+  }
+ } while (0);
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i4 = (HEAP32[i2 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i4 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) == 22) {
+    i8 = 0;
+    STACKTOP = i1;
+    return i8 | 0;
+   }
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((i5 | 0) > (HEAPU8[i4 + 6 | 0] | 0 | 0)) {
+    i8 = 0;
+    STACKTOP = i1;
+    return i8 | 0;
+   } else {
+    i4 = i4 + (i5 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else {
+   i4 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ if ((i6 | 0) == 5192 | (i4 | 0) == 5192) {
+  i8 = 0;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ if ((i3 | 0) == 1) {
+  i8 = _luaV_lessthan(i2, i6, i4) | 0;
+  STACKTOP = i1;
+  return i8 | 0;
+ } else if ((i3 | 0) == 2) {
+  i8 = _luaV_lessequal(i2, i6, i4) | 0;
+  STACKTOP = i1;
+  return i8 | 0;
+ } else if ((i3 | 0) == 0) {
+  if ((HEAP32[i6 + 8 >> 2] | 0) == (HEAP32[i4 + 8 >> 2] | 0)) {
+   i2 = (_luaV_equalobj_(i2, i6, i4) | 0) != 0;
+  } else {
+   i2 = 0;
+  }
+  i8 = i2 & 1;
+  STACKTOP = i1;
+  return i8 | 0;
+ } else {
+  i8 = 0;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ return 0;
+}
+function _lexerror(i7, i3, i8) {
+ i7 = i7 | 0;
+ i3 = i3 | 0;
+ i8 = i8 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i12 = STACKTOP;
+ STACKTOP = STACKTOP + 80 | 0;
+ i2 = i12;
+ i12 = i12 + 12 | 0;
+ _luaO_chunkid(i12, (HEAP32[i7 + 68 >> 2] | 0) + 16 | 0, 60);
+ i1 = i7 + 52 | 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ i13 = HEAP32[i7 + 4 >> 2] | 0;
+ HEAP32[i2 >> 2] = i12;
+ HEAP32[i2 + 4 >> 2] = i13;
+ HEAP32[i2 + 8 >> 2] = i3;
+ i4 = _luaO_pushfstring(i4, 12592, i2) | 0;
+ if ((i8 | 0) == 0) {
+  i13 = HEAP32[i1 >> 2] | 0;
+  _luaD_throw(i13, 3);
+ }
+ i3 = HEAP32[i1 >> 2] | 0;
+ do {
+  if (!((i8 + -287 | 0) >>> 0 < 3)) {
+   if ((i8 | 0) >= 257) {
+    i5 = HEAP32[12096 + (i8 + -257 << 2) >> 2] | 0;
+    if ((i8 | 0) >= 286) {
+     break;
+    }
+    HEAP32[i2 >> 2] = i5;
+    i5 = _luaO_pushfstring(i3, 12256, i2) | 0;
+    break;
+   }
+   if ((HEAP8[i8 + 10913 | 0] & 4) == 0) {
+    HEAP32[i2 >> 2] = i8;
+    i5 = _luaO_pushfstring(i3, 12240, i2) | 0;
+    break;
+   } else {
+    HEAP32[i2 >> 2] = i8;
+    i5 = _luaO_pushfstring(i3, 12232, i2) | 0;
+    break;
+   }
+  } else {
+   i11 = i7 + 60 | 0;
+   i12 = HEAP32[i11 >> 2] | 0;
+   i10 = i12 + 4 | 0;
+   i13 = HEAP32[i10 >> 2] | 0;
+   i8 = i12 + 8 | 0;
+   i9 = HEAP32[i8 >> 2] | 0;
+   do {
+    if ((i13 + 1 | 0) >>> 0 > i9 >>> 0) {
+     if (i9 >>> 0 > 2147483645) {
+      _lexerror(i7, 12368, 0);
+     }
+     i7 = i9 << 1;
+     if ((i7 | 0) == -2) {
+      _luaM_toobig(i3);
+     } else {
+      i6 = _luaM_realloc_(i3, HEAP32[i12 >> 2] | 0, i9, i7) | 0;
+      HEAP32[i12 >> 2] = i6;
+      HEAP32[i8 >> 2] = i7;
+      i5 = HEAP32[i10 >> 2] | 0;
+      break;
+     }
+    } else {
+     i5 = i13;
+     i6 = HEAP32[i12 >> 2] | 0;
+    }
+   } while (0);
+   HEAP32[i10 >> 2] = i5 + 1;
+   HEAP8[i6 + i5 | 0] = 0;
+   i5 = HEAP32[i1 >> 2] | 0;
+   HEAP32[i2 >> 2] = HEAP32[HEAP32[i11 >> 2] >> 2];
+   i5 = _luaO_pushfstring(i5, 12256, i2) | 0;
+  }
+ } while (0);
+ HEAP32[i2 >> 2] = i4;
+ HEAP32[i2 + 4 >> 2] = i5;
+ _luaO_pushfstring(i3, 12608, i2) | 0;
+ i13 = HEAP32[i1 >> 2] | 0;
+ _luaD_throw(i13, 3);
+}
+function _luaV_objlen(i2, i5, i1) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i3 = STACKTOP;
+ i4 = i1 + 8 | 0;
+ i8 = HEAP32[i4 >> 2] & 15;
+ do {
+  if ((i8 | 0) == 5) {
+   i7 = HEAP32[i1 >> 2] | 0;
+   i8 = HEAP32[i7 + 8 >> 2] | 0;
+   if (((i8 | 0) != 0 ? (HEAP8[i8 + 6 | 0] & 16) == 0 : 0) ? (i6 = _luaT_gettm(i8, 4, HEAP32[(HEAP32[i2 + 12 >> 2] | 0) + 200 >> 2] | 0) | 0, (i6 | 0) != 0) : 0) {
+    i7 = i6;
+    break;
+   }
+   HEAPF64[i5 >> 3] = +(_luaH_getn(i7) | 0);
+   HEAP32[i5 + 8 >> 2] = 3;
+   STACKTOP = i3;
+   return;
+  } else if ((i8 | 0) != 4) {
+   i6 = _luaT_gettmbyobj(i2, i1, 4) | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) == 0) {
+    _luaG_typeerror(i2, i1, 9024);
+   } else {
+    i7 = i6;
+   }
+  } else {
+   HEAPF64[i5 >> 3] = +((HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) >>> 0);
+   HEAP32[i5 + 8 >> 2] = 3;
+   STACKTOP = i3;
+   return;
+  }
+ } while (0);
+ i6 = i2 + 28 | 0;
+ i8 = i5 - (HEAP32[i6 >> 2] | 0) | 0;
+ i5 = i2 + 8 | 0;
+ i11 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i11 + 16;
+ i12 = i7;
+ i10 = HEAP32[i12 + 4 >> 2] | 0;
+ i9 = i11;
+ HEAP32[i9 >> 2] = HEAP32[i12 >> 2];
+ HEAP32[i9 + 4 >> 2] = i10;
+ HEAP32[i11 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+ i7 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i7 + 16;
+ i11 = i1;
+ i9 = HEAP32[i11 + 4 >> 2] | 0;
+ i10 = i7;
+ HEAP32[i10 >> 2] = HEAP32[i11 >> 2];
+ HEAP32[i10 + 4 >> 2] = i9;
+ HEAP32[i7 + 8 >> 2] = HEAP32[i4 >> 2];
+ i7 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i7 + 16;
+ i10 = i1;
+ i9 = HEAP32[i10 + 4 >> 2] | 0;
+ i1 = i7;
+ HEAP32[i1 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i1 + 4 >> 2] = i9;
+ HEAP32[i7 + 8 >> 2] = HEAP32[i4 >> 2];
+ _luaD_call(i2, (HEAP32[i5 >> 2] | 0) + -48 | 0, 1, HEAP8[(HEAP32[i2 + 16 >> 2] | 0) + 18 | 0] & 1);
+ i7 = HEAP32[i6 >> 2] | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i2 = i6 + -16 | 0;
+ HEAP32[i5 >> 2] = i2;
+ i4 = HEAP32[i2 + 4 >> 2] | 0;
+ i5 = i7 + i8 | 0;
+ HEAP32[i5 >> 2] = HEAP32[i2 >> 2];
+ HEAP32[i5 + 4 >> 2] = i4;
+ HEAP32[i7 + (i8 + 8) >> 2] = HEAP32[i6 + -8 >> 2];
+ STACKTOP = i3;
+ return;
+}
+function _get_equalTM(i6, i5, i4) {
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i7 = 0;
+ i1 = STACKTOP;
+ L1 : do {
+  if (((i5 | 0) != 0 ? (HEAP8[i5 + 6 | 0] & 32) == 0 : 0) ? (i7 = i6 + 12 | 0, i2 = _luaT_gettm(i5, 5, HEAP32[(HEAP32[i7 >> 2] | 0) + 204 >> 2] | 0) | 0, (i2 | 0) != 0) : 0) {
+   if ((i5 | 0) != (i4 | 0)) {
+    if (((i4 | 0) != 0 ? (HEAP8[i4 + 6 | 0] & 32) == 0 : 0) ? (i3 = _luaT_gettm(i4, 5, HEAP32[(HEAP32[i7 >> 2] | 0) + 204 >> 2] | 0) | 0, (i3 | 0) != 0) : 0) {
+     i4 = HEAP32[i2 + 8 >> 2] | 0;
+     L9 : do {
+      if ((i4 | 0) == (HEAP32[i3 + 8 >> 2] | 0)) {
+       switch (i4 & 63 | 0) {
+       case 3:
+        {
+         i3 = +HEAPF64[i2 >> 3] == +HEAPF64[i3 >> 3] | 0;
+         break;
+        }
+       case 22:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       case 5:
+        {
+         if ((HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0)) {
+          break L1;
+         } else {
+          break L9;
+         }
+        }
+       case 1:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       case 4:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       case 0:
+        {
+         break L1;
+        }
+       case 7:
+        {
+         if ((HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0)) {
+          break L1;
+         } else {
+          break L9;
+         }
+        }
+       case 2:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       case 20:
+        {
+         i3 = _luaS_eqlngstr(HEAP32[i2 >> 2] | 0, HEAP32[i3 >> 2] | 0) | 0;
+         break;
+        }
+       default:
+        {
+         i3 = (HEAP32[i2 >> 2] | 0) == (HEAP32[i3 >> 2] | 0) | 0;
+        }
+       }
+       if ((i3 | 0) != 0) {
+        break L1;
+       }
+      }
+     } while (0);
+     i2 = 0;
+    } else {
+     i2 = 0;
+    }
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaS_newlstr(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ if (!(i3 >>> 0 < 41)) {
+  if ((i3 + 1 | 0) >>> 0 > 4294967277) {
+   _luaM_toobig(i2);
+  }
+  i10 = HEAP32[(HEAP32[i2 + 12 >> 2] | 0) + 56 >> 2] | 0;
+  i11 = _luaC_newobj(i2, 20, i3 + 17 | 0, 0, 0) | 0;
+  HEAP32[i11 + 12 >> 2] = i3;
+  HEAP32[i11 + 8 >> 2] = i10;
+  HEAP8[i11 + 6 | 0] = 0;
+  i10 = i11 + 16 | 0;
+  _memcpy(i10 | 0, i4 | 0, i3 | 0) | 0;
+  HEAP8[i10 + i3 | 0] = 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ i5 = HEAP32[i2 + 12 >> 2] | 0;
+ i6 = HEAP32[i5 + 56 >> 2] ^ i3;
+ i7 = (i3 >>> 5) + 1 | 0;
+ if (!(i7 >>> 0 > i3 >>> 0)) {
+  i8 = i3;
+  do {
+   i6 = (i6 << 5) + (i6 >>> 2) + (HEAPU8[i4 + (i8 + -1) | 0] | 0) ^ i6;
+   i8 = i8 - i7 | 0;
+  } while (!(i8 >>> 0 < i7 >>> 0));
+ }
+ i10 = i5 + 32 | 0;
+ i9 = HEAP32[i10 >> 2] | 0;
+ i7 = i5 + 24 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ i11 = HEAP32[i8 + ((i9 + -1 & i6) << 2) >> 2] | 0;
+ L12 : do {
+  if ((i11 | 0) != 0) {
+   while (1) {
+    if (((i6 | 0) == (HEAP32[i11 + 8 >> 2] | 0) ? (HEAP32[i11 + 12 >> 2] | 0) == (i3 | 0) : 0) ? (_memcmp(i4, i11 + 16 | 0, i3) | 0) == 0 : 0) {
+     break;
+    }
+    i11 = HEAP32[i11 >> 2] | 0;
+    if ((i11 | 0) == 0) {
+     break L12;
+    }
+   }
+   i2 = i11 + 5 | 0;
+   i3 = (HEAPU8[i2] | 0) ^ 3;
+   if ((((HEAPU8[i5 + 60 | 0] | 0) ^ 3) & i3 | 0) != 0) {
+    STACKTOP = i1;
+    return i11 | 0;
+   }
+   HEAP8[i2] = i3;
+   STACKTOP = i1;
+   return i11 | 0;
+  }
+ } while (0);
+ i5 = i5 + 28 | 0;
+ if ((HEAP32[i5 >> 2] | 0) >>> 0 >= i9 >>> 0 & (i9 | 0) < 1073741823) {
+  _luaS_resize(i2, i9 << 1);
+  i9 = HEAP32[i10 >> 2] | 0;
+  i8 = HEAP32[i7 >> 2] | 0;
+ }
+ i11 = _luaC_newobj(i2, 4, i3 + 17 | 0, i8 + ((i9 + -1 & i6) << 2) | 0, 0) | 0;
+ HEAP32[i11 + 12 >> 2] = i3;
+ HEAP32[i11 + 8 >> 2] = i6;
+ HEAP8[i11 + 6 | 0] = 0;
+ i10 = i11 + 16 | 0;
+ _memcpy(i10 | 0, i4 | 0, i3 | 0) | 0;
+ HEAP8[i10 + i3 | 0] = 0;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+ STACKTOP = i1;
+ return i11 | 0;
+}
+function _lua_pcallk(i3, i7, i2, i9, i6, i5) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i2 = i2 | 0;
+ i9 = i9 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i4 = 0, i8 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i1;
+ if ((i9 | 0) == 0) {
+  i9 = 0;
+ } else {
+  i10 = HEAP32[i3 + 16 >> 2] | 0;
+  do {
+   if ((i9 | 0) <= 0) {
+    if (!((i9 | 0) < -1000999)) {
+     i8 = (HEAP32[i3 + 8 >> 2] | 0) + (i9 << 4) | 0;
+     break;
+    }
+    if ((i9 | 0) == -1001e3) {
+     i8 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+     break;
+    }
+    i9 = -1001e3 - i9 | 0;
+    i10 = HEAP32[i10 >> 2] | 0;
+    if ((HEAP32[i10 + 8 >> 2] | 0) != 22 ? (i8 = HEAP32[i10 >> 2] | 0, (i9 | 0) <= (HEAPU8[i8 + 6 | 0] | 0)) : 0) {
+     i8 = i8 + (i9 + -1 << 4) + 16 | 0;
+    } else {
+     i8 = 5192;
+    }
+   } else {
+    i8 = (HEAP32[i10 >> 2] | 0) + (i9 << 4) | 0;
+    i8 = i8 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i8 : 5192;
+   }
+  } while (0);
+  i9 = i8 - (HEAP32[i3 + 28 >> 2] | 0) | 0;
+ }
+ i8 = i3 + 8 | 0;
+ i7 = (HEAP32[i8 >> 2] | 0) + (~i7 << 4) | 0;
+ HEAP32[i4 >> 2] = i7;
+ if ((i5 | 0) != 0 ? (HEAP16[i3 + 36 >> 1] | 0) == 0 : 0) {
+  i11 = HEAP32[i3 + 16 >> 2] | 0;
+  HEAP32[i11 + 28 >> 2] = i5;
+  HEAP32[i11 + 24 >> 2] = i6;
+  HEAP32[i11 + 20 >> 2] = (HEAP32[i4 >> 2] | 0) - (HEAP32[i3 + 28 >> 2] | 0);
+  HEAP8[i11 + 36 | 0] = HEAP8[i3 + 41 | 0] | 0;
+  i10 = i3 + 68 | 0;
+  i7 = i11 + 32 | 0;
+  HEAP32[i7 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i10 >> 2] = i9;
+  i9 = i11 + 18 | 0;
+  HEAP8[i9] = HEAPU8[i9] | 16;
+  _luaD_call(i3, HEAP32[i4 >> 2] | 0, i2, 1);
+  HEAP8[i9] = HEAP8[i9] & 239;
+  HEAP32[i10 >> 2] = HEAP32[i7 >> 2];
+  i4 = 0;
+ } else {
+  HEAP32[i4 + 4 >> 2] = i2;
+  i4 = _luaD_pcall(i3, 3, i4, i7 - (HEAP32[i3 + 28 >> 2] | 0) | 0, i9) | 0;
+ }
+ if (!((i2 | 0) == -1)) {
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i2 = (HEAP32[i3 + 16 >> 2] | 0) + 4 | 0;
+ i3 = HEAP32[i8 >> 2] | 0;
+ if (!((HEAP32[i2 >> 2] | 0) >>> 0 < i3 >>> 0)) {
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ HEAP32[i2 >> 2] = i3;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _lua_getupvalue(i1, i6, i3) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i5 = HEAP32[i4 + 8 >> 2] & 63;
+ do {
+  if ((i5 | 0) == 38) {
+   i5 = HEAP32[i4 >> 2] | 0;
+   if ((i3 | 0) <= 0) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   if ((HEAPU8[i5 + 6 | 0] | 0 | 0) < (i3 | 0)) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   } else {
+    i4 = 936;
+    i3 = i5 + (i3 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else if ((i5 | 0) == 6) {
+   i5 = HEAP32[i4 >> 2] | 0;
+   i4 = HEAP32[i5 + 12 >> 2] | 0;
+   if ((i3 | 0) <= 0) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   if ((HEAP32[i4 + 40 >> 2] | 0) < (i3 | 0)) {
+    i6 = 0;
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+   i6 = i3 + -1 | 0;
+   i3 = HEAP32[(HEAP32[i5 + 16 + (i6 << 2) >> 2] | 0) + 8 >> 2] | 0;
+   i4 = HEAP32[(HEAP32[i4 + 28 >> 2] | 0) + (i6 << 3) >> 2] | 0;
+   if ((i4 | 0) == 0) {
+    i4 = 936;
+   } else {
+    i4 = i4 + 16 | 0;
+   }
+  } else {
+   i6 = 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ } while (0);
+ i6 = i1 + 8 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ i8 = i3;
+ i7 = HEAP32[i8 + 4 >> 2] | 0;
+ i1 = i5;
+ HEAP32[i1 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i1 + 4 >> 2] = i7;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 16;
+ i6 = i4;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _lua_copy(i1, i8, i4) {
+ i1 = i1 | 0;
+ i8 = i8 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 16 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ do {
+  if ((i8 | 0) <= 0) {
+   if (!((i8 | 0) < -1000999)) {
+    i7 = (HEAP32[i1 + 8 >> 2] | 0) + (i8 << 4) | 0;
+    break;
+   }
+   if ((i8 | 0) == -1001e3) {
+    i7 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i8 = -1001e3 - i8 | 0;
+   i9 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) != 22 ? (i7 = HEAP32[i9 >> 2] | 0, (i8 | 0) <= (HEAPU8[i7 + 6 | 0] | 0 | 0)) : 0) {
+    i7 = i7 + (i8 + -1 << 4) + 16 | 0;
+   } else {
+    i7 = 5192;
+   }
+  } else {
+   i7 = (HEAP32[i6 >> 2] | 0) + (i8 << 4) | 0;
+   i7 = i7 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i7 : 5192;
+  }
+ } while (0);
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i8 = -1001e3 - i4 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i5 = HEAP32[i6 >> 2] | 0, (i8 | 0) <= (HEAPU8[i5 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i5 + (i8 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i5 = (HEAP32[i6 >> 2] | 0) + (i4 << 4) | 0;
+   i5 = i5 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i5 : 5192;
+  }
+ } while (0);
+ i8 = i7;
+ i9 = HEAP32[i8 + 4 >> 2] | 0;
+ i6 = i5;
+ HEAP32[i6 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i6 + 4 >> 2] = i9;
+ i6 = i7 + 8 | 0;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i6 >> 2];
+ if (!((i4 | 0) < -1001e3)) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[i6 >> 2] & 64 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP32[i7 >> 2] | 0;
+ if ((HEAP8[i4 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = HEAP32[HEAP32[HEAP32[i3 >> 2] >> 2] >> 2] | 0;
+ if ((HEAP8[i3 + 5 | 0] & 4) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaC_barrier_(i1, i3, i4);
+ STACKTOP = i2;
+ return;
+}
+function _lua_tolstring(i4, i5, i1) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i7 = i4 + 16 | 0;
+ i10 = HEAP32[i7 >> 2] | 0;
+ i6 = (i5 | 0) > 0;
+ do {
+  if (!i6) {
+   if (!((i5 | 0) < -1000999)) {
+    i8 = (HEAP32[i4 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i8 = (HEAP32[i4 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i9 = -1001e3 - i5 | 0;
+   i10 = HEAP32[i10 >> 2] | 0;
+   if ((HEAP32[i10 + 8 >> 2] | 0) != 22 ? (i8 = HEAP32[i10 >> 2] | 0, (i9 | 0) <= (HEAPU8[i8 + 6 | 0] | 0 | 0)) : 0) {
+    i8 = i8 + (i9 + -1 << 4) + 16 | 0;
+   } else {
+    i8 = 5192;
+   }
+  } else {
+   i8 = (HEAP32[i10 >> 2] | 0) + (i5 << 4) | 0;
+   i8 = i8 >>> 0 < (HEAP32[i4 + 8 >> 2] | 0) >>> 0 ? i8 : 5192;
+  }
+ } while (0);
+ do {
+  if ((HEAP32[i8 + 8 >> 2] & 15 | 0) != 4) {
+   if ((_luaV_tostring(i4, i8) | 0) == 0) {
+    if ((i1 | 0) == 0) {
+     i10 = 0;
+     STACKTOP = i2;
+     return i10 | 0;
+    }
+    HEAP32[i1 >> 2] = 0;
+    i10 = 0;
+    STACKTOP = i2;
+    return i10 | 0;
+   }
+   i8 = i4 + 12 | 0;
+   if ((HEAP32[(HEAP32[i8 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+    _luaC_step(i4);
+   }
+   i7 = HEAP32[i7 >> 2] | 0;
+   if (i6) {
+    i3 = (HEAP32[i7 >> 2] | 0) + (i5 << 4) | 0;
+    i8 = i3 >>> 0 < (HEAP32[i4 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+    break;
+   }
+   if (!((i5 | 0) < -1000999)) {
+    i8 = (HEAP32[i4 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i8 = (HEAP32[i8 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i5 | 0;
+   i5 = HEAP32[i7 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i8 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i8 = 5192;
+   }
+  }
+ } while (0);
+ i3 = HEAP32[i8 >> 2] | 0;
+ if ((i1 | 0) != 0) {
+  HEAP32[i1 >> 2] = HEAP32[i3 + 12 >> 2];
+ }
+ i10 = i3 + 16 | 0;
+ STACKTOP = i2;
+ return i10 | 0;
+}
+function _luaD_pcall(i3, i6, i5, i13, i14) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i13 = i13 | 0;
+ i14 = i14 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0;
+ i1 = STACKTOP;
+ i10 = i3 + 16 | 0;
+ i11 = HEAP32[i10 >> 2] | 0;
+ i12 = i3 + 41 | 0;
+ i7 = HEAP8[i12] | 0;
+ i9 = i3 + 36 | 0;
+ i8 = HEAP16[i9 >> 1] | 0;
+ i4 = i3 + 68 | 0;
+ i2 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = i14;
+ i5 = _luaD_rawrunprotected(i3, i6, i5) | 0;
+ if ((i5 | 0) == 0) {
+  HEAP32[i4 >> 2] = i2;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i6 = i3 + 28 | 0;
+ i14 = HEAP32[i6 >> 2] | 0;
+ i15 = i14 + i13 | 0;
+ _luaF_close(i3, i15);
+ if ((i5 | 0) == 6) {
+  i16 = _luaS_newlstr(i3, 2424, 23) | 0;
+  HEAP32[i15 >> 2] = i16;
+  HEAP32[i14 + (i13 + 8) >> 2] = HEAPU8[i16 + 4 | 0] | 0 | 64;
+ } else if ((i5 | 0) == 4) {
+  i16 = HEAP32[(HEAP32[i3 + 12 >> 2] | 0) + 180 >> 2] | 0;
+  HEAP32[i15 >> 2] = i16;
+  HEAP32[i14 + (i13 + 8) >> 2] = HEAPU8[i16 + 4 | 0] | 0 | 64;
+ } else {
+  i16 = HEAP32[i3 + 8 >> 2] | 0;
+  i18 = i16 + -16 | 0;
+  i17 = HEAP32[i18 + 4 >> 2] | 0;
+  HEAP32[i15 >> 2] = HEAP32[i18 >> 2];
+  HEAP32[i15 + 4 >> 2] = i17;
+  HEAP32[i14 + (i13 + 8) >> 2] = HEAP32[i16 + -8 >> 2];
+ }
+ i13 = i14 + (i13 + 16) | 0;
+ HEAP32[i3 + 8 >> 2] = i13;
+ HEAP32[i10 >> 2] = i11;
+ HEAP8[i12] = i7;
+ HEAP16[i9 >> 1] = i8;
+ if ((i11 | 0) != 0) {
+  do {
+   i7 = HEAP32[i11 + 4 >> 2] | 0;
+   i13 = i13 >>> 0 < i7 >>> 0 ? i7 : i13;
+   i11 = HEAP32[i11 + 8 >> 2] | 0;
+  } while ((i11 | 0) != 0);
+ }
+ i6 = i13 - (HEAP32[i6 >> 2] | 0) | 0;
+ i7 = (i6 >> 4) + 1 | 0;
+ i7 = ((i7 | 0) / 8 | 0) + 10 + i7 | 0;
+ i7 = (i7 | 0) > 1e6 ? 1e6 : i7;
+ if ((i6 | 0) > 15999984) {
+  HEAP32[i4 >> 2] = i2;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ if ((i7 | 0) >= (HEAP32[i3 + 32 >> 2] | 0)) {
+  HEAP32[i4 >> 2] = i2;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ _luaD_reallocstack(i3, i7);
+ HEAP32[i4 >> 2] = i2;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _luaH_resize(i1, i4, i6, i9) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0;
+ i3 = STACKTOP;
+ i8 = i4 + 28 | 0;
+ i5 = HEAP32[i8 >> 2] | 0;
+ i7 = HEAPU8[i4 + 7 | 0] | 0;
+ i2 = HEAP32[i4 + 16 >> 2] | 0;
+ if ((i5 | 0) < (i6 | 0)) {
+  if ((i6 + 1 | 0) >>> 0 > 268435455) {
+   _luaM_toobig(i1);
+  }
+  i11 = i4 + 12 | 0;
+  i10 = _luaM_realloc_(i1, HEAP32[i11 >> 2] | 0, i5 << 4, i6 << 4) | 0;
+  HEAP32[i11 >> 2] = i10;
+  i11 = HEAP32[i8 >> 2] | 0;
+  if ((i11 | 0) < (i6 | 0)) {
+   do {
+    HEAP32[i10 + (i11 << 4) + 8 >> 2] = 0;
+    i11 = i11 + 1 | 0;
+   } while ((i11 | 0) != (i6 | 0));
+  }
+  HEAP32[i8 >> 2] = i6;
+ }
+ _setnodevector(i1, i4, i9);
+ do {
+  if ((i5 | 0) > (i6 | 0)) {
+   HEAP32[i8 >> 2] = i6;
+   i8 = i4 + 12 | 0;
+   i9 = i6;
+   do {
+    i10 = HEAP32[i8 >> 2] | 0;
+    if ((HEAP32[i10 + (i9 << 4) + 8 >> 2] | 0) == 0) {
+     i9 = i9 + 1 | 0;
+    } else {
+     i11 = i9 + 1 | 0;
+     _luaH_setint(i1, i4, i11, i10 + (i9 << 4) | 0);
+     i9 = i11;
+    }
+   } while ((i9 | 0) != (i5 | 0));
+   if ((i6 + 1 | 0) >>> 0 > 268435455) {
+    _luaM_toobig(i1);
+   } else {
+    i11 = i4 + 12 | 0;
+    HEAP32[i11 >> 2] = _luaM_realloc_(i1, HEAP32[i11 >> 2] | 0, i5 << 4, i6 << 4) | 0;
+    break;
+   }
+  }
+ } while (0);
+ i5 = 1 << i7;
+ if ((i5 | 0) > 0) {
+  i6 = i5;
+  do {
+   i6 = i6 + -1 | 0;
+   i7 = i2 + (i6 << 5) + 8 | 0;
+   if ((HEAP32[i7 >> 2] | 0) != 0) {
+    i8 = i2 + (i6 << 5) + 16 | 0;
+    i9 = _luaH_get(i4, i8) | 0;
+    if ((i9 | 0) == 5192) {
+     i9 = _luaH_newkey(i1, i4, i8) | 0;
+    }
+    i8 = i2 + (i6 << 5) | 0;
+    i10 = HEAP32[i8 + 4 >> 2] | 0;
+    i11 = i9;
+    HEAP32[i11 >> 2] = HEAP32[i8 >> 2];
+    HEAP32[i11 + 4 >> 2] = i10;
+    HEAP32[i9 + 8 >> 2] = HEAP32[i7 >> 2];
+   }
+  } while ((i6 | 0) > 0);
+ }
+ if ((i2 | 0) == 8016) {
+  STACKTOP = i3;
+  return;
+ }
+ _luaM_realloc_(i1, i2, i5 << 5, 0) | 0;
+ STACKTOP = i3;
+ return;
+}
+function _codearith(i4, i3, i2, i6, i5) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, d13 = 0.0;
+ i7 = STACKTOP;
+ if (((((((HEAP32[i2 >> 2] | 0) == 5 ? (HEAP32[i2 + 16 >> 2] | 0) == -1 : 0) ? (HEAP32[i2 + 20 >> 2] | 0) == -1 : 0) ? (HEAP32[i6 >> 2] | 0) == 5 : 0) ? (HEAP32[i6 + 16 >> 2] | 0) == -1 : 0) ? (HEAP32[i6 + 20 >> 2] | 0) == -1 : 0) ? (d13 = +HEAPF64[i6 + 8 >> 3], !((i3 & -2 | 0) == 16 & d13 == 0.0)) : 0) {
+  i12 = i2 + 8 | 0;
+  HEAPF64[i12 >> 3] = +_luaO_arith(i3 + -13 | 0, +HEAPF64[i12 >> 3], d13);
+  STACKTOP = i7;
+  return;
+ }
+ if ((i3 | 0) == 19 | (i3 | 0) == 21) {
+  i11 = 0;
+ } else {
+  i11 = _luaK_exp2RK(i4, i6) | 0;
+ }
+ i12 = _luaK_exp2RK(i4, i2) | 0;
+ if ((i12 | 0) > (i11 | 0)) {
+  if (((HEAP32[i2 >> 2] | 0) == 6 ? (i8 = HEAP32[i2 + 8 >> 2] | 0, (i8 & 256 | 0) == 0) : 0) ? (HEAPU8[i4 + 46 | 0] | 0 | 0) <= (i8 | 0) : 0) {
+   i10 = i4 + 48 | 0;
+   HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+  }
+  if (((HEAP32[i6 >> 2] | 0) == 6 ? (i1 = HEAP32[i6 + 8 >> 2] | 0, (i1 & 256 | 0) == 0) : 0) ? (HEAPU8[i4 + 46 | 0] | 0 | 0) <= (i1 | 0) : 0) {
+   i10 = i4 + 48 | 0;
+   HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+  }
+ } else {
+  if (((HEAP32[i6 >> 2] | 0) == 6 ? (i10 = HEAP32[i6 + 8 >> 2] | 0, (i10 & 256 | 0) == 0) : 0) ? (HEAPU8[i4 + 46 | 0] | 0 | 0) <= (i10 | 0) : 0) {
+   i10 = i4 + 48 | 0;
+   HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+  }
+  if (((HEAP32[i2 >> 2] | 0) == 6 ? (i9 = HEAP32[i2 + 8 >> 2] | 0, (i9 & 256 | 0) == 0) : 0) ? (HEAPU8[i4 + 46 | 0] | 0 | 0) <= (i9 | 0) : 0) {
+   i10 = i4 + 48 | 0;
+   HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+  }
+ }
+ HEAP32[i2 + 8 >> 2] = _luaK_code(i4, i11 << 14 | i3 | i12 << 23) | 0;
+ HEAP32[i2 >> 2] = 11;
+ HEAP32[(HEAP32[(HEAP32[i4 >> 2] | 0) + 20 >> 2] | 0) + ((HEAP32[i4 + 20 >> 2] | 0) + -1 << 2) >> 2] = i5;
+ STACKTOP = i7;
+ return;
+}
+function _GCTM(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i2 = i4 + 16 | 0;
+ i5 = i4;
+ i6 = HEAP32[i1 + 12 >> 2] | 0;
+ i9 = i6 + 104 | 0;
+ i8 = HEAP32[i9 >> 2] | 0;
+ HEAP32[i9 >> 2] = HEAP32[i8 >> 2];
+ i9 = i6 + 68 | 0;
+ HEAP32[i8 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i9 >> 2] = i8;
+ i9 = i8 + 5 | 0;
+ i7 = HEAPU8[i9] | 0;
+ HEAP8[i9] = i7 & 239;
+ if ((HEAPU8[i6 + 61 | 0] | 0) >= 2) {
+  HEAP8[i9] = HEAP8[i6 + 60 | 0] & 3 | i7 & 168;
+ }
+ HEAP32[i5 >> 2] = i8;
+ i7 = i5 + 8 | 0;
+ HEAP32[i7 >> 2] = HEAPU8[i8 + 4 | 0] | 0 | 64;
+ i8 = _luaT_gettmbyobj(i1, i5, 2) | 0;
+ if ((i8 | 0) == 0) {
+  STACKTOP = i4;
+  return;
+ }
+ i9 = i8 + 8 | 0;
+ if ((HEAP32[i9 >> 2] & 15 | 0) != 6) {
+  STACKTOP = i4;
+  return;
+ }
+ i12 = i1 + 41 | 0;
+ i13 = HEAP8[i12] | 0;
+ i10 = i6 + 63 | 0;
+ i11 = HEAP8[i10] | 0;
+ HEAP8[i12] = 0;
+ HEAP8[i10] = 0;
+ i6 = i1 + 8 | 0;
+ i14 = HEAP32[i6 >> 2] | 0;
+ i16 = i8;
+ i15 = HEAP32[i16 + 4 >> 2] | 0;
+ i8 = i14;
+ HEAP32[i8 >> 2] = HEAP32[i16 >> 2];
+ HEAP32[i8 + 4 >> 2] = i15;
+ HEAP32[i14 + 8 >> 2] = HEAP32[i9 >> 2];
+ i9 = HEAP32[i6 >> 2] | 0;
+ i14 = i5;
+ i8 = HEAP32[i14 + 4 >> 2] | 0;
+ i5 = i9 + 16 | 0;
+ HEAP32[i5 >> 2] = HEAP32[i14 >> 2];
+ HEAP32[i5 + 4 >> 2] = i8;
+ HEAP32[i9 + 24 >> 2] = HEAP32[i7 >> 2];
+ i5 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i5 + 32;
+ i5 = _luaD_pcall(i1, 7, 0, i5 - (HEAP32[i1 + 28 >> 2] | 0) | 0, 0) | 0;
+ HEAP8[i12] = i13;
+ HEAP8[i10] = i11;
+ if ((i5 | 0) == 0 | (i3 | 0) == 0) {
+  STACKTOP = i4;
+  return;
+ }
+ if ((i5 | 0) != 2) {
+  i16 = i5;
+  _luaD_throw(i1, i16);
+ }
+ i3 = HEAP32[i6 >> 2] | 0;
+ if ((HEAP32[i3 + -8 >> 2] & 15 | 0) == 4) {
+  i3 = (HEAP32[i3 + -16 >> 2] | 0) + 16 | 0;
+ } else {
+  i3 = 2528;
+ }
+ HEAP32[i2 >> 2] = i3;
+ _luaO_pushfstring(i1, 2544, i2) | 0;
+ i16 = 5;
+ _luaD_throw(i1, i16);
+}
+function _lua_gc(i3, i5, i4) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i3 + 12 >> 2] | 0;
+ L1 : do {
+  switch (i5 | 0) {
+  case 8:
+   {
+    i5 = i2 + 160 | 0;
+    i2 = HEAP32[i5 >> 2] | 0;
+    HEAP32[i5 >> 2] = i4;
+    break;
+   }
+  case 11:
+   {
+    _luaC_changemode(i3, 0);
+    i2 = 0;
+    break;
+   }
+  case 2:
+   {
+    _luaC_fullgc(i3, 0);
+    i2 = 0;
+    break;
+   }
+  case 5:
+   {
+    if ((HEAP8[i2 + 62 | 0] | 0) == 2) {
+     i2 = (HEAP32[i2 + 20 >> 2] | 0) == 0 | 0;
+     _luaC_forcestep(i3);
+     break L1;
+    }
+    i4 = (i4 << 10) + -1600 | 0;
+    if ((HEAP8[i2 + 63 | 0] | 0) == 0) {
+     i5 = i4;
+     _luaE_setdebt(i2, i5);
+     _luaC_forcestep(i3);
+     i5 = i2 + 61 | 0;
+     i5 = HEAP8[i5] | 0;
+     i5 = i5 << 24 >> 24 == 5;
+     i5 = i5 & 1;
+     STACKTOP = i1;
+     return i5 | 0;
+    }
+    i5 = (HEAP32[i2 + 12 >> 2] | 0) + i4 | 0;
+    _luaE_setdebt(i2, i5);
+    _luaC_forcestep(i3);
+    i5 = i2 + 61 | 0;
+    i5 = HEAP8[i5] | 0;
+    i5 = i5 << 24 >> 24 == 5;
+    i5 = i5 & 1;
+    STACKTOP = i1;
+    return i5 | 0;
+   }
+  case 4:
+   {
+    i2 = (HEAP32[i2 + 12 >> 2] | 0) + (HEAP32[i2 + 8 >> 2] | 0) & 1023;
+    break;
+   }
+  case 1:
+   {
+    _luaE_setdebt(i2, 0);
+    HEAP8[i2 + 63 | 0] = 1;
+    i2 = 0;
+    break;
+   }
+  case 3:
+   {
+    i2 = ((HEAP32[i2 + 12 >> 2] | 0) + (HEAP32[i2 + 8 >> 2] | 0) | 0) >>> 10;
+    break;
+   }
+  case 7:
+   {
+    i5 = i2 + 164 | 0;
+    i2 = HEAP32[i5 >> 2] | 0;
+    HEAP32[i5 >> 2] = i4;
+    break;
+   }
+  case 0:
+   {
+    HEAP8[i2 + 63 | 0] = 0;
+    i2 = 0;
+    break;
+   }
+  case 6:
+   {
+    i5 = i2 + 156 | 0;
+    i2 = HEAP32[i5 >> 2] | 0;
+    HEAP32[i5 >> 2] = i4;
+    break;
+   }
+  case 9:
+   {
+    i2 = HEAPU8[i2 + 63 | 0] | 0;
+    break;
+   }
+  case 10:
+   {
+    _luaC_changemode(i3, 2);
+    i2 = 0;
+    break;
+   }
+  default:
+   {
+    i2 = -1;
+   }
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _os_time(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i4 = i2;
+ i5 = i2 + 48 | 0;
+ i3 = i2 + 4 | 0;
+ if ((_lua_type(i1, 1) | 0) < 1) {
+  i3 = _time(0) | 0;
+ } else {
+  _luaL_checktype(i1, 1, 5);
+  _lua_settop(i1, 1);
+  _lua_getfield(i1, -1, 5864);
+  i6 = _lua_tointegerx(i1, -1, i4) | 0;
+  i6 = (HEAP32[i4 >> 2] | 0) == 0 ? 0 : i6;
+  _lua_settop(i1, -2);
+  HEAP32[i3 >> 2] = i6;
+  _lua_getfield(i1, -1, 5872);
+  i6 = _lua_tointegerx(i1, -1, i4) | 0;
+  i6 = (HEAP32[i4 >> 2] | 0) == 0 ? 0 : i6;
+  _lua_settop(i1, -2);
+  HEAP32[i3 + 4 >> 2] = i6;
+  _lua_getfield(i1, -1, 5880);
+  i6 = _lua_tointegerx(i1, -1, i4) | 0;
+  i6 = (HEAP32[i4 >> 2] | 0) == 0 ? 12 : i6;
+  _lua_settop(i1, -2);
+  HEAP32[i3 + 8 >> 2] = i6;
+  _lua_getfield(i1, -1, 5888);
+  i6 = _lua_tointegerx(i1, -1, i5) | 0;
+  if ((HEAP32[i5 >> 2] | 0) == 0) {
+   HEAP32[i4 >> 2] = 5888;
+   i6 = _luaL_error(i1, 5920, i4) | 0;
+  } else {
+   _lua_settop(i1, -2);
+  }
+  HEAP32[i3 + 12 >> 2] = i6;
+  _lua_getfield(i1, -1, 5896);
+  i6 = _lua_tointegerx(i1, -1, i5) | 0;
+  if ((HEAP32[i5 >> 2] | 0) == 0) {
+   HEAP32[i4 >> 2] = 5896;
+   i6 = _luaL_error(i1, 5920, i4) | 0;
+  } else {
+   _lua_settop(i1, -2);
+  }
+  HEAP32[i3 + 16 >> 2] = i6 + -1;
+  _lua_getfield(i1, -1, 5904);
+  i6 = _lua_tointegerx(i1, -1, i5) | 0;
+  if ((HEAP32[i5 >> 2] | 0) == 0) {
+   HEAP32[i4 >> 2] = 5904;
+   i6 = _luaL_error(i1, 5920, i4) | 0;
+  } else {
+   _lua_settop(i1, -2);
+  }
+  HEAP32[i3 + 20 >> 2] = i6 + -1900;
+  _lua_getfield(i1, -1, 5912);
+  if ((_lua_type(i1, -1) | 0) == 0) {
+   i4 = -1;
+  } else {
+   i4 = _lua_toboolean(i1, -1) | 0;
+  }
+  _lua_settop(i1, -2);
+  HEAP32[i3 + 32 >> 2] = i4;
+  i3 = _mktime(i3 | 0) | 0;
+ }
+ if ((i3 | 0) == -1) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  _lua_pushnumber(i1, +(i3 | 0));
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _addk(i6, i4, i3) {
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i10 = i1;
+ i2 = HEAP32[(HEAP32[i6 + 12 >> 2] | 0) + 52 >> 2] | 0;
+ i8 = _luaH_set(i2, HEAP32[i6 + 4 >> 2] | 0, i4) | 0;
+ i4 = HEAP32[i6 >> 2] | 0;
+ i9 = i8 + 8 | 0;
+ if (((HEAP32[i9 >> 2] | 0) == 3 ? (HEAPF64[i10 >> 3] = +HEAPF64[i8 >> 3] + 6755399441055744.0, i7 = HEAP32[i10 >> 2] | 0, i5 = HEAP32[i4 + 8 >> 2] | 0, (HEAP32[i5 + (i7 << 4) + 8 >> 2] | 0) == (HEAP32[i3 + 8 >> 2] | 0)) : 0) ? (_luaV_equalobj_(0, i5 + (i7 << 4) | 0, i3) | 0) != 0 : 0) {
+  i10 = i7;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i5 = i4 + 44 | 0;
+ i10 = HEAP32[i5 >> 2] | 0;
+ i7 = i6 + 32 | 0;
+ i6 = HEAP32[i7 >> 2] | 0;
+ HEAPF64[i8 >> 3] = +(i6 | 0);
+ HEAP32[i9 >> 2] = 3;
+ i9 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) >= (i9 | 0)) {
+  i9 = i4 + 8 | 0;
+  HEAP32[i9 >> 2] = _luaM_growaux_(i2, HEAP32[i9 >> 2] | 0, i5, 16, 67108863, 10600) | 0;
+  i9 = HEAP32[i5 >> 2] | 0;
+ }
+ i8 = HEAP32[i4 + 8 >> 2] | 0;
+ if ((i10 | 0) < (i9 | 0)) {
+  while (1) {
+   i9 = i10 + 1 | 0;
+   HEAP32[i8 + (i10 << 4) + 8 >> 2] = 0;
+   if ((i9 | 0) < (HEAP32[i5 >> 2] | 0)) {
+    i10 = i9;
+   } else {
+    break;
+   }
+  }
+ }
+ i5 = i3;
+ i9 = HEAP32[i5 + 4 >> 2] | 0;
+ i10 = i8 + (i6 << 4) | 0;
+ HEAP32[i10 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i10 + 4 >> 2] = i9;
+ i10 = i3 + 8 | 0;
+ HEAP32[i8 + (i6 << 4) + 8 >> 2] = HEAP32[i10 >> 2];
+ HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + 1;
+ if ((HEAP32[i10 >> 2] & 64 | 0) == 0) {
+  i10 = i6;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i3 = HEAP32[i3 >> 2] | 0;
+ if ((HEAP8[i3 + 5 | 0] & 3) == 0) {
+  i10 = i6;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ if ((HEAP8[i4 + 5 | 0] & 4) == 0) {
+  i10 = i6;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ _luaC_barrier_(i2, i4, i3);
+ i10 = i6;
+ STACKTOP = i1;
+ return i10 | 0;
+}
+function _singlevaraux(i5, i4, i2, i11) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ if ((i5 | 0) == 0) {
+  i11 = 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ i7 = i5 + 12 | 0;
+ i8 = i5 + 40 | 0;
+ i9 = HEAPU8[i5 + 46 | 0] | 0;
+ while (1) {
+  i6 = i9 + -1 | 0;
+  i10 = HEAP32[i5 >> 2] | 0;
+  if ((i9 | 0) <= 0) {
+   break;
+  }
+  if ((_luaS_eqstr(i4, HEAP32[(HEAP32[i10 + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i7 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((HEAP32[i8 >> 2] | 0) + i6 << 1) >> 1] | 0) * 12 | 0) >> 2] | 0) | 0) == 0) {
+   i9 = i6;
+  } else {
+   i3 = 5;
+   break;
+  }
+ }
+ if ((i3 | 0) == 5) {
+  HEAP32[i2 + 16 >> 2] = -1;
+  HEAP32[i2 + 20 >> 2] = -1;
+  HEAP32[i2 >> 2] = 7;
+  HEAP32[i2 + 8 >> 2] = i6;
+  if ((i11 | 0) != 0) {
+   i11 = 7;
+   STACKTOP = i1;
+   return i11 | 0;
+  }
+  i2 = i5 + 16 | 0;
+  do {
+   i2 = HEAP32[i2 >> 2] | 0;
+  } while ((HEAPU8[i2 + 8 | 0] | 0) > (i6 | 0));
+  HEAP8[i2 + 9 | 0] = 1;
+  i11 = 7;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ i7 = HEAP32[i10 + 28 >> 2] | 0;
+ i6 = i5 + 47 | 0;
+ L17 : do {
+  if ((HEAP8[i6] | 0) != 0) {
+   i8 = 0;
+   while (1) {
+    i9 = i8 + 1 | 0;
+    if ((_luaS_eqstr(HEAP32[i7 + (i8 << 3) >> 2] | 0, i4) | 0) != 0) {
+     break;
+    }
+    if ((i9 | 0) < (HEAPU8[i6] | 0)) {
+     i8 = i9;
+    } else {
+     i3 = 13;
+     break L17;
+    }
+   }
+   if ((i8 | 0) < 0) {
+    i3 = 13;
+   }
+  } else {
+   i3 = 13;
+  }
+ } while (0);
+ do {
+  if ((i3 | 0) == 13) {
+   if ((_singlevaraux(HEAP32[i5 + 8 >> 2] | 0, i4, i2, 0) | 0) == 0) {
+    i11 = 0;
+    STACKTOP = i1;
+    return i11 | 0;
+   } else {
+    i8 = _newupvalue(i5, i4, i2) | 0;
+    break;
+   }
+  }
+ } while (0);
+ HEAP32[i2 + 16 >> 2] = -1;
+ HEAP32[i2 + 20 >> 2] = -1;
+ HEAP32[i2 >> 2] = 8;
+ HEAP32[i2 + 8 >> 2] = i8;
+ i11 = 8;
+ STACKTOP = i1;
+ return i11 | 0;
+}
+function _mainposition(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ switch (HEAP32[i3 + 8 >> 2] & 63 | 0) {
+ case 3:
+  {
+   HEAPF64[i4 >> 3] = +HEAPF64[i3 >> 3] + 1.0;
+   i3 = (HEAP32[i4 + 4 >> 2] | 0) + (HEAP32[i4 >> 2] | 0) | 0;
+   if ((i3 | 0) < 0) {
+    i4 = 0 - i3 | 0;
+    i3 = (i3 | 0) == (i4 | 0) ? 0 : i4;
+   }
+   i5 = (HEAP32[i1 + 16 >> 2] | 0) + (((i3 | 0) % ((1 << HEAPU8[i1 + 7 | 0]) + -1 | 1 | 0) | 0) << 5) | 0;
+   STACKTOP = i2;
+   return i5 | 0;
+  }
+ case 2:
+  {
+   i5 = (HEAP32[i1 + 16 >> 2] | 0) + ((((HEAP32[i3 >> 2] | 0) >>> 0) % (((1 << HEAPU8[i1 + 7 | 0]) + -1 | 1) >>> 0) | 0) << 5) | 0;
+   STACKTOP = i2;
+   return i5 | 0;
+  }
+ case 20:
+  {
+   i5 = HEAP32[i3 >> 2] | 0;
+   i4 = i5 + 6 | 0;
+   if ((HEAP8[i4] | 0) == 0) {
+    i6 = i5 + 8 | 0;
+    HEAP32[i6 >> 2] = _luaS_hash(i5 + 16 | 0, HEAP32[i5 + 12 >> 2] | 0, HEAP32[i6 >> 2] | 0) | 0;
+    HEAP8[i4] = 1;
+    i5 = HEAP32[i3 >> 2] | 0;
+   }
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + (((1 << HEAPU8[i1 + 7 | 0]) + -1 & HEAP32[i5 + 8 >> 2]) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ case 22:
+  {
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + ((((HEAP32[i3 >> 2] | 0) >>> 0) % (((1 << HEAPU8[i1 + 7 | 0]) + -1 | 1) >>> 0) | 0) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ case 4:
+  {
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + (((1 << HEAPU8[i1 + 7 | 0]) + -1 & HEAP32[(HEAP32[i3 >> 2] | 0) + 8 >> 2]) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ case 1:
+  {
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + (((1 << HEAPU8[i1 + 7 | 0]) + -1 & HEAP32[i3 >> 2]) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ default:
+  {
+   i6 = (HEAP32[i1 + 16 >> 2] | 0) + ((((HEAP32[i3 >> 2] | 0) >>> 0) % (((1 << HEAPU8[i1 + 7 | 0]) + -1 | 1) >>> 0) | 0) << 5) | 0;
+   STACKTOP = i2;
+   return i6 | 0;
+  }
+ }
+ return 0;
+}
+function _clearvalues(i2, i5, i1) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i4 = STACKTOP;
+ if ((i5 | 0) == (i1 | 0)) {
+  STACKTOP = i4;
+  return;
+ }
+ do {
+  i7 = i5 + 16 | 0;
+  i9 = HEAP32[i7 >> 2] | 0;
+  i6 = i9 + (1 << (HEAPU8[i5 + 7 | 0] | 0) << 5) | 0;
+  i8 = i5 + 28 | 0;
+  if ((HEAP32[i8 >> 2] | 0) > 0) {
+   i11 = i5 + 12 | 0;
+   i12 = 0;
+   do {
+    i13 = HEAP32[i11 >> 2] | 0;
+    i10 = i13 + (i12 << 4) + 8 | 0;
+    i9 = HEAP32[i10 >> 2] | 0;
+    do {
+     if ((i9 & 64 | 0) != 0) {
+      i13 = HEAP32[i13 + (i12 << 4) >> 2] | 0;
+      if ((i9 & 15 | 0) != 4) {
+       if ((HEAP8[i13 + 5 | 0] & 3) == 0) {
+        break;
+       }
+       HEAP32[i10 >> 2] = 0;
+       break;
+      }
+      if ((i13 | 0) != 0 ? !((HEAP8[i13 + 5 | 0] & 3) == 0) : 0) {
+       _reallymarkobject(i2, i13);
+      }
+     }
+    } while (0);
+    i12 = i12 + 1 | 0;
+   } while ((i12 | 0) < (HEAP32[i8 >> 2] | 0));
+   i7 = HEAP32[i7 >> 2] | 0;
+  } else {
+   i7 = i9;
+  }
+  if (i7 >>> 0 < i6 >>> 0) {
+   do {
+    i8 = i7 + 8 | 0;
+    i9 = HEAP32[i8 >> 2] | 0;
+    do {
+     if (!((i9 | 0) == 0 | (i9 & 64 | 0) == 0)) {
+      i10 = HEAP32[i7 >> 2] | 0;
+      if ((i9 & 15 | 0) == 4) {
+       if ((i10 | 0) == 0) {
+        break;
+       }
+       if ((HEAP8[i10 + 5 | 0] & 3) == 0) {
+        break;
+       }
+       _reallymarkobject(i2, i10);
+       break;
+      }
+      if ((!((HEAP8[i10 + 5 | 0] & 3) == 0) ? (HEAP32[i8 >> 2] = 0, i3 = i7 + 24 | 0, (HEAP32[i3 >> 2] & 64 | 0) != 0) : 0) ? !((HEAP8[(HEAP32[i7 + 16 >> 2] | 0) + 5 | 0] & 3) == 0) : 0) {
+       HEAP32[i3 >> 2] = 11;
+      }
+     }
+    } while (0);
+    i7 = i7 + 32 | 0;
+   } while (i7 >>> 0 < i6 >>> 0);
+  }
+  i5 = HEAP32[i5 + 24 >> 2] | 0;
+ } while ((i5 | 0) != (i1 | 0));
+ STACKTOP = i4;
+ return;
+}
+function _reallymarkobject(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ i2 = i4 + 5 | 0;
+ HEAP8[i2] = HEAP8[i2] & 252;
+ switch (HEAPU8[i4 + 4 | 0] | 0 | 0) {
+ case 6:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ case 20:
+ case 4:
+  {
+   i4 = (HEAP32[i4 + 12 >> 2] | 0) + 17 | 0;
+   break;
+  }
+ case 7:
+  {
+   i5 = HEAP32[i4 + 8 >> 2] | 0;
+   if ((i5 | 0) != 0 ? !((HEAP8[i5 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i1, i5);
+   }
+   i5 = HEAP32[i4 + 12 >> 2] | 0;
+   if ((i5 | 0) != 0 ? !((HEAP8[i5 + 5 | 0] & 3) == 0) : 0) {
+    _reallymarkobject(i1, i5);
+   }
+   i4 = (HEAP32[i4 + 16 >> 2] | 0) + 24 | 0;
+   break;
+  }
+ case 8:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 60 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ case 10:
+  {
+   i6 = i4 + 8 | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i7 + 8 >> 2] & 64 | 0) != 0 ? (i5 = HEAP32[i7 >> 2] | 0, !((HEAP8[i5 + 5 | 0] & 3) == 0)) : 0) {
+    _reallymarkobject(i1, i5);
+    i7 = HEAP32[i6 >> 2] | 0;
+   }
+   if ((i7 | 0) == (i4 + 16 | 0)) {
+    i4 = 32;
+   } else {
+    STACKTOP = i3;
+    return;
+   }
+   break;
+  }
+ case 5:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 24 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ case 38:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 8 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ case 9:
+  {
+   i7 = i1 + 84 | 0;
+   HEAP32[i4 + 72 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i4;
+   STACKTOP = i3;
+   return;
+  }
+ default:
+  {
+   STACKTOP = i3;
+   return;
+  }
+ }
+ HEAP8[i2] = HEAPU8[i2] | 0 | 4;
+ i7 = i1 + 16 | 0;
+ HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + i4;
+ STACKTOP = i3;
+ return;
+}
+function _lua_upvaluejoin(i1, i9, i7, i6, i3) {
+ i1 = i1 | 0;
+ i9 = i9 | 0;
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i8 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i9 | 0) <= 0) {
+   if (!((i9 | 0) < -1000999)) {
+    i8 = (HEAP32[i1 + 8 >> 2] | 0) + (i9 << 4) | 0;
+    break;
+   }
+   if ((i9 | 0) == -1001e3) {
+    i8 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i10 = -1001e3 - i9 | 0;
+   i9 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) != 22 ? (i8 = HEAP32[i9 >> 2] | 0, (i10 | 0) <= (HEAPU8[i8 + 6 | 0] | 0 | 0)) : 0) {
+    i8 = i8 + (i10 + -1 << 4) + 16 | 0;
+   } else {
+    i8 = 5192;
+   }
+  } else {
+   i8 = (HEAP32[i5 >> 2] | 0) + (i9 << 4) | 0;
+   i8 = i8 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i8 : 5192;
+  }
+ } while (0);
+ i8 = HEAP32[i8 >> 2] | 0;
+ i7 = i8 + 16 + (i7 + -1 << 2) | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i3 = (HEAP32[i4 >> 2] | 0) + 16 + (i3 + -1 << 2) | 0;
+ HEAP32[i7 >> 2] = HEAP32[i3 >> 2];
+ i3 = HEAP32[i3 >> 2] | 0;
+ if ((HEAP8[i3 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[i8 + 5 | 0] & 4) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaC_barrier_(i1, i8, i3);
+ STACKTOP = i2;
+ return;
+}
+function _lua_upvalueid(i5, i7, i1) {
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i5 + 16 >> 2] | 0;
+ i6 = (i7 | 0) > 0;
+ do {
+  if (!i6) {
+   if (!((i7 | 0) < -1000999)) {
+    i8 = (HEAP32[i5 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i8 = (HEAP32[i5 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i10 = -1001e3 - i7 | 0;
+   i9 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i9 + 8 >> 2] | 0) != 22 ? (i8 = HEAP32[i9 >> 2] | 0, (i10 | 0) <= (HEAPU8[i8 + 6 | 0] | 0 | 0)) : 0) {
+    i8 = i8 + (i10 + -1 << 4) + 16 | 0;
+   } else {
+    i8 = 5192;
+   }
+  } else {
+   i8 = (HEAP32[i4 >> 2] | 0) + (i7 << 4) | 0;
+   i8 = i8 >>> 0 < (HEAP32[i5 + 8 >> 2] | 0) >>> 0 ? i8 : 5192;
+  }
+ } while (0);
+ i9 = HEAP32[i8 + 8 >> 2] & 63;
+ if ((i9 | 0) == 38) {
+  i10 = (HEAP32[i8 >> 2] | 0) + (i1 + -1 << 4) + 16 | 0;
+  STACKTOP = i2;
+  return i10 | 0;
+ } else if ((i9 | 0) == 6) {
+  do {
+   if (!i6) {
+    if (!((i7 | 0) < -1000999)) {
+     i3 = (HEAP32[i5 + 8 >> 2] | 0) + (i7 << 4) | 0;
+     break;
+    }
+    if ((i7 | 0) == -1001e3) {
+     i3 = (HEAP32[i5 + 12 >> 2] | 0) + 40 | 0;
+     break;
+    }
+    i5 = -1001e3 - i7 | 0;
+    i4 = HEAP32[i4 >> 2] | 0;
+    if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+     i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+    } else {
+     i3 = 5192;
+    }
+   } else {
+    i3 = (HEAP32[i4 >> 2] | 0) + (i7 << 4) | 0;
+    i3 = i3 >>> 0 < (HEAP32[i5 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+   }
+  } while (0);
+  i10 = HEAP32[(HEAP32[i3 >> 2] | 0) + 16 + (i1 + -1 << 2) >> 2] | 0;
+  STACKTOP = i2;
+  return i10 | 0;
+ } else {
+  i10 = 0;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ return 0;
+}
+function _lua_rawequal(i2, i6, i4) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i5 = (HEAP32[i2 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i5 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i7 = -1001e3 - i6 | 0;
+   i6 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i5 = HEAP32[i6 >> 2] | 0, (i7 | 0) <= (HEAPU8[i5 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i5 + (i7 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i5 = (HEAP32[i3 >> 2] | 0) + (i6 << 4) | 0;
+   i5 = i5 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i5 : 5192;
+  }
+ } while (0);
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i2 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i2 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i2 = -1001e3 - i4 | 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP32[i3 + 8 >> 2] | 0) == 22) {
+    i7 = 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((i2 | 0) > (HEAPU8[i3 + 6 | 0] | 0 | 0)) {
+    i7 = 0;
+    STACKTOP = i1;
+    return i7 | 0;
+   } else {
+    i2 = i3 + (i2 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else {
+   i3 = (HEAP32[i3 >> 2] | 0) + (i4 << 4) | 0;
+   i2 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ if ((i5 | 0) == 5192 | (i2 | 0) == 5192) {
+  i7 = 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ if ((HEAP32[i5 + 8 >> 2] | 0) == (HEAP32[i2 + 8 >> 2] | 0)) {
+  i2 = (_luaV_equalobj_(0, i5, i2) | 0) != 0;
+ } else {
+  i2 = 0;
+ }
+ i7 = i2 & 1;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaO_chunkid(i1, i4, i6) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i3 = _strlen(i4 | 0) | 0;
+ i5 = HEAP8[i4] | 0;
+ if (i5 << 24 >> 24 == 64) {
+  if (i3 >>> 0 > i6 >>> 0) {
+   HEAP8[i1 + 0 | 0] = HEAP8[5552 | 0] | 0;
+   HEAP8[i1 + 1 | 0] = HEAP8[5553 | 0] | 0;
+   HEAP8[i1 + 2 | 0] = HEAP8[5554 | 0] | 0;
+   _memcpy(i1 + 3 | 0, i4 + (4 - i6 + i3) | 0, i6 + -3 | 0) | 0;
+   STACKTOP = i2;
+   return;
+  } else {
+   _memcpy(i1 | 0, i4 + 1 | 0, i3 | 0) | 0;
+   STACKTOP = i2;
+   return;
+  }
+ } else if (i5 << 24 >> 24 == 61) {
+  i4 = i4 + 1 | 0;
+  if (i3 >>> 0 > i6 >>> 0) {
+   i9 = i6 + -1 | 0;
+   _memcpy(i1 | 0, i4 | 0, i9 | 0) | 0;
+   HEAP8[i1 + i9 | 0] = 0;
+   STACKTOP = i2;
+   return;
+  } else {
+   _memcpy(i1 | 0, i4 | 0, i3 | 0) | 0;
+   STACKTOP = i2;
+   return;
+  }
+ } else {
+  i5 = _strchr(i4, 10) | 0;
+  i9 = i1 + 0 | 0;
+  i8 = 5560 | 0;
+  i7 = i9 + 9 | 0;
+  do {
+   HEAP8[i9] = HEAP8[i8] | 0;
+   i9 = i9 + 1 | 0;
+   i8 = i8 + 1 | 0;
+  } while ((i9 | 0) < (i7 | 0));
+  i7 = i1 + 9 | 0;
+  i6 = i6 + -15 | 0;
+  i8 = (i5 | 0) == 0;
+  if (i3 >>> 0 < i6 >>> 0 & i8) {
+   _memcpy(i7 | 0, i4 | 0, i3 | 0) | 0;
+   i3 = i3 + 9 | 0;
+  } else {
+   if (!i8) {
+    i3 = i5 - i4 | 0;
+   }
+   i3 = i3 >>> 0 > i6 >>> 0 ? i6 : i3;
+   _memcpy(i7 | 0, i4 | 0, i3 | 0) | 0;
+   i9 = i1 + (i3 + 9) | 0;
+   HEAP8[i9 + 0 | 0] = HEAP8[5552 | 0] | 0;
+   HEAP8[i9 + 1 | 0] = HEAP8[5553 | 0] | 0;
+   HEAP8[i9 + 2 | 0] = HEAP8[5554 | 0] | 0;
+   i3 = i3 + 12 | 0;
+  }
+  i9 = i1 + i3 | 0;
+  HEAP8[i9 + 0 | 0] = HEAP8[5576 | 0] | 0;
+  HEAP8[i9 + 1 | 0] = HEAP8[5577 | 0] | 0;
+  HEAP8[i9 + 2 | 0] = HEAP8[5578 | 0] | 0;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaS_resize(i4, i1) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i3 = STACKTOP;
+ i5 = HEAP32[i4 + 12 >> 2] | 0;
+ i2 = i5 + 24 | 0;
+ _luaC_runtilstate(i4, -5);
+ i5 = i5 + 32 | 0;
+ i8 = HEAP32[i5 >> 2] | 0;
+ L1 : do {
+  if ((i8 | 0) < (i1 | 0)) {
+   if ((i1 + 1 | 0) >>> 0 > 1073741823) {
+    _luaM_toobig(i4);
+   }
+   i7 = _luaM_realloc_(i4, HEAP32[i2 >> 2] | 0, i8 << 2, i1 << 2) | 0;
+   HEAP32[i2 >> 2] = i7;
+   i6 = HEAP32[i5 >> 2] | 0;
+   if ((i6 | 0) < (i1 | 0)) {
+    i8 = i6;
+    while (1) {
+     HEAP32[i7 + (i8 << 2) >> 2] = 0;
+     i8 = i8 + 1 | 0;
+     if ((i8 | 0) == (i1 | 0)) {
+      i8 = i6;
+      break L1;
+     }
+     i7 = HEAP32[i2 >> 2] | 0;
+    }
+   } else {
+    i8 = i6;
+   }
+  }
+ } while (0);
+ if ((i8 | 0) > 0) {
+  i6 = i1 + -1 | 0;
+  i7 = 0;
+  do {
+   i10 = (HEAP32[i2 >> 2] | 0) + (i7 << 2) | 0;
+   i9 = HEAP32[i10 >> 2] | 0;
+   HEAP32[i10 >> 2] = 0;
+   if ((i9 | 0) != 0) {
+    while (1) {
+     i8 = HEAP32[i9 >> 2] | 0;
+     i10 = HEAP32[i9 + 8 >> 2] & i6;
+     HEAP32[i9 >> 2] = HEAP32[(HEAP32[i2 >> 2] | 0) + (i10 << 2) >> 2];
+     HEAP32[(HEAP32[i2 >> 2] | 0) + (i10 << 2) >> 2] = i9;
+     i10 = i9 + 5 | 0;
+     HEAP8[i10] = HEAP8[i10] & 191;
+     if ((i8 | 0) == 0) {
+      break;
+     } else {
+      i9 = i8;
+     }
+    }
+    i8 = HEAP32[i5 >> 2] | 0;
+   }
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) < (i8 | 0));
+ }
+ if ((i8 | 0) <= (i1 | 0)) {
+  HEAP32[i5 >> 2] = i1;
+  STACKTOP = i3;
+  return;
+ }
+ if ((i1 + 1 | 0) >>> 0 > 1073741823) {
+  _luaM_toobig(i4);
+ }
+ HEAP32[i2 >> 2] = _luaM_realloc_(i4, HEAP32[i2 >> 2] | 0, i8 << 2, i1 << 2) | 0;
+ HEAP32[i5 >> 2] = i1;
+ STACKTOP = i3;
+ return;
+}
+function _luaD_poscall(i6, i7) {
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ i4 = i6 + 16 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ i5 = HEAPU8[i6 + 40 | 0] | 0;
+ if ((i5 & 6 | 0) == 0) {
+  i8 = i3 + 8 | 0;
+ } else {
+  if ((i5 & 2 | 0) != 0) {
+   i8 = i6 + 28 | 0;
+   i7 = i7 - (HEAP32[i8 >> 2] | 0) | 0;
+   _luaD_hook(i6, 1, -1);
+   i7 = (HEAP32[i8 >> 2] | 0) + i7 | 0;
+  }
+  i8 = i3 + 8 | 0;
+  HEAP32[i6 + 20 >> 2] = HEAP32[(HEAP32[i8 >> 2] | 0) + 28 >> 2];
+ }
+ i5 = HEAP32[i3 >> 2] | 0;
+ i9 = HEAP16[i3 + 16 >> 1] | 0;
+ i3 = i9 << 16 >> 16;
+ HEAP32[i4 >> 2] = HEAP32[i8 >> 2];
+ i4 = i6 + 8 | 0;
+ if (i9 << 16 >> 16 == 0) {
+  i9 = i5;
+  HEAP32[i4 >> 2] = i9;
+  i9 = i3 + 1 | 0;
+  STACKTOP = i1;
+  return i9 | 0;
+ } else {
+  i6 = i3;
+ }
+ while (1) {
+  if (!(i7 >>> 0 < (HEAP32[i4 >> 2] | 0) >>> 0)) {
+   break;
+  }
+  i8 = i5 + 16 | 0;
+  i11 = i7;
+  i10 = HEAP32[i11 + 4 >> 2] | 0;
+  i9 = i5;
+  HEAP32[i9 >> 2] = HEAP32[i11 >> 2];
+  HEAP32[i9 + 4 >> 2] = i10;
+  HEAP32[i5 + 8 >> 2] = HEAP32[i7 + 8 >> 2];
+  i6 = i6 + -1 | 0;
+  if ((i6 | 0) == 0) {
+   i2 = 12;
+   break;
+  } else {
+   i7 = i7 + 16 | 0;
+   i5 = i8;
+  }
+ }
+ if ((i2 | 0) == 12) {
+  HEAP32[i4 >> 2] = i8;
+  i11 = i3 + 1 | 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ if ((i6 | 0) > 0) {
+  i2 = i6;
+  i7 = i5;
+ } else {
+  i11 = i5;
+  HEAP32[i4 >> 2] = i11;
+  i11 = i3 + 1 | 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ while (1) {
+  i2 = i2 + -1 | 0;
+  HEAP32[i7 + 8 >> 2] = 0;
+  if ((i2 | 0) <= 0) {
+   break;
+  } else {
+   i7 = i7 + 16 | 0;
+  }
+ }
+ i11 = i5 + (i6 << 4) | 0;
+ HEAP32[i4 >> 2] = i11;
+ i11 = i3 + 1 | 0;
+ STACKTOP = i1;
+ return i11 | 0;
+}
+function _lua_rawset(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i4 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i5 >> 2] | 0) + (i4 << 4) | 0;
+   i5 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i4 = i1 + 8 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ i3 = _luaH_set(i1, HEAP32[i5 >> 2] | 0, i6 + -32 | 0) | 0;
+ i9 = i6 + -16 | 0;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i3;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i6 + -8 >> 2];
+ HEAP8[(HEAP32[i5 >> 2] | 0) + 6 | 0] = 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ if ((HEAP32[i3 + -8 >> 2] & 64 | 0) == 0) {
+  i9 = i3;
+  i9 = i9 + -32 | 0;
+  HEAP32[i4 >> 2] = i9;
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[(HEAP32[i3 + -16 >> 2] | 0) + 5 | 0] & 3) == 0) {
+  i9 = i3;
+  i9 = i9 + -32 | 0;
+  HEAP32[i4 >> 2] = i9;
+  STACKTOP = i2;
+  return;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((HEAP8[i5 + 5 | 0] & 4) == 0) {
+  i9 = i3;
+  i9 = i9 + -32 | 0;
+  HEAP32[i4 >> 2] = i9;
+  STACKTOP = i2;
+  return;
+ }
+ _luaC_barrierback_(i1, i5);
+ i9 = HEAP32[i4 >> 2] | 0;
+ i9 = i9 + -32 | 0;
+ HEAP32[i4 >> 2] = i9;
+ STACKTOP = i2;
+ return;
+}
+function _saveSetjmp(i4, i3, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ setjmpId = setjmpId + 1 | 0;
+ HEAP32[i4 >> 2] = setjmpId;
+ while ((i2 | 0) < 40) {
+  if ((HEAP32[i1 + (i2 << 2) >> 2] | 0) == 0) {
+   HEAP32[i1 + (i2 << 2) >> 2] = setjmpId;
+   HEAP32[i1 + ((i2 << 2) + 4) >> 2] = i3;
+   HEAP32[i1 + ((i2 << 2) + 8) >> 2] = 0;
+   return 0;
+  }
+  i2 = i2 + 2 | 0;
+ }
+ _putchar(116);
+ _putchar(111);
+ _putchar(111);
+ _putchar(32);
+ _putchar(109);
+ _putchar(97);
+ _putchar(110);
+ _putchar(121);
+ _putchar(32);
+ _putchar(115);
+ _putchar(101);
+ _putchar(116);
+ _putchar(106);
+ _putchar(109);
+ _putchar(112);
+ _putchar(115);
+ _putchar(32);
+ _putchar(105);
+ _putchar(110);
+ _putchar(32);
+ _putchar(97);
+ _putchar(32);
+ _putchar(102);
+ _putchar(117);
+ _putchar(110);
+ _putchar(99);
+ _putchar(116);
+ _putchar(105);
+ _putchar(111);
+ _putchar(110);
+ _putchar(32);
+ _putchar(99);
+ _putchar(97);
+ _putchar(108);
+ _putchar(108);
+ _putchar(44);
+ _putchar(32);
+ _putchar(98);
+ _putchar(117);
+ _putchar(105);
+ _putchar(108);
+ _putchar(100);
+ _putchar(32);
+ _putchar(119);
+ _putchar(105);
+ _putchar(116);
+ _putchar(104);
+ _putchar(32);
+ _putchar(97);
+ _putchar(32);
+ _putchar(104);
+ _putchar(105);
+ _putchar(103);
+ _putchar(104);
+ _putchar(101);
+ _putchar(114);
+ _putchar(32);
+ _putchar(118);
+ _putchar(97);
+ _putchar(108);
+ _putchar(117);
+ _putchar(101);
+ _putchar(32);
+ _putchar(102);
+ _putchar(111);
+ _putchar(114);
+ _putchar(32);
+ _putchar(77);
+ _putchar(65);
+ _putchar(88);
+ _putchar(95);
+ _putchar(83);
+ _putchar(69);
+ _putchar(84);
+ _putchar(74);
+ _putchar(77);
+ _putchar(80);
+ _putchar(83);
+ _putchar(10);
+ abort(0);
+ return 0;
+}
+function _lua_newthread(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ i3 = i5 + 12 | 0;
+ if ((HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i5);
+ }
+ i2 = _luaC_newobj(i5, 8, 112, 0, 0) | 0;
+ i6 = i5 + 8 | 0;
+ i4 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i4 >> 2] = i2;
+ HEAP32[i4 + 8 >> 2] = 72;
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 16;
+ HEAP32[i2 + 12 >> 2] = HEAP32[i3 >> 2];
+ i6 = i2 + 28 | 0;
+ HEAP32[i6 >> 2] = 0;
+ i4 = i2 + 16 | 0;
+ HEAP32[i4 >> 2] = 0;
+ i3 = i2 + 32 | 0;
+ HEAP32[i3 >> 2] = 0;
+ HEAP32[i2 + 64 >> 2] = 0;
+ HEAP16[i2 + 38 >> 1] = 0;
+ i9 = i2 + 52 | 0;
+ HEAP32[i9 >> 2] = 0;
+ i8 = i2 + 40 | 0;
+ HEAP8[i8] = 0;
+ i10 = i2 + 44 | 0;
+ HEAP32[i10 >> 2] = 0;
+ HEAP8[i2 + 41 | 0] = 1;
+ i7 = i2 + 48 | 0;
+ HEAP32[i7 >> 2] = 0;
+ HEAP32[i2 + 56 >> 2] = 0;
+ HEAP16[i2 + 36 >> 1] = 1;
+ HEAP8[i2 + 6 | 0] = 0;
+ HEAP32[i2 + 68 >> 2] = 0;
+ HEAP8[i8] = HEAP8[i5 + 40 | 0] | 0;
+ i8 = HEAP32[i5 + 44 >> 2] | 0;
+ HEAP32[i10 >> 2] = i8;
+ HEAP32[i9 >> 2] = HEAP32[i5 + 52 >> 2];
+ HEAP32[i7 >> 2] = i8;
+ i5 = _luaM_realloc_(i5, 0, 0, 640) | 0;
+ HEAP32[i6 >> 2] = i5;
+ HEAP32[i3 >> 2] = 40;
+ i6 = 0;
+ do {
+  HEAP32[i5 + (i6 << 4) + 8 >> 2] = 0;
+  i6 = i6 + 1 | 0;
+ } while ((i6 | 0) != 40);
+ HEAP32[i2 + 24 >> 2] = i5 + ((HEAP32[i3 >> 2] | 0) + -5 << 4);
+ i10 = i2 + 72 | 0;
+ HEAP32[i2 + 80 >> 2] = 0;
+ HEAP32[i2 + 84 >> 2] = 0;
+ HEAP8[i2 + 90 | 0] = 0;
+ HEAP32[i10 >> 2] = i5;
+ HEAP32[i2 + 8 >> 2] = i5 + 16;
+ HEAP32[i5 + 8 >> 2] = 0;
+ HEAP32[i2 + 76 >> 2] = i5 + 336;
+ HEAP32[i4 >> 2] = i10;
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaK_self(i2, i5, i3) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ _luaK_dischargevars(i2, i5);
+ if ((HEAP32[i5 >> 2] | 0) == 6) {
+  i6 = i5 + 8 | 0;
+  i8 = HEAP32[i6 >> 2] | 0;
+  if ((HEAP32[i5 + 16 >> 2] | 0) != (HEAP32[i5 + 20 >> 2] | 0)) {
+   if ((i8 | 0) < (HEAPU8[i2 + 46 | 0] | 0 | 0)) {
+    i7 = 6;
+   } else {
+    _exp2reg(i2, i5, i8);
+   }
+  }
+ } else {
+  i6 = i5 + 8 | 0;
+  i7 = 6;
+ }
+ if ((i7 | 0) == 6) {
+  _luaK_exp2nextreg(i2, i5);
+ }
+ i8 = HEAP32[i6 >> 2] | 0;
+ if (((HEAP32[i5 >> 2] | 0) == 6 ? (i8 & 256 | 0) == 0 : 0) ? (HEAPU8[i2 + 46 | 0] | 0 | 0) <= (i8 | 0) : 0) {
+  i10 = i2 + 48 | 0;
+  HEAP8[i10] = (HEAP8[i10] | 0) + -1 << 24 >> 24;
+ }
+ i7 = i2 + 48 | 0;
+ HEAP32[i6 >> 2] = HEAPU8[i7] | 0;
+ HEAP32[i5 >> 2] = 6;
+ i10 = HEAP8[i7] | 0;
+ i5 = (i10 & 255) + 2 | 0;
+ i9 = (HEAP32[i2 >> 2] | 0) + 78 | 0;
+ do {
+  if (i5 >>> 0 > (HEAPU8[i9] | 0) >>> 0) {
+   if (i5 >>> 0 > 249) {
+    _luaX_syntaxerror(HEAP32[i2 + 12 >> 2] | 0, 10536);
+   } else {
+    HEAP8[i9] = i5;
+    i4 = HEAP8[i7] | 0;
+    break;
+   }
+  } else {
+   i4 = i10;
+  }
+ } while (0);
+ HEAP8[i7] = (i4 & 255) + 2;
+ i10 = HEAP32[i6 >> 2] | 0;
+ _luaK_code(i2, i8 << 23 | i10 << 6 | (_luaK_exp2RK(i2, i3) | 0) << 14 | 12) | 0;
+ if ((HEAP32[i3 >> 2] | 0) != 6) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((i3 & 256 | 0) != 0) {
+  STACKTOP = i1;
+  return;
+ }
+ if ((HEAPU8[i2 + 46 | 0] | 0 | 0) > (i3 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP8[i7] = (HEAP8[i7] | 0) + -1 << 24 >> 24;
+ STACKTOP = i1;
+ return;
+}
+function _luaD_rawrunprotected(i10, i9, i11) {
+ i10 = i10 | 0;
+ i9 = i9 | 0;
+ i11 = i11 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i12 = 0, i13 = 0;
+ i7 = STACKTOP;
+ STACKTOP = STACKTOP + 176 | 0;
+ i8 = STACKTOP;
+ STACKTOP = STACKTOP + 168 | 0;
+ HEAP32[i8 >> 2] = 0;
+ i6 = i7;
+ i5 = i10 + 38 | 0;
+ i4 = HEAP16[i5 >> 1] | 0;
+ i1 = i6 + 160 | 0;
+ HEAP32[i1 >> 2] = 0;
+ i3 = i10 + 64 | 0;
+ HEAP32[i6 >> 2] = HEAP32[i3 >> 2];
+ HEAP32[i3 >> 2] = i6;
+ _saveSetjmp(i6 + 4 | 0, 1, i8 | 0) | 0;
+ __THREW__ = 0;
+ i13 = __THREW__;
+ __THREW__ = 0;
+ if ((i13 | 0) != 0 & (threwValue | 0) != 0) {
+  i12 = _testSetjmp(HEAP32[i13 >> 2] | 0, i8) | 0;
+  if ((i12 | 0) == 0) {
+   _longjmp(i13 | 0, threwValue | 0);
+  }
+  tempRet0 = threwValue;
+ } else {
+  i12 = -1;
+ }
+ if ((i12 | 0) == 1) {
+  i12 = tempRet0;
+ } else {
+  i12 = 0;
+ }
+ while (1) {
+  if ((i12 | 0) != 0) {
+   i2 = 6;
+   break;
+  }
+  __THREW__ = 0;
+  invoke_vii(i9 | 0, i10 | 0, i11 | 0);
+  i13 = __THREW__;
+  __THREW__ = 0;
+  if ((i13 | 0) != 0 & (threwValue | 0) != 0) {
+   i12 = _testSetjmp(HEAP32[i13 >> 2] | 0, i8) | 0;
+   if ((i12 | 0) == 0) {
+    _longjmp(i13 | 0, threwValue | 0);
+   }
+   tempRet0 = threwValue;
+  } else {
+   i12 = -1;
+  }
+  if ((i12 | 0) == 1) {
+   i12 = tempRet0;
+  } else {
+   break;
+  }
+ }
+ if ((i2 | 0) == 6) {
+  i13 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i3 >> 2] = i13;
+  HEAP16[i5 >> 1] = i4;
+  i13 = HEAP32[i1 >> 2] | 0;
+  STACKTOP = i7;
+  return i13 | 0;
+ }
+ i13 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i3 >> 2] = i13;
+ HEAP16[i5 >> 1] = i4;
+ i13 = HEAP32[i1 >> 2] | 0;
+ STACKTOP = i7;
+ return i13 | 0;
+}
+function _luaB_tonumber(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = 0.0, i7 = 0, d8 = 0.0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2 + 4 | 0;
+ i4 = i2;
+ do {
+  if ((_lua_type(i1, 2) | 0) >= 1) {
+   i9 = _luaL_checklstring(i1, 1, i4) | 0;
+   i3 = i9 + (HEAP32[i4 >> 2] | 0) | 0;
+   i5 = _luaL_checkinteger(i1, 2) | 0;
+   if (!((i5 + -2 | 0) >>> 0 < 35)) {
+    _luaL_argerror(i1, 2, 9648) | 0;
+   }
+   i10 = _strspn(i9, 9672) | 0;
+   i7 = i9 + i10 | 0;
+   i4 = HEAP8[i7] | 0;
+   if (i4 << 24 >> 24 == 43) {
+    i4 = 0;
+    i7 = i9 + (i10 + 1) | 0;
+   } else if (i4 << 24 >> 24 == 45) {
+    i4 = 1;
+    i7 = i9 + (i10 + 1) | 0;
+   } else {
+    i4 = 0;
+   }
+   if ((_isalnum(HEAPU8[i7] | 0 | 0) | 0) != 0) {
+    d6 = +(i5 | 0);
+    d8 = 0.0;
+    do {
+     i9 = HEAP8[i7] | 0;
+     i10 = i9 & 255;
+     if ((i10 + -48 | 0) >>> 0 < 10) {
+      i9 = (i9 << 24 >> 24) + -48 | 0;
+     } else {
+      i9 = (_toupper(i10 | 0) | 0) + -55 | 0;
+     }
+     if ((i9 | 0) >= (i5 | 0)) {
+      break;
+     }
+     d8 = d6 * d8 + +(i9 | 0);
+     i7 = i7 + 1 | 0;
+    } while ((_isalnum(HEAPU8[i7] | 0 | 0) | 0) != 0);
+    if ((i7 + (_strspn(i7, 9672) | 0) | 0) == (i3 | 0)) {
+     if ((i4 | 0) != 0) {
+      d8 = -d8;
+     }
+     _lua_pushnumber(i1, d8);
+     STACKTOP = i2;
+     return 1;
+    }
+   }
+  } else {
+   d6 = +_lua_tonumberx(i1, 1, i3);
+   if ((HEAP32[i3 >> 2] | 0) == 0) {
+    _luaL_checkany(i1, 1);
+    break;
+   }
+   _lua_pushnumber(i1, d6);
+   STACKTOP = i2;
+   return 1;
+  }
+ } while (0);
+ _lua_pushnil(i1);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaK_storevar(i1, i5, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i7 = HEAP32[i5 >> 2] | 0;
+ if ((i7 | 0) == 7) {
+  if (((HEAP32[i3 >> 2] | 0) == 6 ? (i6 = HEAP32[i3 + 8 >> 2] | 0, (i6 & 256 | 0) == 0) : 0) ? (HEAPU8[i1 + 46 | 0] | 0) <= (i6 | 0) : 0) {
+   i7 = i1 + 48 | 0;
+   HEAP8[i7] = (HEAP8[i7] | 0) + -1 << 24 >> 24;
+  }
+  _exp2reg(i1, i3, HEAP32[i5 + 8 >> 2] | 0);
+  STACKTOP = i2;
+  return;
+ } else if ((i7 | 0) == 9) {
+  i4 = i5 + 8 | 0;
+  i7 = (HEAP8[i4 + 3 | 0] | 0) == 7 ? 10 : 8;
+  i6 = _luaK_exp2RK(i1, i3) | 0;
+  _luaK_code(i1, i6 << 14 | i7 | HEAPU8[i4 + 2 | 0] << 6 | HEAPU16[i4 >> 1] << 23) | 0;
+ } else if ((i7 | 0) == 8) {
+  _luaK_dischargevars(i1, i3);
+  if ((HEAP32[i3 >> 2] | 0) == 6) {
+   i6 = i3 + 8 | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i3 + 16 >> 2] | 0) != (HEAP32[i3 + 20 >> 2] | 0)) {
+    if ((i7 | 0) < (HEAPU8[i1 + 46 | 0] | 0)) {
+     i4 = 12;
+    } else {
+     _exp2reg(i1, i3, i7);
+     i7 = HEAP32[i6 >> 2] | 0;
+    }
+   }
+  } else {
+   i6 = i3 + 8 | 0;
+   i4 = 12;
+  }
+  if ((i4 | 0) == 12) {
+   _luaK_exp2nextreg(i1, i3);
+   i7 = HEAP32[i6 >> 2] | 0;
+  }
+  _luaK_code(i1, i7 << 6 | HEAP32[i5 + 8 >> 2] << 23 | 9) | 0;
+ }
+ if ((HEAP32[i3 >> 2] | 0) != 6) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((i3 & 256 | 0) != 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAPU8[i1 + 46 | 0] | 0) > (i3 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = i1 + 48 | 0;
+ HEAP8[i7] = (HEAP8[i7] | 0) + -1 << 24 >> 24;
+ STACKTOP = i2;
+ return;
+}
+function _closegoto(i10, i3, i9) {
+ i10 = i10 | 0;
+ i3 = i3 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i7 = i1;
+ i4 = HEAP32[i10 + 48 >> 2] | 0;
+ i6 = HEAP32[i10 + 64 >> 2] | 0;
+ i2 = i6 + 12 | 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ i8 = HEAP8[i5 + (i3 << 4) + 12 | 0] | 0;
+ if ((i8 & 255) < (HEAPU8[i9 + 12 | 0] | 0)) {
+  i11 = HEAP32[i10 + 52 >> 2] | 0;
+  i12 = HEAP32[i5 + (i3 << 4) + 8 >> 2] | 0;
+  i8 = (HEAP32[(HEAP32[(HEAP32[i4 >> 2] | 0) + 24 >> 2] | 0) + ((HEAP16[(HEAP32[HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 64 >> 2] >> 2] | 0) + ((HEAP32[i4 + 40 >> 2] | 0) + (i8 & 255) << 1) >> 1] | 0) * 12 | 0) >> 2] | 0) + 16 | 0;
+  HEAP32[i7 >> 2] = (HEAP32[i5 + (i3 << 4) >> 2] | 0) + 16;
+  HEAP32[i7 + 4 >> 2] = i12;
+  HEAP32[i7 + 8 >> 2] = i8;
+  _semerror(i10, _luaO_pushfstring(i11, 6248, i7) | 0);
+ }
+ _luaK_patchlist(i4, HEAP32[i5 + (i3 << 4) + 4 >> 2] | 0, HEAP32[i9 + 4 >> 2] | 0);
+ i4 = i6 + 16 | 0;
+ i5 = (HEAP32[i4 >> 2] | 0) + -1 | 0;
+ if ((i5 | 0) <= (i3 | 0)) {
+  i12 = i5;
+  HEAP32[i4 >> 2] = i12;
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  i12 = HEAP32[i2 >> 2] | 0;
+  i5 = i12 + (i3 << 4) | 0;
+  i3 = i3 + 1 | 0;
+  i12 = i12 + (i3 << 4) | 0;
+  HEAP32[i5 + 0 >> 2] = HEAP32[i12 + 0 >> 2];
+  HEAP32[i5 + 4 >> 2] = HEAP32[i12 + 4 >> 2];
+  HEAP32[i5 + 8 >> 2] = HEAP32[i12 + 8 >> 2];
+  HEAP32[i5 + 12 >> 2] = HEAP32[i12 + 12 >> 2];
+  i5 = (HEAP32[i4 >> 2] | 0) + -1 | 0;
+ } while ((i3 | 0) < (i5 | 0));
+ HEAP32[i4 >> 2] = i5;
+ STACKTOP = i1;
+ return;
+}
+function _luaM_growaux_(i4, i5, i1, i7, i8, i9) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ i9 = i9 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i10 = i2;
+ i6 = HEAP32[i1 >> 2] | 0;
+ if ((i6 | 0) >= ((i8 | 0) / 2 | 0 | 0)) {
+  if ((i6 | 0) < (i8 | 0)) {
+   i3 = i8;
+  } else {
+   HEAP32[i10 >> 2] = i9;
+   HEAP32[i10 + 4 >> 2] = i8;
+   _luaG_runerror(i4, 4112, i10);
+  }
+ } else {
+  i3 = i6 << 1;
+  i3 = (i3 | 0) < 4 ? 4 : i3;
+ }
+ if ((i3 + 1 | 0) >>> 0 > (4294967293 / (i7 >>> 0) | 0) >>> 0) {
+  _luaM_toobig(i4);
+ }
+ i6 = Math_imul(i6, i7) | 0;
+ i8 = Math_imul(i3, i7) | 0;
+ i9 = HEAP32[i4 + 12 >> 2] | 0;
+ i7 = (i5 | 0) != 0;
+ i11 = i9 + 4 | 0;
+ i10 = FUNCTION_TABLE_iiiii[HEAP32[i9 >> 2] & 3](HEAP32[i11 >> 2] | 0, i5, i6, i8) | 0;
+ if ((i10 | 0) != 0 | (i8 | 0) == 0) {
+  i5 = i9 + 12 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i6 = 0 - i6 | 0;
+  i11 = i7 ? i6 : 0;
+  i11 = i11 + i8 | 0;
+  i11 = i11 + i4 | 0;
+  HEAP32[i5 >> 2] = i11;
+  HEAP32[i1 >> 2] = i3;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ if ((HEAP8[i9 + 63 | 0] | 0) == 0) {
+  _luaD_throw(i4, 4);
+ }
+ _luaC_fullgc(i4, 1);
+ i10 = FUNCTION_TABLE_iiiii[HEAP32[i9 >> 2] & 3](HEAP32[i11 >> 2] | 0, i5, i6, i8) | 0;
+ if ((i10 | 0) == 0) {
+  _luaD_throw(i4, 4);
+ } else {
+  i5 = i9 + 12 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i6 = 0 - i6 | 0;
+  i11 = i7 ? i6 : 0;
+  i11 = i11 + i8 | 0;
+  i11 = i11 + i4 | 0;
+  HEAP32[i5 >> 2] = i11;
+  HEAP32[i1 >> 2] = i3;
+  STACKTOP = i2;
+  return i10 | 0;
+ }
+ return 0;
+}
+function _luaD_hook(i5, i14, i13) {
+ i5 = i5 | 0;
+ i14 = i14 | 0;
+ i13 = i13 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i15 = 0, i16 = 0;
+ i11 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i11;
+ i3 = HEAP32[i5 + 52 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  STACKTOP = i11;
+  return;
+ }
+ i8 = i5 + 41 | 0;
+ if ((HEAP8[i8] | 0) == 0) {
+  STACKTOP = i11;
+  return;
+ }
+ i10 = HEAP32[i5 + 16 >> 2] | 0;
+ i6 = i5 + 8 | 0;
+ i15 = HEAP32[i6 >> 2] | 0;
+ i1 = i5 + 28 | 0;
+ i16 = i15;
+ i12 = HEAP32[i1 >> 2] | 0;
+ i7 = i16 - i12 | 0;
+ i9 = i10 + 4 | 0;
+ i12 = (HEAP32[i9 >> 2] | 0) - i12 | 0;
+ HEAP32[i4 >> 2] = i14;
+ HEAP32[i4 + 20 >> 2] = i13;
+ HEAP32[i4 + 96 >> 2] = i10;
+ do {
+  if (((HEAP32[i5 + 24 >> 2] | 0) - i16 | 0) < 336) {
+   i14 = HEAP32[i5 + 32 >> 2] | 0;
+   if ((i14 | 0) > 1e6) {
+    _luaD_throw(i5, 6);
+   }
+   i13 = (i7 >> 4) + 25 | 0;
+   i14 = i14 << 1;
+   i14 = (i14 | 0) > 1e6 ? 1e6 : i14;
+   i13 = (i14 | 0) < (i13 | 0) ? i13 : i14;
+   if ((i13 | 0) > 1e6) {
+    _luaD_reallocstack(i5, 1000200);
+    _luaG_runerror(i5, 2224, i4);
+   } else {
+    _luaD_reallocstack(i5, i13);
+    i2 = HEAP32[i6 >> 2] | 0;
+    break;
+   }
+  } else {
+   i2 = i15;
+  }
+ } while (0);
+ HEAP32[i9 >> 2] = i2 + 320;
+ HEAP8[i8] = 0;
+ i16 = i10 + 18 | 0;
+ HEAP8[i16] = HEAPU8[i16] | 2;
+ FUNCTION_TABLE_vii[i3 & 15](i5, i4);
+ HEAP8[i8] = 1;
+ HEAP32[i9 >> 2] = (HEAP32[i1 >> 2] | 0) + i12;
+ HEAP32[i6 >> 2] = (HEAP32[i1 >> 2] | 0) + i7;
+ HEAP8[i16] = HEAP8[i16] & 253;
+ STACKTOP = i11;
+ return;
+}
+function _funcargs(i10, i2, i1) {
+ i10 = i10 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i6 = i3;
+ i9 = i10 + 48 | 0;
+ i5 = HEAP32[i9 >> 2] | 0;
+ i7 = i10 + 16 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 | 0) == 289) {
+  i9 = _luaK_stringK(i5, HEAP32[i10 + 24 >> 2] | 0) | 0;
+  HEAP32[i6 + 16 >> 2] = -1;
+  HEAP32[i6 + 20 >> 2] = -1;
+  HEAP32[i6 >> 2] = 4;
+  HEAP32[i6 + 8 >> 2] = i9;
+  _luaX_next(i10);
+ } else if ((i8 | 0) == 40) {
+  _luaX_next(i10);
+  if ((HEAP32[i7 >> 2] | 0) == 41) {
+   HEAP32[i6 >> 2] = 0;
+  } else {
+   _subexpr(i10, i6, 0) | 0;
+   if ((HEAP32[i7 >> 2] | 0) == 44) {
+    do {
+     _luaX_next(i10);
+     _luaK_exp2nextreg(HEAP32[i9 >> 2] | 0, i6);
+     _subexpr(i10, i6, 0) | 0;
+    } while ((HEAP32[i7 >> 2] | 0) == 44);
+   }
+   _luaK_setreturns(i5, i6, -1);
+  }
+  _check_match(i10, 41, 40, i1);
+ } else if ((i8 | 0) == 123) {
+  _constructor(i10, i6);
+ } else {
+  _luaX_syntaxerror(i10, 6624);
+ }
+ i8 = i2 + 8 | 0;
+ i7 = HEAP32[i8 >> 2] | 0;
+ i9 = HEAP32[i6 >> 2] | 0;
+ if ((i9 | 0) == 0) {
+  i4 = 13;
+ } else if ((i9 | 0) == 13 | (i9 | 0) == 12) {
+  i6 = 0;
+ } else {
+  _luaK_exp2nextreg(i5, i6);
+  i4 = 13;
+ }
+ if ((i4 | 0) == 13) {
+  i6 = (HEAPU8[i5 + 48 | 0] | 0) - i7 | 0;
+ }
+ i10 = _luaK_codeABC(i5, 29, i7, i6, 2) | 0;
+ HEAP32[i2 + 16 >> 2] = -1;
+ HEAP32[i2 + 20 >> 2] = -1;
+ HEAP32[i2 >> 2] = 12;
+ HEAP32[i8 >> 2] = i10;
+ _luaK_fixline(i5, i1);
+ HEAP8[i5 + 48 | 0] = i7 + 1;
+ STACKTOP = i3;
+ return;
+}
+function _luaD_reallocstack(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ i2 = i3 + 28 | 0;
+ i8 = HEAP32[i2 >> 2] | 0;
+ i7 = i3 + 32 | 0;
+ i9 = HEAP32[i7 >> 2] | 0;
+ if ((i6 + 1 | 0) >>> 0 > 268435455) {
+  _luaM_toobig(i3);
+ }
+ i5 = _luaM_realloc_(i3, i8, i9 << 4, i6 << 4) | 0;
+ HEAP32[i2 >> 2] = i5;
+ if ((i9 | 0) < (i6 | 0)) {
+  do {
+   HEAP32[i5 + (i9 << 4) + 8 >> 2] = 0;
+   i9 = i9 + 1 | 0;
+  } while ((i9 | 0) != (i6 | 0));
+ }
+ HEAP32[i7 >> 2] = i6;
+ HEAP32[i3 + 24 >> 2] = i5 + (i6 + -5 << 4);
+ i6 = i3 + 8 | 0;
+ HEAP32[i6 >> 2] = i5 + ((HEAP32[i6 >> 2] | 0) - i8 >> 4 << 4);
+ i6 = HEAP32[i3 + 56 >> 2] | 0;
+ if ((i6 | 0) != 0 ? (i4 = i6 + 8 | 0, HEAP32[i4 >> 2] = i5 + ((HEAP32[i4 >> 2] | 0) - i8 >> 4 << 4), i4 = HEAP32[i6 >> 2] | 0, (i4 | 0) != 0) : 0) {
+  do {
+   i9 = i4 + 8 | 0;
+   HEAP32[i9 >> 2] = (HEAP32[i2 >> 2] | 0) + ((HEAP32[i9 >> 2] | 0) - i8 >> 4 << 4);
+   i4 = HEAP32[i4 >> 2] | 0;
+  } while ((i4 | 0) != 0);
+ }
+ i3 = HEAP32[i3 + 16 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  i9 = i3 + 4 | 0;
+  HEAP32[i9 >> 2] = (HEAP32[i2 >> 2] | 0) + ((HEAP32[i9 >> 2] | 0) - i8 >> 4 << 4);
+  HEAP32[i3 >> 2] = (HEAP32[i2 >> 2] | 0) + ((HEAP32[i3 >> 2] | 0) - i8 >> 4 << 4);
+  if (!((HEAP8[i3 + 18 | 0] & 1) == 0)) {
+   i9 = i3 + 24 | 0;
+   HEAP32[i9 >> 2] = (HEAP32[i2 >> 2] | 0) + ((HEAP32[i9 >> 2] | 0) - i8 >> 4 << 4);
+  }
+  i3 = HEAP32[i3 + 8 >> 2] | 0;
+ } while ((i3 | 0) != 0);
+ STACKTOP = i1;
+ return;
+}
+function _luaF_close(i7, i6) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i7 + 12 >> 2] | 0;
+ i3 = i7 + 56 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i4 + 60 | 0;
+ i2 = i4 + 68 | 0;
+ while (1) {
+  i9 = i8 + 8 | 0;
+  if ((HEAP32[i9 >> 2] | 0) >>> 0 < i6 >>> 0) {
+   i2 = 10;
+   break;
+  }
+  HEAP32[i3 >> 2] = HEAP32[i8 >> 2];
+  if ((((HEAPU8[i5] | 0) ^ 3) & ((HEAPU8[i8 + 5 | 0] | 0) ^ 3) | 0) == 0) {
+   if ((HEAP32[i9 >> 2] | 0) != (i8 + 16 | 0)) {
+    i9 = i8 + 16 | 0;
+    i10 = i9 + 4 | 0;
+    HEAP32[(HEAP32[i10 >> 2] | 0) + 16 >> 2] = HEAP32[i9 >> 2];
+    HEAP32[(HEAP32[i9 >> 2] | 0) + 20 >> 2] = HEAP32[i10 >> 2];
+   }
+   _luaM_realloc_(i7, i8, 32, 0) | 0;
+  } else {
+   i11 = i8 + 16 | 0;
+   i10 = i11 + 4 | 0;
+   HEAP32[(HEAP32[i10 >> 2] | 0) + 16 >> 2] = HEAP32[i11 >> 2];
+   HEAP32[(HEAP32[i11 >> 2] | 0) + 20 >> 2] = HEAP32[i10 >> 2];
+   i11 = HEAP32[i9 >> 2] | 0;
+   i10 = i8 + 16 | 0;
+   i14 = i11;
+   i13 = HEAP32[i14 + 4 >> 2] | 0;
+   i12 = i10;
+   HEAP32[i12 >> 2] = HEAP32[i14 >> 2];
+   HEAP32[i12 + 4 >> 2] = i13;
+   HEAP32[i8 + 24 >> 2] = HEAP32[i11 + 8 >> 2];
+   HEAP32[i9 >> 2] = i10;
+   HEAP32[i8 >> 2] = HEAP32[i2 >> 2];
+   HEAP32[i2 >> 2] = i8;
+   _luaC_checkupvalcolor(i4, i8);
+  }
+  i8 = HEAP32[i3 >> 2] | 0;
+  if ((i8 | 0) == 0) {
+   i2 = 10;
+   break;
+  }
+ }
+ if ((i2 | 0) == 10) {
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaK_dischargevars(i3, i1) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ switch (HEAP32[i1 >> 2] | 0) {
+ case 12:
+  {
+   HEAP32[i1 >> 2] = 6;
+   i6 = i1 + 8 | 0;
+   HEAP32[i6 >> 2] = (HEAP32[(HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i6 >> 2] << 2) >> 2] | 0) >>> 6 & 255;
+   STACKTOP = i2;
+   return;
+  }
+ case 13:
+  {
+   i6 = (HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i1 + 8 >> 2] << 2) | 0;
+   HEAP32[i6 >> 2] = HEAP32[i6 >> 2] & 8388607 | 16777216;
+   HEAP32[i1 >> 2] = 11;
+   STACKTOP = i2;
+   return;
+  }
+ case 9:
+  {
+   i4 = i1 + 8 | 0;
+   i5 = HEAP16[i4 >> 1] | 0;
+   if ((i5 & 256 | 0) == 0 ? (HEAPU8[i3 + 46 | 0] | 0) <= (i5 | 0) : 0) {
+    i6 = i3 + 48 | 0;
+    HEAP8[i6] = (HEAP8[i6] | 0) + -1 << 24 >> 24;
+   }
+   i5 = i4 + 2 | 0;
+   if ((HEAP8[i4 + 3 | 0] | 0) == 7) {
+    if ((HEAPU8[i3 + 46 | 0] | 0) > (HEAPU8[i5] | 0)) {
+     i6 = 7;
+    } else {
+     i6 = i3 + 48 | 0;
+     HEAP8[i6] = (HEAP8[i6] | 0) + -1 << 24 >> 24;
+     i6 = 7;
+    }
+   } else {
+    i6 = 6;
+   }
+   HEAP32[i4 >> 2] = _luaK_code(i3, HEAPU8[i5] << 23 | i6 | HEAP16[i4 >> 1] << 14) | 0;
+   HEAP32[i1 >> 2] = 11;
+   STACKTOP = i2;
+   return;
+  }
+ case 7:
+  {
+   HEAP32[i1 >> 2] = 6;
+   STACKTOP = i2;
+   return;
+  }
+ case 8:
+  {
+   i6 = i1 + 8 | 0;
+   HEAP32[i6 >> 2] = _luaK_code(i3, HEAP32[i6 >> 2] << 23 | 5) | 0;
+   HEAP32[i1 >> 2] = 11;
+   STACKTOP = i2;
+   return;
+  }
+ default:
+  {
+   STACKTOP = i2;
+   return;
+  }
+ }
+}
+function _gmatch_aux(i10) {
+ i10 = i10 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 288 | 0;
+ i2 = i1 + 8 | 0;
+ i12 = i1 + 4 | 0;
+ i3 = i1;
+ i8 = _lua_tolstring(i10, -1001001, i12) | 0;
+ i7 = _lua_tolstring(i10, -1001002, i3) | 0;
+ i5 = i2 + 16 | 0;
+ HEAP32[i5 >> 2] = i10;
+ HEAP32[i2 >> 2] = 200;
+ HEAP32[i2 + 4 >> 2] = i8;
+ i9 = i2 + 8 | 0;
+ HEAP32[i9 >> 2] = i8 + (HEAP32[i12 >> 2] | 0);
+ HEAP32[i2 + 12 >> 2] = i7 + (HEAP32[i3 >> 2] | 0);
+ i3 = i8 + (_lua_tointegerx(i10, -1001003, 0) | 0) | 0;
+ if (i3 >>> 0 > (HEAP32[i9 >> 2] | 0) >>> 0) {
+  i12 = 0;
+  STACKTOP = i1;
+  return i12 | 0;
+ }
+ i11 = i2 + 20 | 0;
+ while (1) {
+  HEAP32[i11 >> 2] = 0;
+  i4 = _match(i2, i3, i7) | 0;
+  i12 = i3 + 1 | 0;
+  if ((i4 | 0) != 0) {
+   break;
+  }
+  if (i12 >>> 0 > (HEAP32[i9 >> 2] | 0) >>> 0) {
+   i2 = 0;
+   i6 = 7;
+   break;
+  } else {
+   i3 = i12;
+  }
+ }
+ if ((i6 | 0) == 7) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ _lua_pushinteger(i10, i4 - i8 + ((i4 | 0) == (i3 | 0)) | 0);
+ _lua_replace(i10, -1001003);
+ i7 = HEAP32[i11 >> 2] | 0;
+ i6 = (i7 | 0) != 0 | (i3 | 0) == 0 ? i7 : 1;
+ _luaL_checkstack(HEAP32[i5 >> 2] | 0, i6, 7200);
+ if ((i6 | 0) > 0) {
+  i5 = 0;
+ } else {
+  i12 = i7;
+  STACKTOP = i1;
+  return i12 | 0;
+ }
+ while (1) {
+  _push_onecapture(i2, i5, i3, i4);
+  i5 = i5 + 1 | 0;
+  if ((i5 | 0) == (i6 | 0)) {
+   i2 = i6;
+   break;
+  }
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _lua_rawseti(i1, i5, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i6 >> 2] | 0, (i5 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i4 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i6 >> 2] | 0) + (i5 << 4) | 0;
+   i5 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i4 = i1 + 8 | 0;
+ _luaH_setint(i1, HEAP32[i5 >> 2] | 0, i3, (HEAP32[i4 >> 2] | 0) + -16 | 0);
+ i3 = HEAP32[i4 >> 2] | 0;
+ if ((HEAP32[i3 + -8 >> 2] & 64 | 0) == 0) {
+  i6 = i3;
+  i6 = i6 + -16 | 0;
+  HEAP32[i4 >> 2] = i6;
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[(HEAP32[i3 + -16 >> 2] | 0) + 5 | 0] & 3) == 0) {
+  i6 = i3;
+  i6 = i6 + -16 | 0;
+  HEAP32[i4 >> 2] = i6;
+  STACKTOP = i2;
+  return;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((HEAP8[i5 + 5 | 0] & 4) == 0) {
+  i6 = i3;
+  i6 = i6 + -16 | 0;
+  HEAP32[i4 >> 2] = i6;
+  STACKTOP = i2;
+  return;
+ }
+ _luaC_barrierback_(i1, i5);
+ i6 = HEAP32[i4 >> 2] | 0;
+ i6 = i6 + -16 | 0;
+ HEAP32[i4 >> 2] = i6;
+ STACKTOP = i2;
+ return;
+}
+function _ll_require(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i5 = i2;
+ i4 = i2 + 8 | 0;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ _lua_settop(i1, 1);
+ _lua_getfield(i1, -1001e3, 4576);
+ _lua_getfield(i1, 2, i3);
+ if ((_lua_toboolean(i1, -1) | 0) != 0) {
+  STACKTOP = i2;
+  return 1;
+ }
+ _lua_settop(i1, -2);
+ _luaL_buffinit(i1, i4);
+ _lua_getfield(i1, -1001001, 4240);
+ if ((_lua_type(i1, 3) | 0) == 5) {
+  i6 = 1;
+ } else {
+  _luaL_error(i1, 4656, i5) | 0;
+  i6 = 1;
+ }
+ while (1) {
+  _lua_rawgeti(i1, 3, i6);
+  if ((_lua_type(i1, -1) | 0) == 0) {
+   _lua_settop(i1, -2);
+   _luaL_pushresult(i4);
+   i7 = _lua_tolstring(i1, -1, 0) | 0;
+   HEAP32[i5 >> 2] = i3;
+   HEAP32[i5 + 4 >> 2] = i7;
+   _luaL_error(i1, 4696, i5) | 0;
+  }
+  _lua_pushstring(i1, i3) | 0;
+  _lua_callk(i1, 1, 2, 0, 0);
+  if ((_lua_type(i1, -2) | 0) == 6) {
+   break;
+  }
+  if ((_lua_isstring(i1, -2) | 0) == 0) {
+   _lua_settop(i1, -3);
+  } else {
+   _lua_settop(i1, -2);
+   _luaL_addvalue(i4);
+  }
+  i6 = i6 + 1 | 0;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_insert(i1, -2);
+ _lua_callk(i1, 2, 1, 0, 0);
+ if ((_lua_type(i1, -1) | 0) != 0) {
+  _lua_setfield(i1, 2, i3);
+ }
+ _lua_getfield(i1, 2, i3);
+ if ((_lua_type(i1, -1) | 0) != 0) {
+  STACKTOP = i2;
+  return 1;
+ }
+ _lua_pushboolean(i1, 1);
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, 2, i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _f_parser(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i8 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i8 + -1;
+ if ((i8 | 0) == 0) {
+  i6 = _luaZ_fill(i5) | 0;
+ } else {
+  i8 = i5 + 4 | 0;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  i6 = HEAPU8[i6] | 0;
+ }
+ i5 = HEAP32[i3 + 52 >> 2] | 0;
+ i7 = (i5 | 0) == 0;
+ if ((i6 | 0) == 27) {
+  if (!i7 ? (_strchr(i5, 98) | 0) == 0 : 0) {
+   HEAP32[i4 >> 2] = 2360;
+   HEAP32[i4 + 4 >> 2] = i5;
+   _luaO_pushfstring(i1, 2376, i4) | 0;
+   _luaD_throw(i1, 3);
+  }
+  i8 = _luaU_undump(i1, HEAP32[i3 >> 2] | 0, i3 + 4 | 0, HEAP32[i3 + 56 >> 2] | 0) | 0;
+ } else {
+  if (!i7 ? (_strchr(i5, 116) | 0) == 0 : 0) {
+   HEAP32[i4 >> 2] = 2368;
+   HEAP32[i4 + 4 >> 2] = i5;
+   _luaO_pushfstring(i1, 2376, i4) | 0;
+   _luaD_throw(i1, 3);
+  }
+  i8 = _luaY_parser(i1, HEAP32[i3 >> 2] | 0, i3 + 4 | 0, i3 + 16 | 0, HEAP32[i3 + 56 >> 2] | 0, i6) | 0;
+ }
+ i7 = i8 + 6 | 0;
+ if ((HEAP8[i7] | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i5 = i8 + 16 | 0;
+ i6 = i8 + 5 | 0;
+ i4 = 0;
+ do {
+  i3 = _luaF_newupval(i1) | 0;
+  HEAP32[i5 + (i4 << 2) >> 2] = i3;
+  if (!((HEAP8[i3 + 5 | 0] & 3) == 0) ? !((HEAP8[i6] & 4) == 0) : 0) {
+   _luaC_barrier_(i1, i8, i3);
+  }
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) < (HEAPU8[i7] | 0));
+ STACKTOP = i2;
+ return;
+}
+function _str_rep(i9) {
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i6;
+ i2 = i6 + 1044 | 0;
+ i3 = i6 + 1040 | 0;
+ i1 = _luaL_checklstring(i9, 1, i2) | 0;
+ i8 = _luaL_checkinteger(i9, 2) | 0;
+ i5 = _luaL_optlstring(i9, 3, 7040, i3) | 0;
+ if ((i8 | 0) < 1) {
+  _lua_pushlstring(i9, 7040, 0) | 0;
+  i12 = 1;
+  STACKTOP = i6;
+  return i12 | 0;
+ }
+ i7 = HEAP32[i2 >> 2] | 0;
+ i10 = HEAP32[i3 >> 2] | 0;
+ i11 = i10 + i7 | 0;
+ if (!(i11 >>> 0 < i7 >>> 0) ? i11 >>> 0 < (2147483647 / (i8 >>> 0) | 0) >>> 0 : 0) {
+  i7 = (Math_imul(i10, i8 + -1 | 0) | 0) + (Math_imul(i7, i8) | 0) | 0;
+  i11 = _luaL_buffinitsize(i9, i4, i7) | 0;
+  _memcpy(i11 | 0, i1 | 0, HEAP32[i2 >> 2] | 0) | 0;
+  if ((i8 | 0) > 1) {
+   while (1) {
+    i8 = i8 + -1 | 0;
+    i9 = HEAP32[i2 >> 2] | 0;
+    i10 = i11 + i9 | 0;
+    i12 = HEAP32[i3 >> 2] | 0;
+    if ((i12 | 0) == 0) {
+     i12 = i9;
+    } else {
+     _memcpy(i10 | 0, i5 | 0, i12 | 0) | 0;
+     i12 = HEAP32[i2 >> 2] | 0;
+     i10 = i11 + ((HEAP32[i3 >> 2] | 0) + i9) | 0;
+    }
+    _memcpy(i10 | 0, i1 | 0, i12 | 0) | 0;
+    if ((i8 | 0) <= 1) {
+     break;
+    } else {
+     i11 = i10;
+    }
+   }
+  }
+  _luaL_pushresultsize(i4, i7);
+  i12 = 1;
+  STACKTOP = i6;
+  return i12 | 0;
+ }
+ i12 = _luaL_error(i9, 7168, i4) | 0;
+ STACKTOP = i6;
+ return i12 | 0;
+}
+function ___strchrnul(i6, i2) {
+ i6 = i6 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i3 = i2 & 255;
+ if ((i3 | 0) == 0) {
+  i7 = i6 + (_strlen(i6 | 0) | 0) | 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ L5 : do {
+  if ((i6 & 3 | 0) != 0) {
+   i4 = i2 & 255;
+   while (1) {
+    i5 = HEAP8[i6] | 0;
+    if (i5 << 24 >> 24 == 0) {
+     i4 = i6;
+     i5 = 13;
+     break;
+    }
+    i7 = i6 + 1 | 0;
+    if (i5 << 24 >> 24 == i4 << 24 >> 24) {
+     i4 = i6;
+     i5 = 13;
+     break;
+    }
+    if ((i7 & 3 | 0) == 0) {
+     i4 = i7;
+     break L5;
+    } else {
+     i6 = i7;
+    }
+   }
+   if ((i5 | 0) == 13) {
+    STACKTOP = i1;
+    return i4 | 0;
+   }
+  } else {
+   i4 = i6;
+  }
+ } while (0);
+ i3 = Math_imul(i3, 16843009) | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ L15 : do {
+  if (((i6 & -2139062144 ^ -2139062144) & i6 + -16843009 | 0) == 0) {
+   while (1) {
+    i7 = i6 ^ i3;
+    i5 = i4 + 4 | 0;
+    if (((i7 & -2139062144 ^ -2139062144) & i7 + -16843009 | 0) != 0) {
+     break L15;
+    }
+    i6 = HEAP32[i5 >> 2] | 0;
+    if (((i6 & -2139062144 ^ -2139062144) & i6 + -16843009 | 0) == 0) {
+     i4 = i5;
+    } else {
+     i4 = i5;
+     break;
+    }
+   }
+  }
+ } while (0);
+ i2 = i2 & 255;
+ while (1) {
+  i7 = HEAP8[i4] | 0;
+  if (i7 << 24 >> 24 == 0 | i7 << 24 >> 24 == i2 << 24 >> 24) {
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _lua_replace(i2, i6) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i3 = STACKTOP;
+ i7 = i2 + 8 | 0;
+ i9 = HEAP32[i7 >> 2] | 0;
+ i5 = i9 + -16 | 0;
+ i4 = i2 + 16 | 0;
+ i12 = HEAP32[i4 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i10 = i9 + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i10 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i11 = -1001e3 - i6 | 0;
+   i12 = HEAP32[i12 >> 2] | 0;
+   if ((HEAP32[i12 + 8 >> 2] | 0) != 22 ? (i10 = HEAP32[i12 >> 2] | 0, (i11 | 0) <= (HEAPU8[i10 + 6 | 0] | 0 | 0)) : 0) {
+    i10 = i10 + (i11 + -1 << 4) + 16 | 0;
+   } else {
+    i10 = 5192;
+   }
+  } else {
+   i10 = (HEAP32[i12 >> 2] | 0) + (i6 << 4) | 0;
+   i10 = i10 >>> 0 < i9 >>> 0 ? i10 : 5192;
+  }
+ } while (0);
+ i13 = i5;
+ i11 = HEAP32[i13 + 4 >> 2] | 0;
+ i12 = i10;
+ HEAP32[i12 >> 2] = HEAP32[i13 >> 2];
+ HEAP32[i12 + 4 >> 2] = i11;
+ i9 = i9 + -8 | 0;
+ HEAP32[i10 + 8 >> 2] = HEAP32[i9 >> 2];
+ if ((((i6 | 0) < -1001e3 ? (HEAP32[i9 >> 2] & 64 | 0) != 0 : 0) ? (i1 = HEAP32[i5 >> 2] | 0, !((HEAP8[i1 + 5 | 0] & 3) == 0)) : 0) ? (i8 = HEAP32[HEAP32[HEAP32[i4 >> 2] >> 2] >> 2] | 0, !((HEAP8[i8 + 5 | 0] & 4) == 0)) : 0) {
+  _luaC_barrier_(i2, i8, i1);
+ }
+ HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + -16;
+ STACKTOP = i3;
+ return;
+}
+function _memchr(i4, i3, i6) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i2 = i3 & 255;
+ i7 = (i6 | 0) == 0;
+ L1 : do {
+  if ((i4 & 3 | 0) == 0 | i7) {
+   i5 = i6;
+   i6 = 5;
+  } else {
+   i5 = i3 & 255;
+   while (1) {
+    if ((HEAP8[i4] | 0) == i5 << 24 >> 24) {
+     i5 = i6;
+     i6 = 6;
+     break L1;
+    }
+    i4 = i4 + 1 | 0;
+    i6 = i6 + -1 | 0;
+    i7 = (i6 | 0) == 0;
+    if ((i4 & 3 | 0) == 0 | i7) {
+     i5 = i6;
+     i6 = 5;
+     break;
+    }
+   }
+  }
+ } while (0);
+ if ((i6 | 0) == 5) {
+  if (i7) {
+   i5 = 0;
+  } else {
+   i6 = 6;
+  }
+ }
+ L8 : do {
+  if ((i6 | 0) == 6) {
+   i3 = i3 & 255;
+   if (!((HEAP8[i4] | 0) == i3 << 24 >> 24)) {
+    i2 = Math_imul(i2, 16843009) | 0;
+    L11 : do {
+     if (i5 >>> 0 > 3) {
+      do {
+       i7 = HEAP32[i4 >> 2] ^ i2;
+       if (((i7 & -2139062144 ^ -2139062144) & i7 + -16843009 | 0) != 0) {
+        break L11;
+       }
+       i4 = i4 + 4 | 0;
+       i5 = i5 + -4 | 0;
+      } while (i5 >>> 0 > 3);
+     }
+    } while (0);
+    if ((i5 | 0) == 0) {
+     i5 = 0;
+    } else {
+     while (1) {
+      if ((HEAP8[i4] | 0) == i3 << 24 >> 24) {
+       break L8;
+      }
+      i4 = i4 + 1 | 0;
+      i5 = i5 + -1 | 0;
+      if ((i5 | 0) == 0) {
+       i5 = 0;
+       break;
+      }
+     }
+    }
+   }
+  }
+ } while (0);
+ STACKTOP = i1;
+ return ((i5 | 0) != 0 ? i4 : 0) | 0;
+}
+function _lua_insert(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i2 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i2 = i2 + 8 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if (i4 >>> 0 > i3 >>> 0) {
+  while (1) {
+   i5 = i4 + -16 | 0;
+   i8 = i5;
+   i7 = HEAP32[i8 + 4 >> 2] | 0;
+   i6 = i4;
+   HEAP32[i6 >> 2] = HEAP32[i8 >> 2];
+   HEAP32[i6 + 4 >> 2] = i7;
+   HEAP32[i4 + 8 >> 2] = HEAP32[i4 + -8 >> 2];
+   if (i5 >>> 0 > i3 >>> 0) {
+    i4 = i5;
+   } else {
+    break;
+   }
+  }
+  i4 = HEAP32[i2 >> 2] | 0;
+ }
+ i6 = i4;
+ i7 = HEAP32[i6 + 4 >> 2] | 0;
+ i8 = i3;
+ HEAP32[i8 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i8 + 4 >> 2] = i7;
+ HEAP32[i3 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+ STACKTOP = i1;
+ return;
+}
+function _findlocal(i6, i4, i1, i2) {
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ do {
+  if ((HEAP8[i4 + 18 | 0] & 1) == 0) {
+   i7 = (HEAP32[i4 >> 2] | 0) + 16 | 0;
+   i5 = 7;
+  } else {
+   if ((i1 | 0) >= 0) {
+    i8 = HEAP32[i4 + 24 >> 2] | 0;
+    i7 = HEAP32[(HEAP32[HEAP32[i4 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+    i7 = _luaF_getlocalname(i7, i1, ((HEAP32[i4 + 28 >> 2] | 0) - (HEAP32[i7 + 12 >> 2] | 0) >> 2) + -1 | 0) | 0;
+    if ((i7 | 0) == 0) {
+     i7 = i8;
+     i5 = 7;
+     break;
+    } else {
+     break;
+    }
+   }
+   i5 = HEAP32[i4 >> 2] | 0;
+   i6 = HEAPU8[(HEAP32[(HEAP32[i5 >> 2] | 0) + 12 >> 2] | 0) + 76 | 0] | 0;
+   if ((((HEAP32[i4 + 24 >> 2] | 0) - i5 >> 4) - i6 | 0) <= (0 - i1 | 0)) {
+    i8 = 0;
+    STACKTOP = i3;
+    return i8 | 0;
+   }
+   HEAP32[i2 >> 2] = i5 + (i6 - i1 << 4);
+   i8 = 2208;
+   STACKTOP = i3;
+   return i8 | 0;
+  }
+ } while (0);
+ if ((i5 | 0) == 7) {
+  if ((HEAP32[i6 + 16 >> 2] | 0) == (i4 | 0)) {
+   i4 = i6 + 8 | 0;
+  } else {
+   i4 = HEAP32[i4 + 12 >> 2] | 0;
+  }
+  if (((HEAP32[i4 >> 2] | 0) - i7 >> 4 | 0) >= (i1 | 0) & (i1 | 0) > 0) {
+   i8 = i7;
+   i7 = 2192;
+  } else {
+   i8 = 0;
+   STACKTOP = i3;
+   return i8 | 0;
+  }
+ }
+ HEAP32[i2 >> 2] = i8 + (i1 + -1 << 4);
+ i8 = i7;
+ STACKTOP = i3;
+ return i8 | 0;
+}
+function _luaH_setint(i4, i5, i6, i1) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, d7 = 0.0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i8 = i2 + 16 | 0;
+ i3 = i2;
+ i9 = i6 + -1 | 0;
+ L1 : do {
+  if (i9 >>> 0 < (HEAP32[i5 + 28 >> 2] | 0) >>> 0) {
+   i9 = (HEAP32[i5 + 12 >> 2] | 0) + (i9 << 4) | 0;
+   i8 = 10;
+  } else {
+   d7 = +(i6 | 0);
+   HEAPF64[i8 >> 3] = d7 + 1.0;
+   i8 = (HEAP32[i8 + 4 >> 2] | 0) + (HEAP32[i8 >> 2] | 0) | 0;
+   if ((i8 | 0) < 0) {
+    i9 = 0 - i8 | 0;
+    i8 = (i8 | 0) == (i9 | 0) ? 0 : i9;
+   }
+   i9 = (HEAP32[i5 + 16 >> 2] | 0) + (((i8 | 0) % ((1 << (HEAPU8[i5 + 7 | 0] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+   while (1) {
+    if ((HEAP32[i9 + 24 >> 2] | 0) == 3 ? +HEAPF64[i9 + 16 >> 3] == d7 : 0) {
+     break;
+    }
+    i9 = HEAP32[i9 + 28 >> 2] | 0;
+    if ((i9 | 0) == 0) {
+     i8 = 12;
+     break L1;
+    }
+   }
+   i8 = 10;
+  }
+ } while (0);
+ if ((i8 | 0) == 10) {
+  if ((i9 | 0) == 5192) {
+   d7 = +(i6 | 0);
+   i8 = 12;
+  }
+ }
+ if ((i8 | 0) == 12) {
+  HEAPF64[i3 >> 3] = d7;
+  HEAP32[i3 + 8 >> 2] = 3;
+  i9 = _luaH_newkey(i4, i5, i3) | 0;
+ }
+ i5 = i1;
+ i6 = HEAP32[i5 + 4 >> 2] | 0;
+ i8 = i9;
+ HEAP32[i8 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i8 + 4 >> 2] = i6;
+ HEAP32[i9 + 8 >> 2] = HEAP32[i1 + 8 >> 2];
+ STACKTOP = i2;
+ return;
+}
+function _lua_tounsignedx(i6, i8, i1) {
+ i6 = i6 | 0;
+ i8 = i8 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i4 = i2 + 8 | 0;
+ i3 = i2;
+ i7 = HEAP32[i6 + 16 >> 2] | 0;
+ do {
+  if ((i8 | 0) <= 0) {
+   if (!((i8 | 0) < -1000999)) {
+    i5 = (HEAP32[i6 + 8 >> 2] | 0) + (i8 << 4) | 0;
+    break;
+   }
+   if ((i8 | 0) == -1001e3) {
+    i5 = (HEAP32[i6 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i8 | 0;
+   i7 = HEAP32[i7 >> 2] | 0;
+   if ((HEAP32[i7 + 8 >> 2] | 0) != 22 ? (i5 = HEAP32[i7 >> 2] | 0, (i6 | 0) <= (HEAPU8[i5 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i5 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i5 = (HEAP32[i7 >> 2] | 0) + (i8 << 4) | 0;
+   i5 = i5 >>> 0 < (HEAP32[i6 + 8 >> 2] | 0) >>> 0 ? i5 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i5 + 8 >> 2] | 0) != 3) {
+  i5 = _luaV_tonumber(i5, i4) | 0;
+  if ((i5 | 0) == 0) {
+   if ((i1 | 0) == 0) {
+    i8 = 0;
+    STACKTOP = i2;
+    return i8 | 0;
+   }
+   HEAP32[i1 >> 2] = 0;
+   i8 = 0;
+   STACKTOP = i2;
+   return i8 | 0;
+  }
+ }
+ HEAPF64[i3 >> 3] = +HEAPF64[i5 >> 3] + 6755399441055744.0;
+ i3 = HEAP32[i3 >> 2] | 0;
+ if ((i1 | 0) == 0) {
+  i8 = i3;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ HEAP32[i1 >> 2] = 1;
+ i8 = i3;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _luaC_freeallobjects(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i5 = i1 + 12 | 0;
+ i3 = HEAP32[i5 >> 2] | 0;
+ i7 = i3 + 104 | 0;
+ while (1) {
+  i4 = HEAP32[i7 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   break;
+  } else {
+   i7 = i4;
+  }
+ }
+ i4 = i3 + 72 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  i5 = i3;
+ } else {
+  while (1) {
+   i8 = i6 + 5 | 0;
+   HEAP8[i8] = HEAPU8[i8] | 0 | 8;
+   HEAP32[i4 >> 2] = HEAP32[i6 >> 2];
+   HEAP32[i6 >> 2] = HEAP32[i7 >> 2];
+   HEAP32[i7 >> 2] = i6;
+   i7 = HEAP32[i4 >> 2] | 0;
+   if ((i7 | 0) == 0) {
+    break;
+   } else {
+    i8 = i6;
+    i6 = i7;
+    i7 = i8;
+   }
+  }
+  i5 = HEAP32[i5 >> 2] | 0;
+ }
+ i5 = i5 + 104 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if ((i6 | 0) != 0) {
+  do {
+   i8 = i6 + 5 | 0;
+   HEAP8[i8] = HEAP8[i8] & 191;
+   _GCTM(i1, 0);
+   i6 = HEAP32[i5 >> 2] | 0;
+  } while ((i6 | 0) != 0);
+ }
+ HEAP8[i3 + 60 | 0] = 3;
+ HEAP8[i3 + 62 | 0] = 0;
+ _sweeplist(i1, i4, -3) | 0;
+ _sweeplist(i1, i3 + 68 | 0, -3) | 0;
+ i4 = i3 + 32 | 0;
+ if ((HEAP32[i4 >> 2] | 0) <= 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i3 + 24 | 0;
+ i5 = 0;
+ do {
+  _sweeplist(i1, (HEAP32[i3 >> 2] | 0) + (i5 << 2) | 0, -3) | 0;
+  i5 = i5 + 1 | 0;
+ } while ((i5 | 0) < (HEAP32[i4 >> 2] | 0));
+ STACKTOP = i2;
+ return;
+}
+function _strspn(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i2;
+ HEAP32[i3 + 0 >> 2] = 0;
+ HEAP32[i3 + 4 >> 2] = 0;
+ HEAP32[i3 + 8 >> 2] = 0;
+ HEAP32[i3 + 12 >> 2] = 0;
+ HEAP32[i3 + 16 >> 2] = 0;
+ HEAP32[i3 + 20 >> 2] = 0;
+ HEAP32[i3 + 24 >> 2] = 0;
+ HEAP32[i3 + 28 >> 2] = 0;
+ i4 = HEAP8[i5] | 0;
+ if (i4 << 24 >> 24 == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ if ((HEAP8[i5 + 1 | 0] | 0) == 0) {
+  i3 = i1;
+  while (1) {
+   if ((HEAP8[i3] | 0) == i4 << 24 >> 24) {
+    i3 = i3 + 1 | 0;
+   } else {
+    break;
+   }
+  }
+  i6 = i3 - i1 | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ do {
+  i7 = i4 & 255;
+  i6 = i3 + (i7 >>> 5 << 2) | 0;
+  HEAP32[i6 >> 2] = HEAP32[i6 >> 2] | 1 << (i7 & 31);
+  i5 = i5 + 1 | 0;
+  i4 = HEAP8[i5] | 0;
+ } while (!(i4 << 24 >> 24 == 0));
+ i5 = HEAP8[i1] | 0;
+ L12 : do {
+  if (i5 << 24 >> 24 == 0) {
+   i4 = i1;
+  } else {
+   i4 = i1;
+   while (1) {
+    i7 = i5 & 255;
+    i6 = i4 + 1 | 0;
+    if ((HEAP32[i3 + (i7 >>> 5 << 2) >> 2] & 1 << (i7 & 31) | 0) == 0) {
+     break L12;
+    }
+    i5 = HEAP8[i6] | 0;
+    if (i5 << 24 >> 24 == 0) {
+     i4 = i6;
+     break;
+    } else {
+     i4 = i6;
+    }
+   }
+  }
+ } while (0);
+ i7 = i4 - i1 | 0;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _lua_remove(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i5 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i3 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i3 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i4 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i5 >> 2] | 0) + (i4 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i4 = i3 + 16 | 0;
+ i2 = i2 + 8 | 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ if (!(i4 >>> 0 < i5 >>> 0)) {
+  i5 = i5 + -16 | 0;
+  HEAP32[i2 >> 2] = i5;
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i7 = i4;
+  i6 = HEAP32[i7 + 4 >> 2] | 0;
+  i5 = i3;
+  HEAP32[i5 >> 2] = HEAP32[i7 >> 2];
+  HEAP32[i5 + 4 >> 2] = i6;
+  HEAP32[i3 + 8 >> 2] = HEAP32[i3 + 24 >> 2];
+  i5 = i4 + 16 | 0;
+  i3 = HEAP32[i2 >> 2] | 0;
+  if (i5 >>> 0 < i3 >>> 0) {
+   i3 = i4;
+   i4 = i5;
+  } else {
+   break;
+  }
+ }
+ i7 = i3 + -16 | 0;
+ HEAP32[i2 >> 2] = i7;
+ STACKTOP = i1;
+ return;
+}
+function _luaD_protectedparser(i1, i4, i3, i2) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i13 = i5;
+ i6 = i1 + 36 | 0;
+ HEAP16[i6 >> 1] = (HEAP16[i6 >> 1] | 0) + 1 << 16 >> 16;
+ HEAP32[i13 >> 2] = i4;
+ HEAP32[i13 + 56 >> 2] = i3;
+ HEAP32[i13 + 52 >> 2] = i2;
+ i10 = i13 + 16 | 0;
+ HEAP32[i10 >> 2] = 0;
+ i9 = i13 + 24 | 0;
+ HEAP32[i9 >> 2] = 0;
+ i8 = i13 + 28 | 0;
+ HEAP32[i8 >> 2] = 0;
+ i7 = i13 + 36 | 0;
+ HEAP32[i7 >> 2] = 0;
+ i2 = i13 + 40 | 0;
+ HEAP32[i2 >> 2] = 0;
+ i3 = i13 + 48 | 0;
+ HEAP32[i3 >> 2] = 0;
+ i12 = i13 + 4 | 0;
+ HEAP32[i12 >> 2] = 0;
+ i11 = i13 + 12 | 0;
+ HEAP32[i11 >> 2] = 0;
+ i4 = _luaD_pcall(i1, 6, i13, (HEAP32[i1 + 8 >> 2] | 0) - (HEAP32[i1 + 28 >> 2] | 0) | 0, HEAP32[i1 + 68 >> 2] | 0) | 0;
+ HEAP32[i12 >> 2] = _luaM_realloc_(i1, HEAP32[i12 >> 2] | 0, HEAP32[i11 >> 2] | 0, 0) | 0;
+ HEAP32[i11 >> 2] = 0;
+ _luaM_realloc_(i1, HEAP32[i10 >> 2] | 0, HEAP32[i9 >> 2] << 1, 0) | 0;
+ _luaM_realloc_(i1, HEAP32[i8 >> 2] | 0, HEAP32[i7 >> 2] << 4, 0) | 0;
+ _luaM_realloc_(i1, HEAP32[i2 >> 2] | 0, HEAP32[i3 >> 2] << 4, 0) | 0;
+ HEAP16[i6 >> 1] = (HEAP16[i6 >> 1] | 0) + -1 << 16 >> 16;
+ STACKTOP = i5;
+ return i4 | 0;
+}
+function _markmt(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 252 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 256 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 260 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 264 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 268 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 272 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 276 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 280 >> 2] | 0;
+ if ((i3 | 0) != 0 ? !((HEAP8[i3 + 5 | 0] & 3) == 0) : 0) {
+  _reallymarkobject(i1, i3);
+ }
+ i3 = HEAP32[i1 + 284 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[i3 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _reallymarkobject(i1, i3);
+ STACKTOP = i2;
+ return;
+}
+function _findlabel(i9, i2) {
+ i9 = i9 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
+ i1 = STACKTOP;
+ i3 = i9 + 48 | 0;
+ i7 = HEAP32[(HEAP32[i3 >> 2] | 0) + 16 >> 2] | 0;
+ i10 = HEAP32[i9 + 64 >> 2] | 0;
+ i4 = HEAP32[i10 + 12 >> 2] | 0;
+ i6 = i7 + 4 | 0;
+ i13 = HEAP16[i6 >> 1] | 0;
+ i5 = i10 + 28 | 0;
+ if ((i13 | 0) >= (HEAP32[i5 >> 2] | 0)) {
+  i15 = 0;
+  STACKTOP = i1;
+  return i15 | 0;
+ }
+ i10 = i10 + 24 | 0;
+ i11 = i4 + (i2 << 4) | 0;
+ while (1) {
+  i14 = HEAP32[i10 >> 2] | 0;
+  i12 = i14 + (i13 << 4) | 0;
+  i15 = i13 + 1 | 0;
+  if ((_luaS_eqstr(HEAP32[i12 >> 2] | 0, HEAP32[i11 >> 2] | 0) | 0) != 0) {
+   break;
+  }
+  if ((i15 | 0) < (HEAP32[i5 >> 2] | 0)) {
+   i13 = i15;
+  } else {
+   i2 = 0;
+   i8 = 10;
+   break;
+  }
+ }
+ if ((i8 | 0) == 10) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ i8 = HEAP8[i14 + (i13 << 4) + 12 | 0] | 0;
+ do {
+  if ((HEAPU8[i4 + (i2 << 4) + 12 | 0] | 0) > (i8 & 255)) {
+   if ((HEAP8[i7 + 9 | 0] | 0) == 0 ? (HEAP32[i5 >> 2] | 0) <= (HEAP16[i6 >> 1] | 0) : 0) {
+    break;
+   }
+   _luaK_patchclose(HEAP32[i3 >> 2] | 0, HEAP32[i4 + (i2 << 4) + 4 >> 2] | 0, i8 & 255);
+  }
+ } while (0);
+ _closegoto(i9, i2, i12);
+ i15 = 1;
+ STACKTOP = i1;
+ return i15 | 0;
+}
+function _lua_getmetatable(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i4 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i3 = HEAP32[i4 + 8 >> 2] & 15;
+ if ((i3 | 0) == 7) {
+  i3 = HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] | 0;
+ } else if ((i3 | 0) == 5) {
+  i3 = HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] | 0;
+ } else {
+  i3 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + (i3 << 2) + 252 >> 2] | 0;
+ }
+ if ((i3 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i5 = i1 + 8 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i4 + 8 >> 2] = 69;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 16;
+ i5 = 1;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _str_byte(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i6 = i1;
+ i4 = i1 + 4 | 0;
+ i3 = _luaL_checklstring(i2, 1, i4) | 0;
+ i5 = _luaL_optinteger(i2, 2, 1) | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ if (!((i5 | 0) > -1)) {
+  if (i7 >>> 0 < (0 - i5 | 0) >>> 0) {
+   i5 = 0;
+  } else {
+   i5 = i5 + 1 + i7 | 0;
+  }
+ }
+ i8 = _luaL_optinteger(i2, 3, i5) | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ if (!((i8 | 0) > -1)) {
+  if (i7 >>> 0 < (0 - i8 | 0) >>> 0) {
+   i8 = 0;
+  } else {
+   i8 = i8 + 1 + i7 | 0;
+  }
+ }
+ i9 = (i5 | 0) == 0 ? 1 : i5;
+ i10 = i8 >>> 0 > i7 >>> 0 ? i7 : i8;
+ if (i9 >>> 0 > i10 >>> 0) {
+  i10 = 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i4 = i10 - i9 + 1 | 0;
+ if ((i10 | 0) == -1) {
+  i10 = _luaL_error(i2, 7944, i6) | 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ _luaL_checkstack(i2, i4, 7944);
+ if ((i4 | 0) <= 0) {
+  i10 = i4;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i6 = i9 + -1 | 0;
+ i8 = ~i8;
+ i7 = ~i7;
+ i5 = 0 - (i8 >>> 0 > i7 >>> 0 ? i8 : i7) - (i5 >>> 0 > 1 ? i5 : 1) | 0;
+ i7 = 0;
+ do {
+  _lua_pushinteger(i2, HEAPU8[i3 + (i6 + i7) | 0] | 0);
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != (i5 | 0));
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _lua_setuservalue(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i5 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i5 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i6 >> 2] | 0, (i5 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i5 = i4 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i5 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i6 >> 2] | 0) + (i5 << 4) | 0;
+   i5 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i4 = i1 + 8 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if ((HEAP32[i6 + -8 >> 2] | 0) != 0) {
+  HEAP32[(HEAP32[i5 >> 2] | 0) + 12 >> 2] = HEAP32[i6 + -16 >> 2];
+  i6 = HEAP32[(HEAP32[i4 >> 2] | 0) + -16 >> 2] | 0;
+  if (!((HEAP8[i6 + 5 | 0] & 3) == 0) ? (i2 = HEAP32[i5 >> 2] | 0, !((HEAP8[i2 + 5 | 0] & 4) == 0)) : 0) {
+   _luaC_barrier_(i1, i2, i6);
+  }
+ } else {
+  HEAP32[(HEAP32[i5 >> 2] | 0) + 12 >> 2] = 0;
+ }
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -16;
+ STACKTOP = i3;
+ return;
+}
+function _f_luaopen(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i6;
+ i4 = HEAP32[i1 + 12 >> 2] | 0;
+ i2 = _luaM_realloc_(i1, 0, 0, 640) | 0;
+ HEAP32[i1 + 28 >> 2] = i2;
+ i3 = i1 + 32 | 0;
+ HEAP32[i3 >> 2] = 40;
+ i7 = 0;
+ do {
+  HEAP32[i2 + (i7 << 4) + 8 >> 2] = 0;
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != 40);
+ HEAP32[i1 + 24 >> 2] = i2 + ((HEAP32[i3 >> 2] | 0) + -5 << 4);
+ i7 = i1 + 72 | 0;
+ HEAP32[i1 + 80 >> 2] = 0;
+ HEAP32[i1 + 84 >> 2] = 0;
+ HEAP8[i1 + 90 | 0] = 0;
+ HEAP32[i7 >> 2] = i2;
+ HEAP32[i1 + 8 >> 2] = i2 + 16;
+ HEAP32[i2 + 8 >> 2] = 0;
+ HEAP32[i1 + 76 >> 2] = i2 + 336;
+ HEAP32[i1 + 16 >> 2] = i7;
+ i7 = _luaH_new(i1) | 0;
+ HEAP32[i4 + 40 >> 2] = i7;
+ HEAP32[i4 + 48 >> 2] = 69;
+ _luaH_resize(i1, i7, 2, 0);
+ HEAP32[i5 >> 2] = i1;
+ i3 = i5 + 8 | 0;
+ HEAP32[i3 >> 2] = 72;
+ _luaH_setint(i1, i7, 1, i5);
+ HEAP32[i5 >> 2] = _luaH_new(i1) | 0;
+ HEAP32[i3 >> 2] = 69;
+ _luaH_setint(i1, i7, 2, i5);
+ _luaS_resize(i1, 32);
+ _luaT_init(i1);
+ _luaX_init(i1);
+ i7 = _luaS_newlstr(i1, 6896, 17) | 0;
+ HEAP32[i4 + 180 >> 2] = i7;
+ i7 = i7 + 5 | 0;
+ HEAP8[i7] = HEAPU8[i7] | 0 | 32;
+ HEAP8[i4 + 63 | 0] = 1;
+ STACKTOP = i6;
+ return;
+}
+function _lua_tointegerx(i6, i7, i1) {
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i5 = HEAP32[i6 + 16 >> 2] | 0;
+ do {
+  if ((i7 | 0) <= 0) {
+   if (!((i7 | 0) < -1000999)) {
+    i4 = (HEAP32[i6 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i4 = (HEAP32[i6 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i7 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i7 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i6 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i4 + 8 >> 2] | 0) != 3) {
+  i4 = _luaV_tonumber(i4, i3) | 0;
+  if ((i4 | 0) == 0) {
+   if ((i1 | 0) == 0) {
+    i7 = 0;
+    STACKTOP = i2;
+    return i7 | 0;
+   }
+   HEAP32[i1 >> 2] = 0;
+   i7 = 0;
+   STACKTOP = i2;
+   return i7 | 0;
+  }
+ }
+ i3 = ~~+HEAPF64[i4 >> 3];
+ if ((i1 | 0) == 0) {
+  i7 = i3;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ HEAP32[i1 >> 2] = 1;
+ i7 = i3;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _close_state(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i6 = i1 + 12 | 0;
+ i3 = HEAP32[i6 >> 2] | 0;
+ i4 = i1 + 28 | 0;
+ _luaF_close(i1, HEAP32[i4 >> 2] | 0);
+ _luaC_freeallobjects(i1);
+ i6 = HEAP32[i6 >> 2] | 0;
+ _luaM_realloc_(i1, HEAP32[i6 + 24 >> 2] | 0, HEAP32[i6 + 32 >> 2] << 2, 0) | 0;
+ i6 = i3 + 144 | 0;
+ i5 = i3 + 152 | 0;
+ HEAP32[i6 >> 2] = _luaM_realloc_(i1, HEAP32[i6 >> 2] | 0, HEAP32[i5 >> 2] | 0, 0) | 0;
+ HEAP32[i5 >> 2] = 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) == 0) {
+  i5 = HEAP32[i3 >> 2] | 0;
+  i6 = i3 + 4 | 0;
+  i6 = HEAP32[i6 >> 2] | 0;
+  FUNCTION_TABLE_iiiii[i5 & 3](i6, i1, 400, 0) | 0;
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i1 + 16 >> 2] = i1 + 72;
+ i7 = i1 + 84 | 0;
+ i6 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = 0;
+ if ((i6 | 0) != 0) {
+  while (1) {
+   i5 = HEAP32[i6 + 12 >> 2] | 0;
+   _luaM_realloc_(i1, i6, 40, 0) | 0;
+   if ((i5 | 0) == 0) {
+    break;
+   } else {
+    i6 = i5;
+   }
+  }
+  i5 = HEAP32[i4 >> 2] | 0;
+ }
+ _luaM_realloc_(i1, i5, HEAP32[i1 + 32 >> 2] << 4, 0) | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i7 = i3 + 4 | 0;
+ i7 = HEAP32[i7 >> 2] | 0;
+ FUNCTION_TABLE_iiiii[i6 & 3](i7, i1, 400, 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _ll_module(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i2;
+ i5 = i2 + 4 | 0;
+ i6 = _luaL_checklstring(i1, 1, 0) | 0;
+ i3 = _lua_gettop(i1) | 0;
+ _luaL_pushmodule(i1, i6, 1);
+ _lua_getfield(i1, -1, 4728);
+ i7 = (_lua_type(i1, -1) | 0) == 0;
+ _lua_settop(i1, -2);
+ if (i7) {
+  _lua_pushvalue(i1, -1);
+  _lua_setfield(i1, -2, 4784);
+  _lua_pushstring(i1, i6) | 0;
+  _lua_setfield(i1, -2, 4728);
+  i7 = _strrchr(i6, 46) | 0;
+  _lua_pushlstring(i1, i6, ((i7 | 0) == 0 ? i6 : i7 + 1 | 0) - i6 | 0) | 0;
+  _lua_setfield(i1, -2, 4792);
+ }
+ _lua_pushvalue(i1, -1);
+ if (!(((_lua_getstack(i1, 1, i5) | 0) != 0 ? (_lua_getinfo(i1, 4736, i5) | 0) != 0 : 0) ? (_lua_iscfunction(i1, -1) | 0) == 0 : 0)) {
+  _luaL_error(i1, 4744, i4) | 0;
+ }
+ _lua_pushvalue(i1, -2);
+ _lua_setupvalue(i1, -2, 1) | 0;
+ _lua_settop(i1, -2);
+ if ((i3 | 0) < 2) {
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i4 = 2;
+ }
+ while (1) {
+  if ((_lua_type(i1, i4) | 0) == 6) {
+   _lua_pushvalue(i1, i4);
+   _lua_pushvalue(i1, -2);
+   _lua_callk(i1, 1, 0, 0, 0);
+  }
+  if ((i4 | 0) == (i3 | 0)) {
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ STACKTOP = i2;
+ return 1;
+}
+function _strcspn(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i1;
+ i4 = HEAP8[i5] | 0;
+ if (!(i4 << 24 >> 24 == 0) ? (HEAP8[i5 + 1 | 0] | 0) != 0 : 0) {
+  HEAP32[i3 + 0 >> 2] = 0;
+  HEAP32[i3 + 4 >> 2] = 0;
+  HEAP32[i3 + 8 >> 2] = 0;
+  HEAP32[i3 + 12 >> 2] = 0;
+  HEAP32[i3 + 16 >> 2] = 0;
+  HEAP32[i3 + 20 >> 2] = 0;
+  HEAP32[i3 + 24 >> 2] = 0;
+  HEAP32[i3 + 28 >> 2] = 0;
+  do {
+   i7 = i4 & 255;
+   i6 = i3 + (i7 >>> 5 << 2) | 0;
+   HEAP32[i6 >> 2] = HEAP32[i6 >> 2] | 1 << (i7 & 31);
+   i5 = i5 + 1 | 0;
+   i4 = HEAP8[i5] | 0;
+  } while (!(i4 << 24 >> 24 == 0));
+  i5 = HEAP8[i2] | 0;
+  L7 : do {
+   if (i5 << 24 >> 24 == 0) {
+    i4 = i2;
+   } else {
+    i4 = i2;
+    while (1) {
+     i7 = i5 & 255;
+     i6 = i4 + 1 | 0;
+     if ((HEAP32[i3 + (i7 >>> 5 << 2) >> 2] & 1 << (i7 & 31) | 0) != 0) {
+      break L7;
+     }
+     i5 = HEAP8[i6] | 0;
+     if (i5 << 24 >> 24 == 0) {
+      i4 = i6;
+      break;
+     } else {
+      i4 = i6;
+     }
+    }
+   }
+  } while (0);
+  i7 = i4 - i2 | 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i7 = (___strchrnul(i2, i4 << 24 >> 24) | 0) - i2 | 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _main(i4, i5) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ i3 = _luaL_newstate() | 0;
+ if ((i3 | 0) == 0) {
+  i4 = HEAP32[i5 >> 2] | 0;
+  i3 = HEAP32[_stderr >> 2] | 0;
+  if ((i4 | 0) != 0) {
+   HEAP32[i2 >> 2] = i4;
+   _fprintf(i3 | 0, 496, i2 | 0) | 0;
+   _fflush(i3 | 0) | 0;
+  }
+  HEAP32[i2 >> 2] = 8;
+  _fprintf(i3 | 0, 912, i2 | 0) | 0;
+  _fflush(i3 | 0) | 0;
+  i8 = 1;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ _lua_pushcclosure(i3, 141, 0);
+ _lua_pushinteger(i3, i4);
+ _lua_pushlightuserdata(i3, i5);
+ i6 = _lua_pcallk(i3, 2, 1, 0, 0, 0) | 0;
+ i7 = _lua_toboolean(i3, -1) | 0;
+ i6 = (i6 | 0) == 0;
+ if (!i6) {
+  if ((_lua_type(i3, -1) | 0) == 4) {
+   i8 = _lua_tolstring(i3, -1, 0) | 0;
+  } else {
+   i8 = 0;
+  }
+  i4 = HEAP32[20] | 0;
+  i5 = HEAP32[_stderr >> 2] | 0;
+  if ((i4 | 0) != 0) {
+   HEAP32[i2 >> 2] = i4;
+   _fprintf(i5 | 0, 496, i2 | 0) | 0;
+   _fflush(i5 | 0) | 0;
+  }
+  HEAP32[i2 >> 2] = (i8 | 0) == 0 ? 48 : i8;
+  _fprintf(i5 | 0, 912, i2 | 0) | 0;
+  _fflush(i5 | 0) | 0;
+  _lua_settop(i3, -2);
+ }
+ _lua_close(i3);
+ i8 = i6 & (i7 | 0) != 0 & 1 ^ 1;
+ STACKTOP = i1;
+ return i8 | 0;
+}
+function _db_sethook(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i4 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i2 = _lua_tothread(i1, 1) | 0;
+  i5 = 1;
+ } else {
+  i2 = i1;
+  i5 = 0;
+ }
+ i3 = i5 + 1 | 0;
+ if ((_lua_type(i1, i3) | 0) < 1) {
+  _lua_settop(i1, i3);
+  i6 = 0;
+  i7 = 0;
+  i5 = 0;
+ } else {
+  i6 = _luaL_checklstring(i1, i5 | 2, 0) | 0;
+  _luaL_checktype(i1, i3, 6);
+  i5 = _luaL_optinteger(i1, i5 + 3 | 0, 0) | 0;
+  i7 = (_strchr(i6, 99) | 0) != 0 | 0;
+  i8 = (_strchr(i6, 114) | 0) == 0;
+  i7 = i8 ? i7 : i7 | 2;
+  i8 = (_strchr(i6, 108) | 0) == 0;
+  i8 = i8 ? i7 : i7 | 4;
+  i6 = i5;
+  i7 = 9;
+  i5 = (i5 | 0) > 0 ? i8 | 8 : i8;
+ }
+ if ((_luaL_getsubtable(i1, -1001e3, 11584) | 0) != 0) {
+  _lua_pushthread(i2) | 0;
+  _lua_xmove(i2, i1, 1);
+  _lua_pushvalue(i1, i3);
+  _lua_rawset(i1, -3);
+  _lua_sethook(i2, i7, i5, i6) | 0;
+  STACKTOP = i4;
+  return 0;
+ }
+ _lua_pushstring(i1, 11592) | 0;
+ _lua_setfield(i1, -2, 11600);
+ _lua_pushvalue(i1, -1);
+ _lua_setmetatable(i1, -2) | 0;
+ _lua_pushthread(i2) | 0;
+ _lua_xmove(i2, i1, 1);
+ _lua_pushvalue(i1, i3);
+ _lua_rawset(i1, -3);
+ _lua_sethook(i2, i7, i5, i6) | 0;
+ STACKTOP = i4;
+ return 0;
+}
+function _tconcat(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i6 = i3;
+ i2 = i3 + 16 | 0;
+ i5 = i3 + 8 | 0;
+ i4 = _luaL_optlstring(i1, 2, 8208, i5) | 0;
+ _luaL_checktype(i1, 1, 5);
+ i8 = _luaL_optinteger(i1, 3, 1) | 0;
+ if ((_lua_type(i1, 4) | 0) < 1) {
+  i7 = _luaL_len(i1, 1) | 0;
+ } else {
+  i7 = _luaL_checkinteger(i1, 4) | 0;
+ }
+ _luaL_buffinit(i1, i2);
+ if ((i8 | 0) >= (i7 | 0)) {
+  if ((i8 | 0) != (i7 | 0)) {
+   _luaL_pushresult(i2);
+   STACKTOP = i3;
+   return 1;
+  }
+ } else {
+  do {
+   _lua_rawgeti(i1, 1, i8);
+   if ((_lua_isstring(i1, -1) | 0) == 0) {
+    HEAP32[i6 >> 2] = _lua_typename(i1, _lua_type(i1, -1) | 0) | 0;
+    HEAP32[i6 + 4 >> 2] = i8;
+    _luaL_error(i1, 8360, i6) | 0;
+   }
+   _luaL_addvalue(i2);
+   _luaL_addlstring(i2, i4, HEAP32[i5 >> 2] | 0);
+   i8 = i8 + 1 | 0;
+  } while ((i8 | 0) != (i7 | 0));
+ }
+ _lua_rawgeti(i1, 1, i7);
+ if ((_lua_isstring(i1, -1) | 0) == 0) {
+  HEAP32[i6 >> 2] = _lua_typename(i1, _lua_type(i1, -1) | 0) | 0;
+  HEAP32[i6 + 4 >> 2] = i7;
+  _luaL_error(i1, 8360, i6) | 0;
+ }
+ _luaL_addvalue(i2);
+ _luaL_pushresult(i2);
+ STACKTOP = i3;
+ return 1;
+}
+function _searcher_Croot(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _luaL_checklstring(i1, 1, 0) | 0;
+ i5 = _strchr(i4, 46) | 0;
+ if ((i5 | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ _lua_pushlstring(i1, i4, i5 - i4 | 0) | 0;
+ i5 = _lua_tolstring(i1, -1, 0) | 0;
+ _lua_getfield(i1, -1001001, 4440);
+ i6 = _lua_tolstring(i1, -1, 0) | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i3 >> 2] = 4440;
+  _luaL_error(i1, 5032, i3) | 0;
+ }
+ i5 = _searchpath(i1, i5, i6, 4936, 4848) | 0;
+ if ((i5 | 0) == 0) {
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ i6 = _loadfunc(i1, i5, i4) | 0;
+ if ((i6 | 0) == 2) {
+  HEAP32[i3 >> 2] = i4;
+  HEAP32[i3 + 4 >> 2] = i5;
+  _lua_pushfstring(i1, 4856, i3) | 0;
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else if ((i6 | 0) == 0) {
+  _lua_pushstring(i1, i5) | 0;
+  i6 = 2;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  i4 = _lua_tolstring(i1, 1, 0) | 0;
+  i6 = _lua_tolstring(i1, -1, 0) | 0;
+  HEAP32[i3 >> 2] = i4;
+  HEAP32[i3 + 4 >> 2] = i5;
+  HEAP32[i3 + 8 >> 2] = i6;
+  i6 = _luaL_error(i1, 4888, i3) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ return 0;
+}
+function _lua_tonumberx(i5, i7, i1) {
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, d8 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i6 = HEAP32[i5 + 16 >> 2] | 0;
+ do {
+  if ((i7 | 0) <= 0) {
+   if (!((i7 | 0) < -1000999)) {
+    i4 = (HEAP32[i5 + 8 >> 2] | 0) + (i7 << 4) | 0;
+    break;
+   }
+   if ((i7 | 0) == -1001e3) {
+    i4 = (HEAP32[i5 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i7 | 0;
+   i6 = HEAP32[i6 >> 2] | 0;
+   if ((HEAP32[i6 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i6 >> 2] | 0, (i5 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i6 >> 2] | 0) + (i7 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i5 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i4 + 8 >> 2] | 0) != 3) {
+  i4 = _luaV_tonumber(i4, i3) | 0;
+  if ((i4 | 0) == 0) {
+   if ((i1 | 0) == 0) {
+    d8 = 0.0;
+    STACKTOP = i2;
+    return +d8;
+   }
+   HEAP32[i1 >> 2] = 0;
+   d8 = 0.0;
+   STACKTOP = i2;
+   return +d8;
+  }
+ }
+ if ((i1 | 0) != 0) {
+  HEAP32[i1 >> 2] = 1;
+ }
+ d8 = +HEAPF64[i4 >> 3];
+ STACKTOP = i2;
+ return +d8;
+}
+function _luaopen_package(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_getsubtable(i1, -1001e3, 4184) | 0;
+ _lua_createtable(i1, 0, 1);
+ _lua_pushcclosure(i1, 158, 0);
+ _lua_setfield(i1, -2, 4192);
+ _lua_setmetatable(i1, -2) | 0;
+ _lua_createtable(i1, 0, 3);
+ _luaL_setfuncs(i1, 4200, 0);
+ _lua_createtable(i1, 4, 0);
+ _lua_pushvalue(i1, -2);
+ _lua_pushcclosure(i1, 159, 1);
+ _lua_rawseti(i1, -2, 1);
+ _lua_pushvalue(i1, -2);
+ _lua_pushcclosure(i1, 160, 1);
+ _lua_rawseti(i1, -2, 2);
+ _lua_pushvalue(i1, -2);
+ _lua_pushcclosure(i1, 161, 1);
+ _lua_rawseti(i1, -2, 3);
+ _lua_pushvalue(i1, -2);
+ _lua_pushcclosure(i1, 162, 1);
+ _lua_rawseti(i1, -2, 4);
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -3, 4232);
+ _lua_setfield(i1, -2, 4240);
+ _setpath(i1, 4256, 4264, 4280, 4296);
+ _setpath(i1, 4440, 4448, 4464, 4480);
+ _lua_pushlstring(i1, 4552, 10) | 0;
+ _lua_setfield(i1, -2, 4568);
+ _luaL_getsubtable(i1, -1001e3, 4576) | 0;
+ _lua_setfield(i1, -2, 4584);
+ _luaL_getsubtable(i1, -1001e3, 4592) | 0;
+ _lua_setfield(i1, -2, 4608);
+ _lua_rawgeti(i1, -1001e3, 2);
+ _lua_pushvalue(i1, -2);
+ _luaL_setfuncs(i1, 4616, 1);
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_rawlen(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i2 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ i3 = HEAP32[i2 + 8 >> 2] & 15;
+ if ((i3 | 0) == 5) {
+  i5 = _luaH_getn(HEAP32[i2 >> 2] | 0) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else if ((i3 | 0) == 4) {
+  i5 = HEAP32[(HEAP32[i2 >> 2] | 0) + 12 >> 2] | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else if ((i3 | 0) == 7) {
+  i5 = HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else {
+  i5 = 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _searchpath(i3, i5, i6, i7, i8) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i2;
+ i1 = i2 + 8 | 0;
+ _luaL_buffinit(i3, i1);
+ if ((HEAP8[i7] | 0) != 0) {
+  i5 = _luaL_gsub(i3, i5, i7, i8) | 0;
+ }
+ while (1) {
+  i7 = HEAP8[i6] | 0;
+  if (i7 << 24 >> 24 == 59) {
+   i6 = i6 + 1 | 0;
+   continue;
+  } else if (i7 << 24 >> 24 == 0) {
+   i3 = 12;
+   break;
+  }
+  i8 = _strchr(i6, 59) | 0;
+  if ((i8 | 0) == 0) {
+   i8 = i6 + (_strlen(i6 | 0) | 0) | 0;
+  }
+  _lua_pushlstring(i3, i6, i8 - i6 | 0) | 0;
+  if ((i8 | 0) == 0) {
+   i3 = 12;
+   break;
+  }
+  i6 = _luaL_gsub(i3, _lua_tolstring(i3, -1, 0) | 0, 5064, i5) | 0;
+  _lua_remove(i3, -2);
+  i7 = _fopen(i6 | 0, 5088) | 0;
+  if ((i7 | 0) != 0) {
+   i3 = 10;
+   break;
+  }
+  HEAP32[i4 >> 2] = i6;
+  _lua_pushfstring(i3, 5072, i4) | 0;
+  _lua_remove(i3, -2);
+  _luaL_addvalue(i1);
+  i6 = i8;
+ }
+ if ((i3 | 0) == 10) {
+  _fclose(i7 | 0) | 0;
+  i8 = i6;
+  STACKTOP = i2;
+  return i8 | 0;
+ } else if ((i3 | 0) == 12) {
+  _luaL_pushresult(i1);
+  i8 = 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ return 0;
+}
+function _io_readline(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _lua_touserdata(i1, -1001001) | 0;
+ i5 = _lua_tointegerx(i1, -1001002, 0) | 0;
+ if ((HEAP32[i4 + 4 >> 2] | 0) == 0) {
+  i6 = _luaL_error(i1, 3344, i3) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ _lua_settop(i1, 1);
+ if ((i5 | 0) >= 1) {
+  i6 = 1;
+  while (1) {
+   _lua_pushvalue(i1, -1001003 - i6 | 0);
+   if ((i6 | 0) == (i5 | 0)) {
+    break;
+   } else {
+    i6 = i6 + 1 | 0;
+   }
+  }
+ }
+ i4 = _g_read(i1, HEAP32[i4 >> 2] | 0, 2) | 0;
+ if ((_lua_type(i1, 0 - i4 | 0) | 0) != 0) {
+  i6 = i4;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ if ((i4 | 0) > 1) {
+  HEAP32[i3 >> 2] = _lua_tolstring(i1, 1 - i4 | 0, 0) | 0;
+  i6 = _luaL_error(i1, 3368, i3) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ if ((_lua_toboolean(i1, -1001003) | 0) == 0) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ _lua_settop(i1, 0);
+ _lua_pushvalue(i1, -1001001);
+ i5 = (_luaL_checkudata(i1, 1, 2832) | 0) + 4 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = 0;
+ FUNCTION_TABLE_ii[i6 & 255](i1) | 0;
+ i6 = 0;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaK_setreturns(i3, i5, i6) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i5 >> 2] | 0;
+ if ((i4 | 0) == 13) {
+  i7 = i5 + 8 | 0;
+  i8 = HEAP32[i3 >> 2] | 0;
+  i4 = HEAP32[i8 + 12 >> 2] | 0;
+  i5 = i4 + (HEAP32[i7 >> 2] << 2) | 0;
+  HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & 8388607 | (i6 << 23) + 8388608;
+  i7 = i4 + (HEAP32[i7 >> 2] << 2) | 0;
+  i4 = i3 + 48 | 0;
+  HEAP32[i7 >> 2] = (HEAPU8[i4] | 0) << 6 | HEAP32[i7 >> 2] & -16321;
+  i7 = HEAP8[i4] | 0;
+  i5 = (i7 & 255) + 1 | 0;
+  i6 = i8 + 78 | 0;
+  do {
+   if (i5 >>> 0 > (HEAPU8[i6] | 0) >>> 0) {
+    if (i5 >>> 0 > 249) {
+     _luaX_syntaxerror(HEAP32[i3 + 12 >> 2] | 0, 10536);
+    } else {
+     HEAP8[i6] = i5;
+     i1 = HEAP8[i4] | 0;
+     break;
+    }
+   } else {
+    i1 = i7;
+   }
+  } while (0);
+  HEAP8[i4] = (i1 & 255) + 1;
+  STACKTOP = i2;
+  return;
+ } else if ((i4 | 0) == 12) {
+  i8 = (HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i5 + 8 >> 2] << 2) | 0;
+  HEAP32[i8 >> 2] = HEAP32[i8 >> 2] & -8372225 | (i6 << 14) + 16384 & 8372224;
+  STACKTOP = i2;
+  return;
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaZ_read(i2, i9, i8) {
+ i2 = i2 | 0;
+ i9 = i9 | 0;
+ i8 = i8 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((i8 | 0) == 0) {
+  i11 = 0;
+  STACKTOP = i1;
+  return i11 | 0;
+ }
+ i7 = i2 + 16 | 0;
+ i6 = i2 + 8 | 0;
+ i4 = i2 + 12 | 0;
+ i5 = i2 + 4 | 0;
+ i11 = HEAP32[i2 >> 2] | 0;
+ while (1) {
+  if ((i11 | 0) == 0) {
+   i10 = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 3](HEAP32[i7 >> 2] | 0, HEAP32[i4 >> 2] | 0, i3) | 0;
+   if ((i10 | 0) == 0) {
+    i2 = 9;
+    break;
+   }
+   i11 = HEAP32[i3 >> 2] | 0;
+   if ((i11 | 0) == 0) {
+    i2 = 9;
+    break;
+   }
+   HEAP32[i2 >> 2] = i11;
+   HEAP32[i5 >> 2] = i10;
+  } else {
+   i10 = HEAP32[i5 >> 2] | 0;
+  }
+  i11 = i8 >>> 0 > i11 >>> 0 ? i11 : i8;
+  _memcpy(i9 | 0, i10 | 0, i11 | 0) | 0;
+  i10 = (HEAP32[i2 >> 2] | 0) - i11 | 0;
+  HEAP32[i2 >> 2] = i10;
+  HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i11;
+  if ((i8 | 0) == (i11 | 0)) {
+   i8 = 0;
+   i2 = 9;
+   break;
+  } else {
+   i8 = i8 - i11 | 0;
+   i9 = i9 + i11 | 0;
+   i11 = i10;
+  }
+ }
+ if ((i2 | 0) == 9) {
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ return 0;
+}
+function _lua_load(i1, i5, i4, i3, i6) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i7 = i2;
+ _luaZ_init(i1, i7, i5, i4);
+ i3 = _luaD_protectedparser(i1, i7, (i3 | 0) == 0 ? 928 : i3, i6) | 0;
+ if ((i3 | 0) != 0) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i4 = HEAP32[(HEAP32[i1 + 8 >> 2] | 0) + -16 >> 2] | 0;
+ if ((HEAP8[i4 + 6 | 0] | 0) != 1) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i5 = _luaH_getint(HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 40 >> 2] | 0, 2) | 0;
+ i4 = i4 + 16 | 0;
+ i6 = HEAP32[(HEAP32[i4 >> 2] | 0) + 8 >> 2] | 0;
+ i9 = i5;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i6;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ i7 = i5 + 8 | 0;
+ HEAP32[i6 + 8 >> 2] = HEAP32[i7 >> 2];
+ if ((HEAP32[i7 >> 2] & 64 | 0) == 0) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i5 = HEAP32[i5 >> 2] | 0;
+ if ((HEAP8[i5 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i4 = HEAP32[i4 >> 2] | 0;
+ if ((HEAP8[i4 + 5 | 0] & 4) == 0) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _luaC_barrier_(i1, i4, i5);
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _g_write(i1, i4, i8) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i8 = i8 | 0;
+ var i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i9 = 0, d10 = 0.0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i5;
+ i3 = i5 + 8 | 0;
+ i7 = _lua_gettop(i1) | 0;
+ if ((i7 | 0) == (i8 | 0)) {
+  i9 = 1;
+  STACKTOP = i5;
+  return i9 | 0;
+ }
+ i6 = i8;
+ i7 = i7 - i8 | 0;
+ i9 = 1;
+ while (1) {
+  i7 = i7 + -1 | 0;
+  if ((_lua_type(i1, i6) | 0) == 3) {
+   if ((i9 | 0) == 0) {
+    i8 = 0;
+   } else {
+    d10 = +_lua_tonumberx(i1, i6, 0);
+    HEAPF64[tempDoublePtr >> 3] = d10;
+    HEAP32[i2 >> 2] = HEAP32[tempDoublePtr >> 2];
+    HEAP32[i2 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+    i8 = (_fprintf(i4 | 0, 3072, i2 | 0) | 0) > 0;
+   }
+  } else {
+   i8 = _luaL_checklstring(i1, i6, i3) | 0;
+   if ((i9 | 0) == 0) {
+    i8 = 0;
+   } else {
+    i8 = _fwrite(i8 | 0, 1, HEAP32[i3 >> 2] | 0, i4 | 0) | 0;
+    i8 = (i8 | 0) == (HEAP32[i3 >> 2] | 0);
+   }
+  }
+  if ((i7 | 0) == 0) {
+   break;
+  } else {
+   i6 = i6 + 1 | 0;
+   i9 = i8 & 1;
+  }
+ }
+ if (i8) {
+  i9 = 1;
+  STACKTOP = i5;
+  return i9 | 0;
+ }
+ i9 = _luaL_fileresult(i1, 0, 0) | 0;
+ STACKTOP = i5;
+ return i9 | 0;
+}
+function _lua_getuservalue(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i2 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i3 = HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0;
+ i2 = i2 + 8 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  HEAP32[i4 + 8 >> 2] = 0;
+  i5 = i4;
+  i5 = i5 + 16 | 0;
+  HEAP32[i2 >> 2] = i5;
+  STACKTOP = i1;
+  return;
+ } else {
+  HEAP32[i4 >> 2] = i3;
+  HEAP32[i4 + 8 >> 2] = 69;
+  i5 = HEAP32[i2 >> 2] | 0;
+  i5 = i5 + 16 | 0;
+  HEAP32[i2 >> 2] = i5;
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaL_addlstring(i7, i6, i1) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = HEAP32[i7 + 12 >> 2] | 0;
+ i3 = i7 + 4 | 0;
+ i9 = HEAP32[i3 >> 2] | 0;
+ i2 = i7 + 8 | 0;
+ i8 = HEAP32[i2 >> 2] | 0;
+ if (!((i9 - i8 | 0) >>> 0 < i1 >>> 0)) {
+  i7 = HEAP32[i7 >> 2] | 0;
+  i9 = i8;
+  i9 = i7 + i9 | 0;
+  _memcpy(i9 | 0, i6 | 0, i1 | 0) | 0;
+  i9 = HEAP32[i2 >> 2] | 0;
+  i9 = i9 + i1 | 0;
+  HEAP32[i2 >> 2] = i9;
+  STACKTOP = i5;
+  return;
+ }
+ i9 = i9 << 1;
+ i9 = (i9 - i8 | 0) >>> 0 < i1 >>> 0 ? i8 + i1 | 0 : i9;
+ if (i9 >>> 0 < i8 >>> 0 | (i9 - i8 | 0) >>> 0 < i1 >>> 0) {
+  _luaL_error(i4, 1272, i5) | 0;
+ }
+ i8 = _lua_newuserdata(i4, i9) | 0;
+ _memcpy(i8 | 0, HEAP32[i7 >> 2] | 0, HEAP32[i2 >> 2] | 0) | 0;
+ if ((HEAP32[i7 >> 2] | 0) != (i7 + 16 | 0)) {
+  _lua_remove(i4, -2);
+ }
+ HEAP32[i7 >> 2] = i8;
+ HEAP32[i3 >> 2] = i9;
+ i9 = HEAP32[i2 >> 2] | 0;
+ i9 = i8 + i9 | 0;
+ _memcpy(i9 | 0, i6 | 0, i1 | 0) | 0;
+ i9 = HEAP32[i2 >> 2] | 0;
+ i9 = i9 + i1 | 0;
+ HEAP32[i2 >> 2] = i9;
+ STACKTOP = i5;
+ return;
+}
+function _lua_rawgeti(i3, i6, i1) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i3 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i4 = _luaH_getint(HEAP32[i4 >> 2] | 0, i1) | 0;
+ i6 = i3 + 8 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ i7 = i4;
+ i1 = HEAP32[i7 + 4 >> 2] | 0;
+ i3 = i5;
+ HEAP32[i3 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i3 + 4 >> 2] = i1;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i4 + 8 >> 2];
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return;
+}
+function _lua_setfield(i1, i6, i3) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i6 = i1 + 8 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i6 >> 2] = i5 + 16;
+ i3 = _luaS_new(i1, i3) | 0;
+ HEAP32[i5 >> 2] = i3;
+ HEAP32[i5 + 8 >> 2] = HEAPU8[i3 + 4 | 0] | 0 | 64;
+ i5 = HEAP32[i6 >> 2] | 0;
+ _luaV_settable(i1, i4, i5 + -16 | 0, i5 + -32 | 0);
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + -32;
+ STACKTOP = i2;
+ return;
+}
+function _luaopen_io(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 11);
+ _luaL_setfuncs(i1, 2680, 0);
+ _luaL_newmetatable(i1, 2832) | 0;
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -2, 2872);
+ _luaL_setfuncs(i1, 2880, 0);
+ _lua_settop(i1, -2);
+ i5 = HEAP32[_stdin >> 2] | 0;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i3 = i4 + 4 | 0;
+ HEAP32[i3 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = i5;
+ HEAP32[i3 >> 2] = 154;
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -1001e3, 2776);
+ _lua_setfield(i1, -2, 2792);
+ i3 = HEAP32[_stdout >> 2] | 0;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i5 = i4 + 4 | 0;
+ HEAP32[i5 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i5 >> 2] = 154;
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -1001e3, 2800);
+ _lua_setfield(i1, -2, 2816);
+ i5 = HEAP32[_stderr >> 2] | 0;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i3 = i4 + 4 | 0;
+ HEAP32[i3 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = i5;
+ HEAP32[i3 >> 2] = 154;
+ _lua_setfield(i1, -2, 2824);
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_pushcclosure(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ if ((i5 | 0) == 0) {
+  i6 = HEAP32[i1 + 8 >> 2] | 0;
+  HEAP32[i6 >> 2] = i4;
+  HEAP32[i6 + 8 >> 2] = 22;
+  i6 = i1 + 8 | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i5 = i5 + 16 | 0;
+  HEAP32[i6 >> 2] = i5;
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i3 = _luaF_newCclosure(i1, i5) | 0;
+ HEAP32[i3 + 12 >> 2] = i4;
+ i4 = i1 + 8 | 0;
+ i6 = (HEAP32[i4 >> 2] | 0) + (0 - i5 << 4) | 0;
+ HEAP32[i4 >> 2] = i6;
+ do {
+  i5 = i5 + -1 | 0;
+  i9 = i6 + (i5 << 4) | 0;
+  i8 = HEAP32[i9 + 4 >> 2] | 0;
+  i7 = i3 + (i5 << 4) + 16 | 0;
+  HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+  HEAP32[i7 + 4 >> 2] = i8;
+  HEAP32[i3 + (i5 << 4) + 24 >> 2] = HEAP32[i6 + (i5 << 4) + 8 >> 2];
+  i6 = HEAP32[i4 >> 2] | 0;
+ } while ((i5 | 0) != 0);
+ HEAP32[i6 >> 2] = i3;
+ HEAP32[i6 + 8 >> 2] = 102;
+ i9 = i1 + 8 | 0;
+ i8 = HEAP32[i9 >> 2] | 0;
+ i8 = i8 + 16 | 0;
+ HEAP32[i9 >> 2] = i8;
+ STACKTOP = i2;
+ return;
+}
+function _luaF_findupval(i3, i4) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i3 + 12 >> 2] | 0;
+ i6 = i3 + 56 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ L1 : do {
+  if ((i5 | 0) == 0) {
+   i5 = i6;
+  } else {
+   while (1) {
+    i7 = HEAP32[i5 + 8 >> 2] | 0;
+    if (i7 >>> 0 < i4 >>> 0) {
+     i5 = i6;
+     break L1;
+    }
+    if ((i7 | 0) == (i4 | 0)) {
+     break;
+    }
+    i6 = HEAP32[i5 >> 2] | 0;
+    if ((i6 | 0) == 0) {
+     break L1;
+    } else {
+     i7 = i5;
+     i5 = i6;
+     i6 = i7;
+    }
+   }
+   i4 = i5 + 5 | 0;
+   i3 = (HEAPU8[i4] | 0) ^ 3;
+   if ((((HEAPU8[i2 + 60 | 0] | 0) ^ 3) & i3 | 0) != 0) {
+    i7 = i5;
+    STACKTOP = i1;
+    return i7 | 0;
+   }
+   HEAP8[i4] = i3;
+   i7 = i5;
+   STACKTOP = i1;
+   return i7 | 0;
+  }
+ } while (0);
+ i7 = _luaC_newobj(i3, 10, 32, i5, 0) | 0;
+ HEAP32[i7 + 8 >> 2] = i4;
+ i4 = i7 + 16 | 0;
+ HEAP32[i4 >> 2] = i2 + 112;
+ i6 = i2 + 132 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i4 + 4 >> 2] = i5;
+ HEAP32[i5 + 16 >> 2] = i7;
+ HEAP32[i6 >> 2] = i7;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaC_checkfinalizer(i5, i4, i6) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ i1 = HEAP32[i5 + 12 >> 2] | 0;
+ i2 = i4 + 5 | 0;
+ if ((HEAP8[i2] & 24) != 0 | (i6 | 0) == 0) {
+  STACKTOP = i3;
+  return;
+ }
+ if (!((HEAP8[i6 + 6 | 0] & 4) == 0)) {
+  STACKTOP = i3;
+  return;
+ }
+ if ((_luaT_gettm(i6, 2, HEAP32[i1 + 192 >> 2] | 0) | 0) == 0) {
+  STACKTOP = i3;
+  return;
+ }
+ i7 = i1 + 76 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 | 0) == (i4 | 0)) {
+  do {
+   i6 = _sweeplist(i5, i8, 1) | 0;
+  } while ((i6 | 0) == (i8 | 0));
+  HEAP32[i7 >> 2] = i6;
+ }
+ i5 = i1 + 68 | 0;
+ while (1) {
+  i6 = HEAP32[i5 >> 2] | 0;
+  if ((i6 | 0) == (i4 | 0)) {
+   break;
+  } else {
+   i5 = i6;
+  }
+ }
+ HEAP32[i5 >> 2] = HEAP32[i4 >> 2];
+ i8 = i1 + 72 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i8 >> 2] = i4;
+ i4 = HEAPU8[i2] | 0 | 16;
+ HEAP8[i2] = i4;
+ if ((HEAPU8[i1 + 61 | 0] | 0) < 2) {
+  HEAP8[i2] = i4 & 191;
+  STACKTOP = i3;
+  return;
+ } else {
+  HEAP8[i2] = HEAP8[i1 + 60 | 0] & 3 | i4 & 184;
+  STACKTOP = i3;
+  return;
+ }
+}
+function _io_lines(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_type(i1, 1) | 0) == -1) {
+  _lua_pushnil(i1);
+ }
+ if ((_lua_type(i1, 1) | 0) == 0) {
+  _lua_getfield(i1, -1001e3, 2776);
+  _lua_replace(i1, 1);
+  if ((HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) + 4 >> 2] | 0) != 0) {
+   i4 = 0;
+   _aux_lines(i1, i4);
+   STACKTOP = i2;
+   return 1;
+  }
+  _luaL_error(i1, 3080, i3) | 0;
+  i4 = 0;
+  _aux_lines(i1, i4);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i4 = _luaL_checklstring(i1, 1, 0) | 0;
+  i6 = _lua_newuserdata(i1, 8) | 0;
+  i5 = i6 + 4 | 0;
+  HEAP32[i5 >> 2] = 0;
+  _luaL_setmetatable(i1, 2832);
+  HEAP32[i6 >> 2] = 0;
+  HEAP32[i5 >> 2] = 156;
+  i5 = _fopen(i4 | 0, 3480) | 0;
+  HEAP32[i6 >> 2] = i5;
+  if ((i5 | 0) == 0) {
+   i6 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+   HEAP32[i3 >> 2] = i4;
+   HEAP32[i3 + 4 >> 2] = i6;
+   _luaL_error(i1, 3520, i3) | 0;
+  }
+  _lua_replace(i1, 1);
+  i6 = 1;
+  _aux_lines(i1, i6);
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _luaC_changemode(i2, i6) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i3 = i2 + 12 | 0;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i4 = i5 + 62 | 0;
+ if ((HEAPU8[i4] | 0) == (i6 | 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ if ((i6 | 0) == 2) {
+  i3 = i5 + 61 | 0;
+  if ((HEAP8[i3] | 0) != 0) {
+   do {
+    _singlestep(i2) | 0;
+   } while ((HEAP8[i3] | 0) != 0);
+  }
+  HEAP32[i5 + 20 >> 2] = (HEAP32[i5 + 12 >> 2] | 0) + (HEAP32[i5 + 8 >> 2] | 0);
+  HEAP8[i4] = 2;
+  STACKTOP = i1;
+  return;
+ }
+ HEAP8[i4] = 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ HEAP8[i4 + 61 | 0] = 2;
+ HEAP32[i4 + 64 >> 2] = 0;
+ i5 = i4 + 72 | 0;
+ do {
+  i6 = _sweeplist(i2, i5, 1) | 0;
+ } while ((i6 | 0) == (i5 | 0));
+ HEAP32[i4 + 80 >> 2] = i6;
+ i5 = i4 + 68 | 0;
+ do {
+  i6 = _sweeplist(i2, i5, 1) | 0;
+ } while ((i6 | 0) == (i5 | 0));
+ HEAP32[i4 + 76 >> 2] = i6;
+ i3 = (HEAP32[i3 >> 2] | 0) + 61 | 0;
+ if ((1 << HEAPU8[i3] & -29 | 0) != 0) {
+  STACKTOP = i1;
+  return;
+ }
+ do {
+  _singlestep(i2) | 0;
+ } while ((1 << HEAPU8[i3] & -29 | 0) == 0);
+ STACKTOP = i1;
+ return;
+}
+function _lua_rawget(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ i4 = _luaH_get(HEAP32[i3 >> 2] | 0, (HEAP32[i5 >> 2] | 0) + -16 | 0) | 0;
+ i5 = HEAP32[i5 >> 2] | 0;
+ i6 = i4;
+ i1 = HEAP32[i6 + 4 >> 2] | 0;
+ i3 = i5 + -16 | 0;
+ HEAP32[i3 >> 2] = HEAP32[i6 >> 2];
+ HEAP32[i3 + 4 >> 2] = i1;
+ HEAP32[i5 + -8 >> 2] = HEAP32[i4 + 8 >> 2];
+ STACKTOP = i2;
+ return;
+}
+function _lua_isstring(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i2 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i2 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i2 = -1001e3 - i4 | 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP32[i3 + 8 >> 2] | 0) == 22) {
+    i4 = 0;
+    i4 = i4 & 1;
+    STACKTOP = i1;
+    return i4 | 0;
+   }
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((i2 | 0) > (HEAPU8[i3 + 6 | 0] | 0 | 0)) {
+    i4 = 0;
+    i4 = i4 & 1;
+    STACKTOP = i1;
+    return i4 | 0;
+   } else {
+    i2 = i3 + (i2 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else {
+   i3 = (HEAP32[i3 >> 2] | 0) + (i4 << 4) | 0;
+   i2 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ if ((i2 | 0) == 5192) {
+  i4 = 0;
+  i4 = i4 & 1;
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i4 = ((HEAP32[i2 + 8 >> 2] & 15) + -3 | 0) >>> 0 < 2;
+ i4 = i4 & 1;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _setnodevector(i5, i1, i3) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ if ((i3 | 0) == 0) {
+  HEAP32[i1 + 16 >> 2] = 8016;
+  i6 = 0;
+  i7 = 8016;
+  i4 = 0;
+  i5 = i1 + 7 | 0;
+  HEAP8[i5] = i4;
+  i6 = i7 + (i6 << 5) | 0;
+  i7 = i1 + 20 | 0;
+  HEAP32[i7 >> 2] = i6;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = _luaO_ceillog2(i3) | 0;
+ if ((i4 | 0) > 30) {
+  _luaG_runerror(i5, 8048, i2);
+ }
+ i3 = 1 << i4;
+ if ((i3 + 1 | 0) >>> 0 > 134217727) {
+  _luaM_toobig(i5);
+ }
+ i6 = _luaM_realloc_(i5, 0, 0, i3 << 5) | 0;
+ i5 = i1 + 16 | 0;
+ HEAP32[i5 >> 2] = i6;
+ if ((i3 | 0) > 0) {
+  i7 = 0;
+  do {
+   HEAP32[i6 + (i7 << 5) + 28 >> 2] = 0;
+   HEAP32[i6 + (i7 << 5) + 24 >> 2] = 0;
+   HEAP32[i6 + (i7 << 5) + 8 >> 2] = 0;
+   i7 = i7 + 1 | 0;
+   i6 = HEAP32[i5 >> 2] | 0;
+  } while ((i7 | 0) != (i3 | 0));
+ }
+ i7 = i3;
+ i4 = i4 & 255;
+ i5 = i1 + 7 | 0;
+ HEAP8[i5] = i4;
+ i6 = i6 + (i7 << 5) | 0;
+ i7 = i1 + 20 | 0;
+ HEAP32[i7 >> 2] = i6;
+ STACKTOP = i2;
+ return;
+}
+function _lua_pushvalue(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ i7 = i3;
+ i6 = HEAP32[i7 + 4 >> 2] | 0;
+ i1 = i4;
+ HEAP32[i1 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i1 + 4 >> 2] = i6;
+ HEAP32[i4 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return;
+}
+function _luaL_setfuncs(i3, i6, i1) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ _luaL_checkversion_(i3, 502.0);
+ if ((_lua_checkstack(i3, i1 + 20 | 0) | 0) == 0) {
+  HEAP32[i4 >> 2] = 1472;
+  _luaL_error(i3, 1216, i4) | 0;
+ }
+ if ((HEAP32[i6 >> 2] | 0) == 0) {
+  i7 = ~i1;
+  _lua_settop(i3, i7);
+  STACKTOP = i2;
+  return;
+ }
+ i4 = -2 - i1 | 0;
+ i5 = 0 - i1 | 0;
+ if ((i1 | 0) <= 0) {
+  do {
+   _lua_pushcclosure(i3, HEAP32[i6 + 4 >> 2] | 0, i1);
+   _lua_setfield(i3, i4, HEAP32[i6 >> 2] | 0);
+   i6 = i6 + 8 | 0;
+  } while ((HEAP32[i6 >> 2] | 0) != 0);
+  i7 = ~i1;
+  _lua_settop(i3, i7);
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  i7 = 0;
+  do {
+   _lua_pushvalue(i3, i5);
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) != (i1 | 0));
+  _lua_pushcclosure(i3, HEAP32[i6 + 4 >> 2] | 0, i1);
+  _lua_setfield(i3, i4, HEAP32[i6 >> 2] | 0);
+  i6 = i6 + 8 | 0;
+ } while ((HEAP32[i6 >> 2] | 0) != 0);
+ i7 = ~i1;
+ _lua_settop(i3, i7);
+ STACKTOP = i2;
+ return;
+}
+function _lua_touserdata(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i2 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ i3 = HEAP32[i2 + 8 >> 2] & 15;
+ if ((i3 | 0) == 2) {
+  i5 = HEAP32[i2 >> 2] | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else if ((i3 | 0) == 7) {
+  i5 = (HEAP32[i2 >> 2] | 0) + 24 | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else {
+  i5 = 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _luaL_checkoption(i2, i3, i6, i4) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i1;
+ if ((i6 | 0) == 0) {
+  i6 = _lua_tolstring(i2, i3, 0) | 0;
+  if ((i6 | 0) == 0) {
+   i9 = _lua_typename(i2, 4) | 0;
+   i6 = _lua_typename(i2, _lua_type(i2, i3) | 0) | 0;
+   HEAP32[i5 >> 2] = i9;
+   HEAP32[i5 + 4 >> 2] = i6;
+   _luaL_argerror(i2, i3, _lua_pushfstring(i2, 1744, i5) | 0) | 0;
+   i6 = 0;
+  }
+ } else {
+  i6 = _luaL_optlstring(i2, i3, i6, 0) | 0;
+ }
+ i9 = HEAP32[i4 >> 2] | 0;
+ L6 : do {
+  if ((i9 | 0) != 0) {
+   i8 = 0;
+   while (1) {
+    i7 = i8 + 1 | 0;
+    if ((_strcmp(i9, i6) | 0) == 0) {
+     break;
+    }
+    i9 = HEAP32[i4 + (i7 << 2) >> 2] | 0;
+    if ((i9 | 0) == 0) {
+     break L6;
+    } else {
+     i8 = i7;
+    }
+   }
+   STACKTOP = i1;
+   return i8 | 0;
+  }
+ } while (0);
+ HEAP32[i5 >> 2] = i6;
+ i9 = _luaL_argerror(i2, i3, _lua_pushfstring(i2, 1192, i5) | 0) | 0;
+ STACKTOP = i1;
+ return i9 | 0;
+}
+function _lua_toboolean(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ i2 = HEAP32[i3 + 8 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  i5 = 0;
+  i5 = i5 & 1;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ if ((i2 | 0) != 1) {
+  i5 = 1;
+  i5 = i5 & 1;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i5 = (HEAP32[i3 >> 2] | 0) != 0;
+ i5 = i5 & 1;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _lua_getfield(i1, i6, i3) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i5 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i4 = (HEAP32[i1 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i4 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i6 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i4 = HEAP32[i5 >> 2] | 0, (i6 | 0) <= (HEAPU8[i4 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i4 + (i6 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i4 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i4 = i4 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i4 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i3 = _luaS_new(i1, i3) | 0;
+ HEAP32[i6 >> 2] = i3;
+ HEAP32[i6 + 8 >> 2] = HEAPU8[i3 + 4 | 0] | 0 | 64;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i6 + 16;
+ _luaV_gettable(i1, i4, i6, i6);
+ STACKTOP = i2;
+ return;
+}
+function _luaL_argerror(i1, i6, i3) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i2 = i4;
+ i5 = i4 + 12 | 0;
+ if ((_lua_getstack(i1, 0, i5) | 0) == 0) {
+  HEAP32[i2 >> 2] = i6;
+  HEAP32[i2 + 4 >> 2] = i3;
+  i8 = _luaL_error(i1, 1040, i2) | 0;
+  STACKTOP = i4;
+  return i8 | 0;
+ }
+ _lua_getinfo(i1, 1064, i5) | 0;
+ if ((_strcmp(HEAP32[i5 + 8 >> 2] | 0, 1072) | 0) == 0) {
+  i6 = i6 + -1 | 0;
+  if ((i6 | 0) == 0) {
+   HEAP32[i2 >> 2] = HEAP32[i5 + 4 >> 2];
+   HEAP32[i2 + 4 >> 2] = i3;
+   i8 = _luaL_error(i1, 1080, i2) | 0;
+   STACKTOP = i4;
+   return i8 | 0;
+  }
+ }
+ i7 = i5 + 4 | 0;
+ i8 = HEAP32[i7 >> 2] | 0;
+ if ((i8 | 0) == 0) {
+  if ((_pushglobalfuncname(i1, i5) | 0) == 0) {
+   i8 = 1112;
+  } else {
+   i8 = _lua_tolstring(i1, -1, 0) | 0;
+  }
+  HEAP32[i7 >> 2] = i8;
+ }
+ HEAP32[i2 >> 2] = i6;
+ HEAP32[i2 + 4 >> 2] = i8;
+ HEAP32[i2 + 8 >> 2] = i3;
+ i8 = _luaL_error(i1, 1120, i2) | 0;
+ STACKTOP = i4;
+ return i8 | 0;
+}
+function _match_class(i3, i2) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ switch (_tolower(i2 | 0) | 0) {
+ case 117:
+  {
+   i3 = _isupper(i3 | 0) | 0;
+   break;
+  }
+ case 97:
+  {
+   i3 = _isalpha(i3 | 0) | 0;
+   break;
+  }
+ case 99:
+  {
+   i3 = _iscntrl(i3 | 0) | 0;
+   break;
+  }
+ case 120:
+  {
+   i3 = _isxdigit(i3 | 0) | 0;
+   break;
+  }
+ case 119:
+  {
+   i3 = _isalnum(i3 | 0) | 0;
+   break;
+  }
+ case 112:
+  {
+   i3 = _ispunct(i3 | 0) | 0;
+   break;
+  }
+ case 100:
+  {
+   i3 = (i3 + -48 | 0) >>> 0 < 10 | 0;
+   break;
+  }
+ case 108:
+  {
+   i3 = _islower(i3 | 0) | 0;
+   break;
+  }
+ case 122:
+  {
+   i3 = (i3 | 0) == 0 | 0;
+   break;
+  }
+ case 103:
+  {
+   i3 = _isgraph(i3 | 0) | 0;
+   break;
+  }
+ case 115:
+  {
+   i3 = _isspace(i3 | 0) | 0;
+   break;
+  }
+ default:
+  {
+   i3 = (i2 | 0) == (i3 | 0) | 0;
+   STACKTOP = i1;
+   return i3 | 0;
+  }
+ }
+ if ((_islower(i2 | 0) | 0) != 0) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ i3 = (i3 | 0) == 0 | 0;
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function _condjump(i1, i3, i6, i4, i5) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ _luaK_code(i1, i6 << 6 | i3 | i4 << 23 | i5 << 14) | 0;
+ i3 = i1 + 28 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i3 >> 2] = -1;
+ i3 = _luaK_code(i1, 2147450903) | 0;
+ if ((i6 | 0) == -1) {
+  i9 = i3;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ if ((i3 | 0) == -1) {
+  i9 = i6;
+  STACKTOP = i2;
+  return i9 | 0;
+ }
+ i8 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ i7 = i3;
+ while (1) {
+  i4 = i8 + (i7 << 2) | 0;
+  i5 = HEAP32[i4 >> 2] | 0;
+  i9 = (i5 >>> 14) + -131071 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  }
+  i9 = i7 + 1 + i9 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  } else {
+   i7 = i9;
+  }
+ }
+ i6 = i6 + ~i7 | 0;
+ if ((((i6 | 0) > -1 ? i6 : 0 - i6 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i4 >> 2] = (i6 << 14) + 2147467264 | i5 & 16383;
+ i9 = i3;
+ STACKTOP = i2;
+ return i9 | 0;
+}
+function _skipcomment(i6, i1) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ HEAP32[i6 >> 2] = 0;
+ i3 = i6 + 4 | 0;
+ i5 = 1712;
+ while (1) {
+  i7 = _fgetc(HEAP32[i3 >> 2] | 0) | 0;
+  if ((i7 | 0) == -1) {
+   i4 = 3;
+   break;
+  }
+  i8 = i5 + 1 | 0;
+  if ((i7 | 0) != (HEAPU8[i5] | 0)) {
+   break;
+  }
+  i5 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i5 + 1;
+  HEAP8[i6 + i5 + 8 | 0] = i7;
+  if ((HEAP8[i8] | 0) == 0) {
+   i4 = 6;
+   break;
+  } else {
+   i5 = i8;
+  }
+ }
+ if ((i4 | 0) == 3) {
+  HEAP32[i1 >> 2] = -1;
+  i8 = 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ } else if ((i4 | 0) == 6) {
+  HEAP32[i6 >> 2] = 0;
+  i7 = _fgetc(HEAP32[i3 >> 2] | 0) | 0;
+ }
+ HEAP32[i1 >> 2] = i7;
+ if ((i7 | 0) != 35) {
+  i8 = 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ do {
+  i8 = _fgetc(HEAP32[i3 >> 2] | 0) | 0;
+ } while (!((i8 | 0) == 10 | (i8 | 0) == -1));
+ HEAP32[i1 >> 2] = _fgetc(HEAP32[i3 >> 2] | 0) | 0;
+ i8 = 1;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _lua_isnumber(i4, i6) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ i5 = HEAP32[i4 + 16 >> 2] | 0;
+ do {
+  if ((i6 | 0) <= 0) {
+   if (!((i6 | 0) < -1000999)) {
+    i3 = (HEAP32[i4 + 8 >> 2] | 0) + (i6 << 4) | 0;
+    break;
+   }
+   if ((i6 | 0) == -1001e3) {
+    i3 = (HEAP32[i4 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i6 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i5 >> 2] | 0) + (i6 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i4 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i3 + 8 >> 2] | 0) == 3) {
+  i6 = 1;
+  i6 = i6 & 1;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ i6 = (_luaV_tonumber(i3, i2) | 0) != 0;
+ i6 = i6 & 1;
+ STACKTOP = i1;
+ return i6 | 0;
+}
+function ___shgetc(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i7 = i3 + 104 | 0;
+ i6 = HEAP32[i7 >> 2] | 0;
+ if (!((i6 | 0) != 0 ? (HEAP32[i3 + 108 >> 2] | 0) >= (i6 | 0) : 0)) {
+  i8 = 3;
+ }
+ if ((i8 | 0) == 3 ? (i1 = ___uflow(i3) | 0, (i1 | 0) >= 0) : 0) {
+  i7 = HEAP32[i7 >> 2] | 0;
+  i6 = HEAP32[i3 + 8 >> 2] | 0;
+  if ((i7 | 0) != 0 ? (i4 = HEAP32[i3 + 4 >> 2] | 0, i5 = i7 - (HEAP32[i3 + 108 >> 2] | 0) + -1 | 0, (i6 - i4 | 0) > (i5 | 0)) : 0) {
+   HEAP32[i3 + 100 >> 2] = i4 + i5;
+  } else {
+   HEAP32[i3 + 100 >> 2] = i6;
+  }
+  i4 = HEAP32[i3 + 4 >> 2] | 0;
+  if ((i6 | 0) != 0) {
+   i8 = i3 + 108 | 0;
+   HEAP32[i8 >> 2] = i6 + 1 - i4 + (HEAP32[i8 >> 2] | 0);
+  }
+  i3 = i4 + -1 | 0;
+  if ((HEAPU8[i3] | 0 | 0) == (i1 | 0)) {
+   i8 = i1;
+   STACKTOP = i2;
+   return i8 | 0;
+  }
+  HEAP8[i3] = i1;
+  i8 = i1;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ HEAP32[i3 + 100 >> 2] = 0;
+ i8 = -1;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _lua_type(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i2 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i2 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i2 = -1001e3 - i4 | 0;
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((HEAP32[i3 + 8 >> 2] | 0) == 22) {
+    i4 = -1;
+    STACKTOP = i1;
+    return i4 | 0;
+   }
+   i3 = HEAP32[i3 >> 2] | 0;
+   if ((i2 | 0) > (HEAPU8[i3 + 6 | 0] | 0 | 0)) {
+    i4 = -1;
+    STACKTOP = i1;
+    return i4 | 0;
+   } else {
+    i2 = i3 + (i2 + -1 << 4) + 16 | 0;
+    break;
+   }
+  } else {
+   i3 = (HEAP32[i3 >> 2] | 0) + (i4 << 4) | 0;
+   i2 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ if ((i2 | 0) == 5192) {
+  i4 = -1;
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i4 = HEAP32[i2 + 8 >> 2] & 15;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _g_iofile(i4, i1, i5) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_type(i4, 1) | 0) < 1) {
+  _lua_getfield(i4, -1001e3, i1);
+  STACKTOP = i2;
+  return;
+ }
+ i6 = _lua_tolstring(i4, 1, 0) | 0;
+ if ((i6 | 0) != 0) {
+  i7 = _lua_newuserdata(i4, 8) | 0;
+  i8 = i7 + 4 | 0;
+  HEAP32[i8 >> 2] = 0;
+  _luaL_setmetatable(i4, 2832);
+  HEAP32[i7 >> 2] = 0;
+  HEAP32[i8 >> 2] = 156;
+  i5 = _fopen(i6 | 0, i5 | 0) | 0;
+  HEAP32[i7 >> 2] = i5;
+  if ((i5 | 0) == 0) {
+   i8 = _strerror(HEAP32[(___errno_location() | 0) >> 2] | 0) | 0;
+   HEAP32[i3 >> 2] = i6;
+   HEAP32[i3 + 4 >> 2] = i8;
+   _luaL_error(i4, 3520, i3) | 0;
+  }
+ } else {
+  if ((HEAP32[(_luaL_checkudata(i4, 1, 2832) | 0) + 4 >> 2] | 0) == 0) {
+   _luaL_error(i4, 3080, i3) | 0;
+  }
+  _lua_pushvalue(i4, 1);
+ }
+ _lua_setfield(i4, -1001e3, i1);
+ _lua_getfield(i4, -1001e3, i1);
+ STACKTOP = i2;
+ return;
+}
+function _lua_getlocal(i4, i5, i2) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((i5 | 0) == 0) {
+  i3 = HEAP32[i4 + 8 >> 2] | 0;
+  if ((HEAP32[i3 + -8 >> 2] | 0) != 70) {
+   i5 = 0;
+   STACKTOP = i1;
+   return i5 | 0;
+  }
+  i5 = _luaF_getlocalname(HEAP32[(HEAP32[i3 + -16 >> 2] | 0) + 12 >> 2] | 0, i2, 0) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else {
+  HEAP32[i3 >> 2] = 0;
+  i2 = _findlocal(i4, HEAP32[i5 + 96 >> 2] | 0, i2, i3) | 0;
+  if ((i2 | 0) == 0) {
+   i5 = 0;
+   STACKTOP = i1;
+   return i5 | 0;
+  }
+  i3 = HEAP32[i3 >> 2] | 0;
+  i5 = i4 + 8 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i8 = i3;
+  i7 = HEAP32[i8 + 4 >> 2] | 0;
+  i6 = i4;
+  HEAP32[i6 >> 2] = HEAP32[i8 >> 2];
+  HEAP32[i6 + 4 >> 2] = i7;
+  HEAP32[i4 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+  HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 16;
+  i5 = i2;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _lua_checkstack(i7, i4) {
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ HEAP32[i3 >> 2] = i4;
+ i2 = HEAP32[i7 + 16 >> 2] | 0;
+ i5 = i7 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i8 = i6;
+ do {
+  if (((HEAP32[i7 + 24 >> 2] | 0) - i8 >> 4 | 0) <= (i4 | 0)) {
+   if (((i8 - (HEAP32[i7 + 28 >> 2] | 0) >> 4) + 5 | 0) > (1e6 - i4 | 0)) {
+    i8 = 0;
+    STACKTOP = i1;
+    return i8 | 0;
+   }
+   i6 = (_luaD_rawrunprotected(i7, 2, i3) | 0) == 0;
+   if (i6) {
+    i5 = HEAP32[i5 >> 2] | 0;
+    i4 = HEAP32[i3 >> 2] | 0;
+    i3 = i6 & 1;
+    break;
+   } else {
+    i8 = 0;
+    STACKTOP = i1;
+    return i8 | 0;
+   }
+  } else {
+   i5 = i6;
+   i3 = 1;
+  }
+ } while (0);
+ i2 = i2 + 4 | 0;
+ i4 = i5 + (i4 << 4) | 0;
+ if (!((HEAP32[i2 >> 2] | 0) >>> 0 < i4 >>> 0)) {
+  i8 = i3;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ HEAP32[i2 >> 2] = i4;
+ i8 = i3;
+ STACKTOP = i1;
+ return i8 | 0;
+}
+function _luaK_exp2nextreg(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ _luaK_dischargevars(i1, i3);
+ if (((HEAP32[i3 >> 2] | 0) == 6 ? (i4 = HEAP32[i3 + 8 >> 2] | 0, (i4 & 256 | 0) == 0) : 0) ? (HEAPU8[i1 + 46 | 0] | 0 | 0) <= (i4 | 0) : 0) {
+  i7 = i1 + 48 | 0;
+  HEAP8[i7] = (HEAP8[i7] | 0) + -1 << 24 >> 24;
+ }
+ i4 = i1 + 48 | 0;
+ i5 = HEAP8[i4] | 0;
+ i6 = (i5 & 255) + 1 | 0;
+ i7 = (HEAP32[i1 >> 2] | 0) + 78 | 0;
+ if (!(i6 >>> 0 > (HEAPU8[i7] | 0) >>> 0)) {
+  i7 = i5;
+  i7 = i7 & 255;
+  i7 = i7 + 1 | 0;
+  i6 = i7 & 255;
+  HEAP8[i4] = i6;
+  i7 = i7 & 255;
+  i7 = i7 + -1 | 0;
+  _exp2reg(i1, i3, i7);
+  STACKTOP = i2;
+  return;
+ }
+ if (i6 >>> 0 > 249) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10536);
+ }
+ HEAP8[i7] = i6;
+ i7 = HEAP8[i4] | 0;
+ i7 = i7 & 255;
+ i7 = i7 + 1 | 0;
+ i6 = i7 & 255;
+ HEAP8[i4] = i6;
+ i7 = i7 & 255;
+ i7 = i7 + -1 | 0;
+ _exp2reg(i1, i3, i7);
+ STACKTOP = i2;
+ return;
+}
+function _lua_next(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i5 = HEAP32[i2 + 16 >> 2] | 0;
+ do {
+  if ((i4 | 0) <= 0) {
+   if (!((i4 | 0) < -1000999)) {
+    i4 = (HEAP32[i2 + 8 >> 2] | 0) + (i4 << 4) | 0;
+    break;
+   }
+   if ((i4 | 0) == -1001e3) {
+    i4 = (HEAP32[i2 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i4 = -1001e3 - i4 | 0;
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((HEAP32[i5 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i5 >> 2] | 0, (i4 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i4 = i3 + (i4 + -1 << 4) + 16 | 0;
+   } else {
+    i4 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i5 >> 2] | 0) + (i4 << 4) | 0;
+   i4 = i3 >>> 0 < (HEAP32[i2 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i3 = i2 + 8 | 0;
+ i2 = _luaH_next(i2, HEAP32[i4 >> 2] | 0, (HEAP32[i3 >> 2] | 0) + -16 | 0) | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i3 >> 2] = (i2 | 0) == 0 ? i4 + -16 | 0 : i4 + 16 | 0;
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _inclinenumber(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 >> 2] | 0;
+ i3 = i1 + 56 | 0;
+ i5 = HEAP32[i3 >> 2] | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i6 + -1;
+ if ((i6 | 0) == 0) {
+  i5 = _luaZ_fill(i5) | 0;
+ } else {
+  i6 = i5 + 4 | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i5 + 1;
+  i5 = HEAPU8[i5] | 0;
+ }
+ HEAP32[i1 >> 2] = i5;
+ if ((i5 | 0) == 13 | (i5 | 0) == 10 ? (i5 | 0) != (i4 | 0) : 0) {
+  i3 = HEAP32[i3 >> 2] | 0;
+  i6 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i3 >> 2] = i6 + -1;
+  if ((i6 | 0) == 0) {
+   i3 = _luaZ_fill(i3) | 0;
+  } else {
+   i6 = i3 + 4 | 0;
+   i3 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i3 + 1;
+   i3 = HEAPU8[i3] | 0;
+  }
+  HEAP32[i1 >> 2] = i3;
+ }
+ i5 = i1 + 4 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i6 + 1;
+ if ((i6 | 0) > 2147483643) {
+  _luaX_syntaxerror(i1, 12560);
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _lua_yieldk(i5, i6, i1, i7) {
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = HEAP32[i5 + 16 >> 2] | 0;
+ if ((HEAP16[i5 + 36 >> 1] | 0) != 0) {
+  if ((HEAP32[(HEAP32[i5 + 12 >> 2] | 0) + 172 >> 2] | 0) == (i5 | 0)) {
+   _luaG_runerror(i5, 2312, i4);
+  } else {
+   _luaG_runerror(i5, 2264, i4);
+  }
+ }
+ HEAP8[i5 + 6 | 0] = 1;
+ HEAP32[i3 + 20 >> 2] = (HEAP32[i3 >> 2] | 0) - (HEAP32[i5 + 28 >> 2] | 0);
+ if (!((HEAP8[i3 + 18 | 0] & 1) == 0)) {
+  STACKTOP = i2;
+  return 0;
+ }
+ HEAP32[i3 + 28 >> 2] = i7;
+ if ((i7 | 0) == 0) {
+  i4 = i5 + 8 | 0;
+  i4 = HEAP32[i4 >> 2] | 0;
+  i7 = ~i6;
+  i7 = i4 + (i7 << 4) | 0;
+  HEAP32[i3 >> 2] = i7;
+  _luaD_throw(i5, 1);
+ }
+ HEAP32[i3 + 24 >> 2] = i1;
+ i4 = i5 + 8 | 0;
+ i4 = HEAP32[i4 >> 2] | 0;
+ i7 = ~i6;
+ i7 = i4 + (i7 << 4) | 0;
+ HEAP32[i3 >> 2] = i7;
+ _luaD_throw(i5, 1);
+ return 0;
+}
+function _luaH_getint(i4, i6) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, d3 = 0.0, i5 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i1;
+ i7 = i6 + -1 | 0;
+ if (i7 >>> 0 < (HEAP32[i4 + 28 >> 2] | 0) >>> 0) {
+  i7 = (HEAP32[i4 + 12 >> 2] | 0) + (i7 << 4) | 0;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ d3 = +(i6 | 0);
+ HEAPF64[i5 >> 3] = d3 + 1.0;
+ i5 = (HEAP32[i5 + 4 >> 2] | 0) + (HEAP32[i5 >> 2] | 0) | 0;
+ if ((i5 | 0) < 0) {
+  i6 = 0 - i5 | 0;
+  i5 = (i5 | 0) == (i6 | 0) ? 0 : i6;
+ }
+ i4 = (HEAP32[i4 + 16 >> 2] | 0) + (((i5 | 0) % ((1 << (HEAPU8[i4 + 7 | 0] | 0)) + -1 | 1 | 0) | 0) << 5) | 0;
+ while (1) {
+  if ((HEAP32[i4 + 24 >> 2] | 0) == 3 ? +HEAPF64[i4 + 16 >> 3] == d3 : 0) {
+   break;
+  }
+  i4 = HEAP32[i4 + 28 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   i4 = 5192;
+   i2 = 10;
+   break;
+  }
+ }
+ if ((i2 | 0) == 10) {
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i7 = i4;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaL_checkversion_(i1, d4) {
+ i1 = i1 | 0;
+ d4 = +d4;
+ var i2 = 0, i3 = 0, i5 = 0, d6 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i5 = _lua_version(i1) | 0;
+ if ((i5 | 0) == (_lua_version(0) | 0)) {
+  d6 = +HEAPF64[i5 >> 3];
+  if (d6 != d4) {
+   HEAPF64[tempDoublePtr >> 3] = d4;
+   HEAP32[i3 >> 2] = HEAP32[tempDoublePtr >> 2];
+   HEAP32[i3 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+   i5 = i3 + 8 | 0;
+   HEAPF64[tempDoublePtr >> 3] = d6;
+   HEAP32[i5 >> 2] = HEAP32[tempDoublePtr >> 2];
+   HEAP32[i5 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+   _luaL_error(i1, 1528, i3) | 0;
+  }
+ } else {
+  _luaL_error(i1, 1496, i3) | 0;
+ }
+ _lua_pushnumber(i1, -4660.0);
+ if ((_lua_tointegerx(i1, -1, 0) | 0) == -4660 ? (_lua_tounsignedx(i1, -1, 0) | 0) == -4660 : 0) {
+  _lua_settop(i1, -2);
+  STACKTOP = i2;
+  return;
+ }
+ _luaL_error(i1, 1584, i3) | 0;
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return;
+}
+function _math_random(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0, i4 = 0, i5 = 0, d6 = 0.0, d7 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ d3 = +((_rand() | 0) % 2147483647 | 0 | 0) / 2147483647.0;
+ i5 = _lua_gettop(i1) | 0;
+ if ((i5 | 0) == 0) {
+  _lua_pushnumber(i1, d3);
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else if ((i5 | 0) == 1) {
+  d6 = +_luaL_checknumber(i1, 1);
+  if (!(d6 >= 1.0)) {
+   _luaL_argerror(i1, 1, 4056) | 0;
+  }
+  _lua_pushnumber(i1, +Math_floor(+(d3 * d6)) + 1.0);
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else if ((i5 | 0) == 2) {
+  d6 = +_luaL_checknumber(i1, 1);
+  d7 = +_luaL_checknumber(i1, 2);
+  if (!(d6 <= d7)) {
+   _luaL_argerror(i1, 2, 4056) | 0;
+  }
+  _lua_pushnumber(i1, d6 + +Math_floor(+(d3 * (d7 - d6 + 1.0))));
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i5 = _luaL_error(i1, 4080, i4) | 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _push_onecapture(i2, i3, i4, i6) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i5 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i1;
+ if ((HEAP32[i2 + 20 >> 2] | 0) <= (i3 | 0)) {
+  i2 = HEAP32[i2 + 16 >> 2] | 0;
+  if ((i3 | 0) == 0) {
+   _lua_pushlstring(i2, i4, i6 - i4 | 0) | 0;
+   STACKTOP = i1;
+   return;
+  } else {
+   _luaL_error(i2, 7224, i5) | 0;
+   STACKTOP = i1;
+   return;
+  }
+ }
+ i4 = HEAP32[i2 + (i3 << 3) + 28 >> 2] | 0;
+ if (!((i4 | 0) == -1)) {
+  i5 = HEAP32[i2 + 16 >> 2] | 0;
+  i3 = HEAP32[i2 + (i3 << 3) + 24 >> 2] | 0;
+  if ((i4 | 0) == -2) {
+   _lua_pushinteger(i5, i3 + 1 - (HEAP32[i2 + 4 >> 2] | 0) | 0);
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  i6 = i2 + 16 | 0;
+  _luaL_error(HEAP32[i6 >> 2] | 0, 7248, i5) | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i3 = HEAP32[i2 + (i3 << 3) + 24 >> 2] | 0;
+ }
+ _lua_pushlstring(i5, i3, i4) | 0;
+ STACKTOP = i1;
+ return;
+}
+function _luaK_nil(i7, i6, i5) {
+ i7 = i7 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ i9 = i5 + i6 | 0;
+ i1 = i9 + -1 | 0;
+ i10 = HEAP32[i7 + 20 >> 2] | 0;
+ do {
+  if ((i10 | 0) > (HEAP32[i7 + 24 >> 2] | 0) ? (i4 = (HEAP32[(HEAP32[i7 >> 2] | 0) + 12 >> 2] | 0) + (i10 + -1 << 2) | 0, i3 = HEAP32[i4 >> 2] | 0, (i3 & 63 | 0) == 4) : 0) {
+   i11 = i3 >>> 6 & 255;
+   i10 = i11 + (i3 >>> 23) | 0;
+   if (!((i11 | 0) <= (i6 | 0) ? (i10 + 1 | 0) >= (i6 | 0) : 0)) {
+    i8 = 5;
+   }
+   if ((i8 | 0) == 5 ? (i11 | 0) < (i6 | 0) | (i11 | 0) > (i9 | 0) : 0) {
+    break;
+   }
+   i5 = (i11 | 0) < (i6 | 0) ? i11 : i6;
+   HEAP32[i4 >> 2] = ((i10 | 0) > (i1 | 0) ? i10 : i1) - i5 << 23 | i5 << 6 & 16320 | i3 & 8372287;
+   STACKTOP = i2;
+   return;
+  }
+ } while (0);
+ _luaK_code(i7, i6 << 6 | (i5 << 23) + -8388608 | 4) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _lua_settable(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ _luaV_settable(i1, i3, i4 + -32 | 0, i4 + -16 | 0);
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + -32;
+ STACKTOP = i2;
+ return;
+}
+function _luaL_findtable(i3, i6, i5, i4) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i7 = 0;
+ i2 = STACKTOP;
+ if ((i6 | 0) != 0) {
+  _lua_pushvalue(i3, i6);
+ }
+ while (1) {
+  i6 = _strchr(i5, 46) | 0;
+  if ((i6 | 0) == 0) {
+   i6 = i5 + (_strlen(i5 | 0) | 0) | 0;
+  }
+  i7 = i6 - i5 | 0;
+  _lua_pushlstring(i3, i5, i7) | 0;
+  _lua_rawget(i3, -2);
+  if ((_lua_type(i3, -1) | 0) != 0) {
+   if ((_lua_type(i3, -1) | 0) != 5) {
+    break;
+   }
+  } else {
+   _lua_settop(i3, -2);
+   _lua_createtable(i3, 0, (HEAP8[i6] | 0) == 46 ? 1 : i4);
+   _lua_pushlstring(i3, i5, i7) | 0;
+   _lua_pushvalue(i3, -2);
+   _lua_settable(i3, -4);
+  }
+  _lua_remove(i3, -2);
+  if ((HEAP8[i6] | 0) == 46) {
+   i5 = i6 + 1 | 0;
+  } else {
+   i3 = 0;
+   i1 = 10;
+   break;
+  }
+ }
+ if ((i1 | 0) == 10) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_settop(i3, -3);
+ i7 = i5;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _luaD_call(i1, i4, i5, i8) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i8 = i8 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i7 = i3;
+ i2 = i1 + 38 | 0;
+ i6 = (HEAP16[i2 >> 1] | 0) + 1 << 16 >> 16;
+ HEAP16[i2 >> 1] = i6;
+ if ((i6 & 65535) > 199) {
+  if (i6 << 16 >> 16 == 200) {
+   _luaG_runerror(i1, 2240, i7);
+  }
+  if ((i6 & 65535) > 224) {
+   _luaD_throw(i1, 6);
+  }
+ }
+ i6 = (i8 | 0) != 0;
+ if (!i6) {
+  i8 = i1 + 36 | 0;
+  HEAP16[i8 >> 1] = (HEAP16[i8 >> 1] | 0) + 1 << 16 >> 16;
+ }
+ if ((_luaD_precall(i1, i4, i5) | 0) == 0) {
+  _luaV_execute(i1);
+ }
+ if (i6) {
+  i8 = HEAP16[i2 >> 1] | 0;
+  i8 = i8 + -1 << 16 >> 16;
+  HEAP16[i2 >> 1] = i8;
+  STACKTOP = i3;
+  return;
+ }
+ i8 = i1 + 36 | 0;
+ HEAP16[i8 >> 1] = (HEAP16[i8 >> 1] | 0) + -1 << 16 >> 16;
+ i8 = HEAP16[i2 >> 1] | 0;
+ i8 = i8 + -1 << 16 >> 16;
+ HEAP16[i2 >> 1] = i8;
+ STACKTOP = i3;
+ return;
+}
+function _pushline(i6, i1) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 528 | 0;
+ i4 = i2;
+ i3 = i2 + 8 | 0;
+ i7 = (i1 | 0) != 0;
+ _lua_getglobal(i6, i7 ? 288 : 296);
+ i8 = _lua_tolstring(i6, -1, 0) | 0;
+ if ((i8 | 0) == 0) {
+  i8 = i7 ? 312 : 320;
+ }
+ i7 = HEAP32[_stdout >> 2] | 0;
+ _fputs(i8 | 0, i7 | 0) | 0;
+ _fflush(i7 | 0) | 0;
+ i8 = (_fgets(i3 | 0, 512, HEAP32[_stdin >> 2] | 0) | 0) == 0;
+ _lua_settop(i6, -2);
+ if (i8) {
+  i8 = 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ i7 = _strlen(i3 | 0) | 0;
+ if ((i7 | 0) != 0 ? (i5 = i3 + (i7 + -1) | 0, (HEAP8[i5] | 0) == 10) : 0) {
+  HEAP8[i5] = 0;
+ }
+ if ((i1 | 0) != 0 ? (HEAP8[i3] | 0) == 61 : 0) {
+  HEAP32[i4 >> 2] = i3 + 1;
+  _lua_pushfstring(i6, 272, i4) | 0;
+  i8 = 1;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ _lua_pushstring(i6, i3) | 0;
+ i8 = 1;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _db_getlocal(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i2;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i3 = _lua_tothread(i1, 1) | 0;
+  i6 = 1;
+ } else {
+  i3 = i1;
+  i6 = 0;
+ }
+ i5 = _luaL_checkinteger(i1, i6 | 2) | 0;
+ i6 = i6 + 1 | 0;
+ if ((_lua_type(i1, i6) | 0) == 6) {
+  _lua_pushvalue(i1, i6);
+  _lua_pushstring(i1, _lua_getlocal(i1, 0, i5) | 0) | 0;
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ if ((_lua_getstack(i3, _luaL_checkinteger(i1, i6) | 0, i4) | 0) == 0) {
+  i6 = _luaL_argerror(i1, i6, 11560) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ i4 = _lua_getlocal(i3, i4, i5) | 0;
+ if ((i4 | 0) == 0) {
+  _lua_pushnil(i1);
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  _lua_xmove(i3, i1, 1);
+  _lua_pushstring(i1, i4) | 0;
+  _lua_pushvalue(i1, -2);
+  i6 = 2;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ return 0;
+}
+function _luaB_print(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i3;
+ i4 = i3 + 4 | 0;
+ i6 = _lua_gettop(i1) | 0;
+ _lua_getglobal(i1, 9584);
+ i5 = HEAP32[_stdout >> 2] | 0;
+ L1 : do {
+  if ((i6 | 0) >= 1) {
+   i7 = 1;
+   while (1) {
+    _lua_pushvalue(i1, -1);
+    _lua_pushvalue(i1, i7);
+    _lua_callk(i1, 1, 1, 0, 0);
+    i8 = _lua_tolstring(i1, -1, i4) | 0;
+    if ((i8 | 0) == 0) {
+     break;
+    }
+    if ((i7 | 0) > 1) {
+     _fputc(9, i5 | 0) | 0;
+    }
+    _fwrite(i8 | 0, 1, HEAP32[i4 >> 2] | 0, i5 | 0) | 0;
+    _lua_settop(i1, -2);
+    if ((i7 | 0) < (i6 | 0)) {
+     i7 = i7 + 1 | 0;
+    } else {
+     break L1;
+    }
+   }
+   i8 = _luaL_error(i1, 9816, i2) | 0;
+   STACKTOP = i3;
+   return i8 | 0;
+  }
+ } while (0);
+ _fputc(10, i5 | 0) | 0;
+ _fflush(i5 | 0) | 0;
+ i8 = 0;
+ STACKTOP = i3;
+ return i8 | 0;
+}
+function _luaB_load(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i2;
+ i6 = _lua_tolstring(i1, 1, i5) | 0;
+ i4 = _luaL_optlstring(i1, 3, 9872, 0) | 0;
+ i3 = (_lua_type(i1, 4) | 0) != -1;
+ if ((i6 | 0) == 0) {
+  i6 = _luaL_optlstring(i1, 2, 9880, 0) | 0;
+  _luaL_checktype(i1, 1, 6);
+  _lua_settop(i1, 5);
+  i4 = _lua_load(i1, 3, 0, i6, i4) | 0;
+ } else {
+  i7 = _luaL_optlstring(i1, 2, i6, 0) | 0;
+  i4 = _luaL_loadbufferx(i1, i6, HEAP32[i5 >> 2] | 0, i7, i4) | 0;
+ }
+ if ((i4 | 0) != 0) {
+  _lua_pushnil(i1);
+  _lua_insert(i1, -2);
+  i7 = 2;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ if (!i3) {
+  i7 = 1;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ _lua_pushvalue(i1, i3 ? 4 : 0);
+ if ((_lua_setupvalue(i1, -2, 1) | 0) != 0) {
+  i7 = 1;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ _lua_settop(i1, -2);
+ i7 = 1;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _db_debug(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 256 | 0;
+ i6 = i1;
+ i4 = i1 + 4 | 0;
+ i3 = HEAP32[_stderr >> 2] | 0;
+ _fwrite(12040, 11, 1, i3 | 0) | 0;
+ _fflush(i3 | 0) | 0;
+ i5 = HEAP32[_stdin >> 2] | 0;
+ if ((_fgets(i4 | 0, 250, i5 | 0) | 0) == 0) {
+  STACKTOP = i1;
+  return 0;
+ }
+ while (1) {
+  if ((_strcmp(i4, 12056) | 0) == 0) {
+   i2 = 7;
+   break;
+  }
+  if (!((_luaL_loadbufferx(i2, i4, _strlen(i4 | 0) | 0, 12064, 0) | 0) == 0 ? (_lua_pcallk(i2, 0, 0, 0, 0, 0) | 0) == 0 : 0)) {
+   HEAP32[i6 >> 2] = _lua_tolstring(i2, -1, 0) | 0;
+   _fprintf(i3 | 0, 12088, i6 | 0) | 0;
+   _fflush(i3 | 0) | 0;
+  }
+  _lua_settop(i2, 0);
+  _fwrite(12040, 11, 1, i3 | 0) | 0;
+  _fflush(i3 | 0) | 0;
+  if ((_fgets(i4 | 0, 250, i5 | 0) | 0) == 0) {
+   i2 = 7;
+   break;
+  }
+ }
+ if ((i2 | 0) == 7) {
+  STACKTOP = i1;
+  return 0;
+ }
+ return 0;
+}
+function _luaL_prepbuffsize(i2, i7) {
+ i2 = i2 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i1 = HEAP32[i2 + 12 >> 2] | 0;
+ i4 = i2 + 4 | 0;
+ i8 = HEAP32[i4 >> 2] | 0;
+ i5 = i2 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ if (!((i8 - i6 | 0) >>> 0 < i7 >>> 0)) {
+  i7 = HEAP32[i2 >> 2] | 0;
+  i8 = i6;
+  i8 = i7 + i8 | 0;
+  STACKTOP = i3;
+  return i8 | 0;
+ }
+ i8 = i8 << 1;
+ i8 = (i8 - i6 | 0) >>> 0 < i7 >>> 0 ? i6 + i7 | 0 : i8;
+ if (i8 >>> 0 < i6 >>> 0 | (i8 - i6 | 0) >>> 0 < i7 >>> 0) {
+  _luaL_error(i1, 1272, i3) | 0;
+ }
+ i6 = _lua_newuserdata(i1, i8) | 0;
+ _memcpy(i6 | 0, HEAP32[i2 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+ if ((HEAP32[i2 >> 2] | 0) != (i2 + 16 | 0)) {
+  _lua_remove(i1, -2);
+ }
+ HEAP32[i2 >> 2] = i6;
+ HEAP32[i4 >> 2] = i8;
+ i7 = i6;
+ i8 = HEAP32[i5 >> 2] | 0;
+ i8 = i7 + i8 | 0;
+ STACKTOP = i3;
+ return i8 | 0;
+}
+function _luaG_runerror(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 96 | 0;
+ i2 = i6;
+ i3 = i6 + 32 | 0;
+ i6 = i6 + 16 | 0;
+ HEAP32[i6 >> 2] = i4;
+ i4 = _luaO_pushvfstring(i1, i5, i6) | 0;
+ i6 = HEAP32[i1 + 16 >> 2] | 0;
+ if ((HEAP8[i6 + 18 | 0] & 1) == 0) {
+  _luaG_errormsg(i1);
+ }
+ i5 = HEAP32[(HEAP32[HEAP32[i6 >> 2] >> 2] | 0) + 12 >> 2] | 0;
+ i7 = HEAP32[i5 + 20 >> 2] | 0;
+ if ((i7 | 0) == 0) {
+  i6 = 0;
+ } else {
+  i6 = HEAP32[i7 + (((HEAP32[i6 + 28 >> 2] | 0) - (HEAP32[i5 + 12 >> 2] | 0) >> 2) + -1 << 2) >> 2] | 0;
+ }
+ i5 = HEAP32[i5 + 36 >> 2] | 0;
+ if ((i5 | 0) == 0) {
+  HEAP8[i3] = 63;
+  HEAP8[i3 + 1 | 0] = 0;
+ } else {
+  _luaO_chunkid(i3, i5 + 16 | 0, 60);
+ }
+ HEAP32[i2 >> 2] = i3;
+ HEAP32[i2 + 4 >> 2] = i6;
+ HEAP32[i2 + 8 >> 2] = i4;
+ _luaO_pushfstring(i1, 2024, i2) | 0;
+ _luaG_errormsg(i1);
+}
+function _db_upvaluejoin(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i3;
+ i2 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 6);
+ _lua_pushvalue(i1, 1);
+ _lua_getinfo(i1, 11728, i4) | 0;
+ if (!((i2 | 0) > 0 ? (i2 | 0) <= (HEAPU8[i4 + 32 | 0] | 0 | 0) : 0)) {
+  _luaL_argerror(i1, 2, 11736) | 0;
+ }
+ i5 = _luaL_checkinteger(i1, 4) | 0;
+ _luaL_checktype(i1, 3, 6);
+ _lua_pushvalue(i1, 3);
+ _lua_getinfo(i1, 11728, i4) | 0;
+ if (!((i5 | 0) > 0 ? (i5 | 0) <= (HEAPU8[i4 + 32 | 0] | 0 | 0) : 0)) {
+  _luaL_argerror(i1, 4, 11736) | 0;
+ }
+ if ((_lua_iscfunction(i1, 1) | 0) != 0) {
+  _luaL_argerror(i1, 1, 11760) | 0;
+ }
+ if ((_lua_iscfunction(i1, 3) | 0) == 0) {
+  _lua_upvaluejoin(i1, 1, i2, 3, i5);
+  STACKTOP = i3;
+  return 0;
+ }
+ _luaL_argerror(i1, 3, 11760) | 0;
+ _lua_upvaluejoin(i1, 1, i2, 3, i5);
+ STACKTOP = i3;
+ return 0;
+}
+function _luaK_jump(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i3 = STACKTOP;
+ i2 = i1 + 28 | 0;
+ i7 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i2 >> 2] = -1;
+ i2 = _luaK_code(i1, 2147450903) | 0;
+ if ((i7 | 0) == -1) {
+  i9 = i2;
+  STACKTOP = i3;
+  return i9 | 0;
+ }
+ if ((i2 | 0) == -1) {
+  i9 = i7;
+  STACKTOP = i3;
+  return i9 | 0;
+ }
+ i6 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ i8 = i2;
+ while (1) {
+  i5 = i6 + (i8 << 2) | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  i9 = (i4 >>> 14) + -131071 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  }
+  i9 = i8 + 1 + i9 | 0;
+  if ((i9 | 0) == -1) {
+   break;
+  } else {
+   i8 = i9;
+  }
+ }
+ i6 = i7 + ~i8 | 0;
+ if ((((i6 | 0) > -1 ? i6 : 0 - i6 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i5 >> 2] = (i6 << 14) + 2147467264 | i4 & 16383;
+ i9 = i2;
+ STACKTOP = i3;
+ return i9 | 0;
+}
+function _findfield(i2, i3, i4) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ L1 : do {
+  if (((i4 | 0) != 0 ? (_lua_type(i2, -1) | 0) == 5 : 0) ? (_lua_pushnil(i2), (_lua_next(i2, -2) | 0) != 0) : 0) {
+   i4 = i4 + -1 | 0;
+   while (1) {
+    if ((_lua_type(i2, -2) | 0) == 4) {
+     if ((_lua_rawequal(i2, i3, -1) | 0) != 0) {
+      i3 = 7;
+      break;
+     }
+     if ((_findfield(i2, i3, i4) | 0) != 0) {
+      i3 = 9;
+      break;
+     }
+    }
+    _lua_settop(i2, -2);
+    if ((_lua_next(i2, -2) | 0) == 0) {
+     i2 = 0;
+     break L1;
+    }
+   }
+   if ((i3 | 0) == 7) {
+    _lua_settop(i2, -2);
+    i2 = 1;
+    break;
+   } else if ((i3 | 0) == 9) {
+    _lua_remove(i2, -2);
+    _lua_pushlstring(i2, 1776, 1) | 0;
+    _lua_insert(i2, -2);
+    _lua_concat(i2, 3);
+    i2 = 1;
+    break;
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _db_gethook(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i3;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i4 = _lua_tothread(i1, 1) | 0;
+ } else {
+  i4 = i1;
+ }
+ i5 = _lua_gethookmask(i4) | 0;
+ i6 = _lua_gethook(i4) | 0;
+ if ((i6 | 0) != 0 & (i6 | 0) != 9) {
+  _lua_pushlstring(i1, 12024, 13) | 0;
+ } else {
+  _luaL_getsubtable(i1, -1001e3, 11584) | 0;
+  _lua_pushthread(i4) | 0;
+  _lua_xmove(i4, i1, 1);
+  _lua_rawget(i1, -2);
+  _lua_remove(i1, -2);
+ }
+ if ((i5 & 1 | 0) == 0) {
+  i6 = 0;
+ } else {
+  HEAP8[i2] = 99;
+  i6 = 1;
+ }
+ if ((i5 & 2 | 0) != 0) {
+  HEAP8[i2 + i6 | 0] = 114;
+  i6 = i6 + 1 | 0;
+ }
+ if ((i5 & 4 | 0) != 0) {
+  HEAP8[i2 + i6 | 0] = 108;
+  i6 = i6 + 1 | 0;
+ }
+ HEAP8[i2 + i6 | 0] = 0;
+ _lua_pushstring(i1, i2) | 0;
+ _lua_pushinteger(i1, _lua_gethookcount(i4) | 0);
+ STACKTOP = i3;
+ return 3;
+}
+function _lua_tothread(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i2 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ if ((HEAP32[i2 + 8 >> 2] | 0) != 72) {
+  i5 = 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i5 = HEAP32[i2 >> 2] | 0;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _luaD_throw(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i3 = i1 + 64 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ if ((i4 | 0) != 0) {
+  HEAP32[i4 + 160 >> 2] = i2;
+  _longjmp((HEAP32[i3 >> 2] | 0) + 4 | 0, 1);
+ }
+ HEAP8[i1 + 6 | 0] = i2;
+ i4 = i1 + 12 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ i5 = HEAP32[i3 + 172 >> 2] | 0;
+ if ((HEAP32[i5 + 64 >> 2] | 0) != 0) {
+  i6 = HEAP32[i1 + 8 >> 2] | 0;
+  i9 = i5 + 8 | 0;
+  i5 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i9 >> 2] = i5 + 16;
+  i9 = i6 + -16 | 0;
+  i8 = HEAP32[i9 + 4 >> 2] | 0;
+  i7 = i5;
+  HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+  HEAP32[i7 + 4 >> 2] = i8;
+  HEAP32[i5 + 8 >> 2] = HEAP32[i6 + -8 >> 2];
+  _luaD_throw(HEAP32[(HEAP32[i4 >> 2] | 0) + 172 >> 2] | 0, i2);
+ }
+ i2 = HEAP32[i3 + 168 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  _abort();
+ }
+ FUNCTION_TABLE_ii[i2 & 255](i1) | 0;
+ _abort();
+}
+function _lua_len(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = i1 + 8 | 0;
+ _luaV_objlen(i1, HEAP32[i5 >> 2] | 0, i3);
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return;
+}
+function _read_line(i4, i5, i1) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 1040 | 0;
+ i2 = i3;
+ _luaL_buffinit(i4, i2);
+ i7 = _luaL_prepbuffsize(i2, 1024) | 0;
+ L1 : do {
+  if ((_fgets(i7 | 0, 1024, i5 | 0) | 0) != 0) {
+   i6 = i2 + 8 | 0;
+   while (1) {
+    i8 = _strlen(i7 | 0) | 0;
+    if ((i8 | 0) != 0 ? (HEAP8[i7 + (i8 + -1) | 0] | 0) == 10 : 0) {
+     break;
+    }
+    HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i8;
+    i7 = _luaL_prepbuffsize(i2, 1024) | 0;
+    if ((_fgets(i7 | 0, 1024, i5 | 0) | 0) == 0) {
+     break L1;
+    }
+   }
+   HEAP32[i6 >> 2] = i8 - i1 + (HEAP32[i6 >> 2] | 0);
+   _luaL_pushresult(i2);
+   i8 = 1;
+   STACKTOP = i3;
+   return i8 | 0;
+  }
+ } while (0);
+ _luaL_pushresult(i2);
+ i8 = (_lua_rawlen(i4, -1) | 0) != 0 | 0;
+ STACKTOP = i3;
+ return i8 | 0;
+}
+function _luaL_tolstring(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ do {
+  if ((_luaL_callmeta(i1, i5, 1384) | 0) == 0) {
+   i6 = _lua_type(i1, i5) | 0;
+   if ((i6 | 0) == 0) {
+    _lua_pushlstring(i1, 1416, 3) | 0;
+    break;
+   } else if ((i6 | 0) == 1) {
+    i6 = (_lua_toboolean(i1, i5) | 0) != 0;
+    _lua_pushstring(i1, i6 ? 1400 : 1408) | 0;
+    break;
+   } else if ((i6 | 0) == 4 | (i6 | 0) == 3) {
+    _lua_pushvalue(i1, i5);
+    break;
+   } else {
+    i7 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+    i6 = _lua_topointer(i1, i5) | 0;
+    HEAP32[i3 >> 2] = i7;
+    HEAP32[i3 + 4 >> 2] = i6;
+    _lua_pushfstring(i1, 1424, i3) | 0;
+    break;
+   }
+  }
+ } while (0);
+ i7 = _lua_tolstring(i1, -1, i4) | 0;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _save(i7, i1) {
+ i7 = i7 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i7 + 60 >> 2] | 0;
+ i3 = i4 + 4 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ i6 = i4 + 8 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ if (!((i8 + 1 | 0) >>> 0 > i5 >>> 0)) {
+  i6 = HEAP32[i4 >> 2] | 0;
+  i7 = i1 & 255;
+  i5 = i8 + 1 | 0;
+  HEAP32[i3 >> 2] = i5;
+  i8 = i6 + i8 | 0;
+  HEAP8[i8] = i7;
+  STACKTOP = i2;
+  return;
+ }
+ if (i5 >>> 0 > 2147483645) {
+  _lexerror(i7, 12368, 0);
+ }
+ i8 = i5 << 1;
+ i7 = HEAP32[i7 + 52 >> 2] | 0;
+ if ((i8 | 0) == -2) {
+  _luaM_toobig(i7);
+ }
+ i7 = _luaM_realloc_(i7, HEAP32[i4 >> 2] | 0, i5, i8) | 0;
+ HEAP32[i4 >> 2] = i7;
+ HEAP32[i6 >> 2] = i8;
+ i8 = HEAP32[i3 >> 2] | 0;
+ i6 = i7;
+ i7 = i1 & 255;
+ i5 = i8 + 1 | 0;
+ HEAP32[i3 >> 2] = i5;
+ i8 = i6 + i8 | 0;
+ HEAP8[i8] = i7;
+ STACKTOP = i2;
+ return;
+}
+function _luaK_patchtohere(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 24 >> 2] = HEAP32[i1 + 20 >> 2];
+ i4 = i1 + 28 | 0;
+ if ((i3 | 0) == -1) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[i4 >> 2] | 0;
+ if ((i7 | 0) == -1) {
+  HEAP32[i4 >> 2] = i3;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ while (1) {
+  i6 = i4 + (i7 << 2) | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i8 = (i5 >>> 14) + -131071 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  }
+  i8 = i7 + 1 + i8 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  } else {
+   i7 = i8;
+  }
+ }
+ i3 = ~i7 + i3 | 0;
+ if ((((i3 | 0) > -1 ? i3 : 0 - i3 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i6 >> 2] = (i3 << 14) + 2147467264 | i5 & 16383;
+ STACKTOP = i2;
+ return;
+}
+function _tinsert(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i7 = i2;
+ _luaL_checktype(i1, 1, 5);
+ i4 = _luaL_len(i1, 1) | 0;
+ i3 = i4 + 1 | 0;
+ i6 = _lua_gettop(i1) | 0;
+ if ((i6 | 0) == 3) {
+  i5 = 2;
+ } else if ((i6 | 0) != 2) {
+  i7 = _luaL_error(i1, 8320, i7) | 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ if ((i5 | 0) == 2) {
+  i5 = _luaL_checkinteger(i1, 2) | 0;
+  if ((i5 | 0) < 1 | (i5 | 0) > (i3 | 0)) {
+   _luaL_argerror(i1, 2, 8256) | 0;
+  }
+  if ((i4 | 0) < (i5 | 0)) {
+   i3 = i5;
+  } else {
+   while (1) {
+    i4 = i3 + -1 | 0;
+    _lua_rawgeti(i1, 1, i4);
+    _lua_rawseti(i1, 1, i3);
+    if ((i4 | 0) > (i5 | 0)) {
+     i3 = i4;
+    } else {
+     i3 = i5;
+     break;
+    }
+   }
+  }
+ }
+ _lua_rawseti(i1, 1, i3);
+ i7 = 0;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _lua_iscfunction(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP32[i3 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i2 = (HEAP32[i3 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i2 = (HEAP32[i3 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i3 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i2 = HEAP32[i4 >> 2] | 0, (i3 | 0) <= (HEAPU8[i2 + 6 | 0] | 0 | 0)) : 0) {
+    i2 = i2 + (i3 + -1 << 4) + 16 | 0;
+   } else {
+    i2 = 5192;
+   }
+  } else {
+   i2 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i2 = i2 >>> 0 < (HEAP32[i3 + 8 >> 2] | 0) >>> 0 ? i2 : 5192;
+  }
+ } while (0);
+ i5 = HEAP32[i2 + 8 >> 2] | 0;
+ STACKTOP = i1;
+ return ((i5 | 0) == 22 | (i5 | 0) == 102) & 1 | 0;
+}
+function _lua_gettable(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 16 >> 2] | 0;
+ do {
+  if ((i5 | 0) <= 0) {
+   if (!((i5 | 0) < -1000999)) {
+    i3 = (HEAP32[i1 + 8 >> 2] | 0) + (i5 << 4) | 0;
+    break;
+   }
+   if ((i5 | 0) == -1001e3) {
+    i3 = (HEAP32[i1 + 12 >> 2] | 0) + 40 | 0;
+    break;
+   }
+   i5 = -1001e3 - i5 | 0;
+   i4 = HEAP32[i4 >> 2] | 0;
+   if ((HEAP32[i4 + 8 >> 2] | 0) != 22 ? (i3 = HEAP32[i4 >> 2] | 0, (i5 | 0) <= (HEAPU8[i3 + 6 | 0] | 0 | 0)) : 0) {
+    i3 = i3 + (i5 + -1 << 4) + 16 | 0;
+   } else {
+    i3 = 5192;
+   }
+  } else {
+   i3 = (HEAP32[i4 >> 2] | 0) + (i5 << 4) | 0;
+   i3 = i3 >>> 0 < (HEAP32[i1 + 8 >> 2] | 0) >>> 0 ? i3 : 5192;
+  }
+ } while (0);
+ i5 = (HEAP32[i1 + 8 >> 2] | 0) + -16 | 0;
+ _luaV_gettable(i1, i3, i5, i5);
+ STACKTOP = i2;
+ return;
+}
+function _luaG_errormsg(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = HEAP32[i1 + 68 >> 2] | 0;
+ if ((i2 | 0) == 0) {
+  _luaD_throw(i1, 2);
+ }
+ i4 = HEAP32[i1 + 28 >> 2] | 0;
+ i3 = i4 + (i2 + 8) | 0;
+ if ((HEAP32[i3 >> 2] & 15 | 0) != 6) {
+  _luaD_throw(i1, 6);
+ }
+ i5 = i1 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i9 = i6 + -16 | 0;
+ i8 = HEAP32[i9 + 4 >> 2] | 0;
+ i7 = i6;
+ HEAP32[i7 >> 2] = HEAP32[i9 >> 2];
+ HEAP32[i7 + 4 >> 2] = i8;
+ HEAP32[i6 + 8 >> 2] = HEAP32[i6 + -8 >> 2];
+ i6 = HEAP32[i5 >> 2] | 0;
+ i7 = i4 + i2 | 0;
+ i2 = HEAP32[i7 + 4 >> 2] | 0;
+ i4 = i6 + -16 | 0;
+ HEAP32[i4 >> 2] = HEAP32[i7 >> 2];
+ HEAP32[i4 + 4 >> 2] = i2;
+ HEAP32[i6 + -8 >> 2] = HEAP32[i3 >> 2];
+ i4 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i4 + 16;
+ _luaD_call(i1, i4 + -16 | 0, 1, 0);
+ _luaD_throw(i1, 2);
+}
+function _luaB_costatus(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i3 = i4;
+ i2 = _lua_tothread(i1, 1) | 0;
+ if ((i2 | 0) == 0) {
+  _luaL_argerror(i1, 1, 10856) | 0;
+ }
+ do {
+  if ((i2 | 0) != (i1 | 0)) {
+   i5 = _lua_status(i2) | 0;
+   if ((i5 | 0) == 0) {
+    if ((_lua_getstack(i2, 0, i3) | 0) > 0) {
+     _lua_pushlstring(i1, 10896, 6) | 0;
+     break;
+    }
+    if ((_lua_gettop(i2) | 0) == 0) {
+     _lua_pushlstring(i1, 10904, 4) | 0;
+     break;
+    } else {
+     _lua_pushlstring(i1, 10880, 9) | 0;
+     break;
+    }
+   } else if ((i5 | 0) == 1) {
+    _lua_pushlstring(i1, 10880, 9) | 0;
+    break;
+   } else {
+    _lua_pushlstring(i1, 10904, 4) | 0;
+    break;
+   }
+  } else {
+   _lua_pushlstring(i1, 10728, 7) | 0;
+  }
+ } while (0);
+ STACKTOP = i4;
+ return 1;
+}
+function _searcher_Lua(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _luaL_checklstring(i1, 1, 0) | 0;
+ _lua_getfield(i1, -1001001, 4256);
+ i5 = _lua_tolstring(i1, -1, 0) | 0;
+ if ((i5 | 0) == 0) {
+  HEAP32[i3 >> 2] = 4256;
+  _luaL_error(i1, 5032, i3) | 0;
+ }
+ i4 = _searchpath(i1, i4, i5, 4936, 4848) | 0;
+ if ((i4 | 0) == 0) {
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ if ((_luaL_loadfilex(i1, i4, 0) | 0) == 0) {
+  _lua_pushstring(i1, i4) | 0;
+  i5 = 2;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i6 = _lua_tolstring(i1, 1, 0) | 0;
+  i5 = _lua_tolstring(i1, -1, 0) | 0;
+  HEAP32[i3 >> 2] = i6;
+  HEAP32[i3 + 4 >> 2] = i4;
+  HEAP32[i3 + 8 >> 2] = i5;
+  i5 = _luaL_error(i1, 4888, i3) | 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _str_sub(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i2 = _luaL_checklstring(i1, 1, i4) | 0;
+ i5 = _luaL_checkinteger(i1, 2) | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if (!((i5 | 0) > -1)) {
+  if (i6 >>> 0 < (0 - i5 | 0) >>> 0) {
+   i5 = 0;
+  } else {
+   i5 = i5 + 1 + i6 | 0;
+  }
+ }
+ i6 = _luaL_optinteger(i1, 3, -1) | 0;
+ i4 = HEAP32[i4 >> 2] | 0;
+ if (!((i6 | 0) > -1)) {
+  if (i4 >>> 0 < (0 - i6 | 0) >>> 0) {
+   i6 = 0;
+  } else {
+   i6 = i6 + 1 + i4 | 0;
+  }
+ }
+ i5 = (i5 | 0) == 0 ? 1 : i5;
+ i4 = i6 >>> 0 > i4 >>> 0 ? i4 : i6;
+ if (i5 >>> 0 > i4 >>> 0) {
+  _lua_pushlstring(i1, 7040, 0) | 0;
+  STACKTOP = i3;
+  return 1;
+ } else {
+  _lua_pushlstring(i1, i2 + (i5 + -1) | 0, 1 - i5 + i4 | 0) | 0;
+  STACKTOP = i3;
+  return 1;
+ }
+ return 0;
+}
+function _searcher_C(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _luaL_checklstring(i1, 1, 0) | 0;
+ _lua_getfield(i1, -1001001, 4440);
+ i5 = _lua_tolstring(i1, -1, 0) | 0;
+ if ((i5 | 0) == 0) {
+  HEAP32[i3 >> 2] = 4440;
+  _luaL_error(i1, 5032, i3) | 0;
+ }
+ i5 = _searchpath(i1, i4, i5, 4936, 4848) | 0;
+ if ((i5 | 0) == 0) {
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ if ((_loadfunc(i1, i5, i4) | 0) == 0) {
+  _lua_pushstring(i1, i5) | 0;
+  i5 = 2;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i6 = _lua_tolstring(i1, 1, 0) | 0;
+  i4 = _lua_tolstring(i1, -1, 0) | 0;
+  HEAP32[i3 >> 2] = i6;
+  HEAP32[i3 + 4 >> 2] = i5;
+  HEAP32[i3 + 8 >> 2] = i4;
+  i5 = _luaL_error(i1, 4888, i3) | 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _io_open(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i5 = STACKTOP;
+ i2 = _luaL_checklstring(i1, 1, 0) | 0;
+ i3 = _luaL_optlstring(i1, 2, 3480, 0) | 0;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i6 = i4 + 4 | 0;
+ HEAP32[i6 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = 0;
+ HEAP32[i6 >> 2] = 156;
+ i6 = HEAP8[i3] | 0;
+ if (!((!(i6 << 24 >> 24 == 0) ? (i7 = i3 + 1 | 0, (_memchr(3552, i6 << 24 >> 24, 4) | 0) != 0) : 0) ? (i6 = (HEAP8[i7] | 0) == 43 ? i3 + 2 | 0 : i7, (HEAP8[(HEAP8[i6] | 0) == 98 ? i6 + 1 | 0 : i6] | 0) == 0) : 0)) {
+  _luaL_argerror(i1, 2, 3560) | 0;
+ }
+ i7 = _fopen(i2 | 0, i3 | 0) | 0;
+ HEAP32[i4 >> 2] = i7;
+ if ((i7 | 0) != 0) {
+  i7 = 1;
+  STACKTOP = i5;
+  return i7 | 0;
+ }
+ i7 = _luaL_fileresult(i1, 0, i2) | 0;
+ STACKTOP = i5;
+ return i7 | 0;
+}
+function _unpack(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i6 = i1;
+ _luaL_checktype(i2, 1, 5);
+ i5 = _luaL_optinteger(i2, 2, 1) | 0;
+ if ((_lua_type(i2, 3) | 0) < 1) {
+  i3 = _luaL_len(i2, 1) | 0;
+ } else {
+  i3 = _luaL_checkinteger(i2, 3) | 0;
+ }
+ if ((i5 | 0) > (i3 | 0)) {
+  i6 = 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ i7 = i3 - i5 | 0;
+ i4 = i7 + 1 | 0;
+ if ((i7 | 0) >= 0 ? (_lua_checkstack(i2, i4) | 0) != 0 : 0) {
+  _lua_rawgeti(i2, 1, i5);
+  if ((i5 | 0) >= (i3 | 0)) {
+   i7 = i4;
+   STACKTOP = i1;
+   return i7 | 0;
+  }
+  do {
+   i5 = i5 + 1 | 0;
+   _lua_rawgeti(i2, 1, i5);
+  } while ((i5 | 0) != (i3 | 0));
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i7 = _luaL_error(i2, 8280, i6) | 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _luaF_getlocalname(i4, i6, i2) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i4 + 60 >> 2] | 0;
+ if ((i3 | 0) <= 0) {
+  i6 = 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ i4 = HEAP32[i4 + 24 >> 2] | 0;
+ i5 = 0;
+ while (1) {
+  if ((HEAP32[i4 + (i5 * 12 | 0) + 4 >> 2] | 0) > (i2 | 0)) {
+   i3 = 0;
+   i2 = 8;
+   break;
+  }
+  if ((HEAP32[i4 + (i5 * 12 | 0) + 8 >> 2] | 0) > (i2 | 0)) {
+   i6 = i6 + -1 | 0;
+   if ((i6 | 0) == 0) {
+    i2 = 6;
+    break;
+   }
+  }
+  i5 = i5 + 1 | 0;
+  if ((i5 | 0) >= (i3 | 0)) {
+   i3 = 0;
+   i2 = 8;
+   break;
+  }
+ }
+ if ((i2 | 0) == 6) {
+  i6 = (HEAP32[i4 + (i5 * 12 | 0) >> 2] | 0) + 16 | 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ } else if ((i2 | 0) == 8) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _luaK_concat(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == -1) {
+  STACKTOP = i2;
+  return;
+ }
+ i7 = HEAP32[i4 >> 2] | 0;
+ if ((i7 | 0) == -1) {
+  HEAP32[i4 >> 2] = i3;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0;
+ while (1) {
+  i6 = i4 + (i7 << 2) | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i8 = (i5 >>> 14) + -131071 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  }
+  i8 = i7 + 1 + i8 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  } else {
+   i7 = i8;
+  }
+ }
+ i3 = ~i7 + i3 | 0;
+ if ((((i3 | 0) > -1 ? i3 : 0 - i3 | 0) | 0) > 131071) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10624);
+ }
+ HEAP32[i6 >> 2] = i5 & 16383 | (i3 << 14) + 2147467264;
+ STACKTOP = i2;
+ return;
+}
+function _scalbn(d3, i2) {
+ d3 = +d3;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0;
+ i1 = STACKTOP;
+ if ((i2 | 0) > 1023) {
+  d3 = d3 * 8.98846567431158e+307;
+  i4 = i2 + -1023 | 0;
+  if ((i4 | 0) > 1023) {
+   i2 = i2 + -2046 | 0;
+   i2 = (i2 | 0) > 1023 ? 1023 : i2;
+   d3 = d3 * 8.98846567431158e+307;
+  } else {
+   i2 = i4;
+  }
+ } else {
+  if ((i2 | 0) < -1022) {
+   d3 = d3 * 2.2250738585072014e-308;
+   i4 = i2 + 1022 | 0;
+   if ((i4 | 0) < -1022) {
+    i2 = i2 + 2044 | 0;
+    i2 = (i2 | 0) < -1022 ? -1022 : i2;
+    d3 = d3 * 2.2250738585072014e-308;
+   } else {
+    i2 = i4;
+   }
+  }
+ }
+ i2 = _bitshift64Shl(i2 + 1023 | 0, 0, 52) | 0;
+ i4 = tempRet0;
+ HEAP32[tempDoublePtr >> 2] = i2;
+ HEAP32[tempDoublePtr + 4 >> 2] = i4;
+ d3 = d3 * +HEAPF64[tempDoublePtr >> 3];
+ STACKTOP = i1;
+ return +d3;
+}
+function _luaK_numberK(i1, d6) {
+ i1 = i1 | 0;
+ d6 = +d6;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i4 = i2 + 16 | 0;
+ i3 = i2;
+ HEAPF64[i4 >> 3] = d6;
+ i5 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 52 >> 2] | 0;
+ HEAPF64[i3 >> 3] = d6;
+ HEAP32[i3 + 8 >> 2] = 3;
+ if (d6 != d6 | 0.0 != 0.0 | d6 == 0.0) {
+  i7 = i5 + 8 | 0;
+  i8 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i8 + 16;
+  i5 = _luaS_newlstr(i5, i4, 8) | 0;
+  HEAP32[i8 >> 2] = i5;
+  HEAP32[i8 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 0 | 64;
+  i5 = _addk(i1, (HEAP32[i7 >> 2] | 0) + -16 | 0, i3) | 0;
+  HEAP32[i7 >> 2] = (HEAP32[i7 >> 2] | 0) + -16;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i8 = _addk(i1, i3, i3) | 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ return 0;
+}
+function _auxresume(i2, i3, i4) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ do {
+  if ((_lua_checkstack(i3, i4) | 0) != 0) {
+   if ((_lua_status(i3) | 0) == 0 ? (_lua_gettop(i3) | 0) == 0 : 0) {
+    _lua_pushlstring(i2, 10792, 28) | 0;
+    i4 = -1;
+    break;
+   }
+   _lua_xmove(i2, i3, i4);
+   if (!((_lua_resume(i3, i2, i4) | 0) >>> 0 < 2)) {
+    _lua_xmove(i3, i2, 1);
+    i4 = -1;
+    break;
+   }
+   i4 = _lua_gettop(i3) | 0;
+   if ((_lua_checkstack(i2, i4 + 1 | 0) | 0) == 0) {
+    _lua_settop(i3, ~i4);
+    _lua_pushlstring(i2, 10824, 26) | 0;
+    i4 = -1;
+    break;
+   } else {
+    _lua_xmove(i3, i2, i4);
+    break;
+   }
+  } else {
+   _lua_pushlstring(i2, 10760, 28) | 0;
+   i4 = -1;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _luaX_setinput(i2, i1, i4, i3, i5) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i6 = 0, i7 = 0;
+ i6 = STACKTOP;
+ HEAP8[i1 + 76 | 0] = 46;
+ i7 = i1 + 52 | 0;
+ HEAP32[i7 >> 2] = i2;
+ HEAP32[i1 >> 2] = i5;
+ HEAP32[i1 + 32 >> 2] = 286;
+ HEAP32[i1 + 56 >> 2] = i4;
+ HEAP32[i1 + 48 >> 2] = 0;
+ HEAP32[i1 + 4 >> 2] = 1;
+ HEAP32[i1 + 8 >> 2] = 1;
+ HEAP32[i1 + 68 >> 2] = i3;
+ i5 = _luaS_new(i2, 12264) | 0;
+ HEAP32[i1 + 72 >> 2] = i5;
+ i5 = i5 + 5 | 0;
+ HEAP8[i5] = HEAPU8[i5] | 0 | 32;
+ i5 = i1 + 60 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ i4 = _luaM_realloc_(HEAP32[i7 >> 2] | 0, HEAP32[i4 >> 2] | 0, HEAP32[i4 + 8 >> 2] | 0, 32) | 0;
+ HEAP32[HEAP32[i5 >> 2] >> 2] = i4;
+ HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] = 32;
+ STACKTOP = i6;
+ return;
+}
+function _luaL_optlstring(i2, i4, i6, i5) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((_lua_type(i2, i4) | 0) >= 1) {
+  i5 = _lua_tolstring(i2, i4, i5) | 0;
+  if ((i5 | 0) != 0) {
+   i6 = i5;
+   STACKTOP = i1;
+   return i6 | 0;
+  }
+  i5 = _lua_typename(i2, 4) | 0;
+  i6 = _lua_typename(i2, _lua_type(i2, i4) | 0) | 0;
+  HEAP32[i3 >> 2] = i5;
+  HEAP32[i3 + 4 >> 2] = i6;
+  _luaL_argerror(i2, i4, _lua_pushfstring(i2, 1744, i3) | 0) | 0;
+  i6 = 0;
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ if ((i5 | 0) == 0) {
+  STACKTOP = i1;
+  return i6 | 0;
+ }
+ if ((i6 | 0) == 0) {
+  i2 = 0;
+ } else {
+  i2 = _strlen(i6 | 0) | 0;
+ }
+ HEAP32[i5 >> 2] = i2;
+ STACKTOP = i1;
+ return i6 | 0;
+}
+function _lua_xmove(i3, i4, i1) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == (i4 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i3 + 8 | 0;
+ i5 = (HEAP32[i3 >> 2] | 0) + (0 - i1 << 4) | 0;
+ HEAP32[i3 >> 2] = i5;
+ if ((i1 | 0) <= 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i4 + 8 | 0;
+ i6 = 0;
+ while (1) {
+  i7 = HEAP32[i4 >> 2] | 0;
+  HEAP32[i4 >> 2] = i7 + 16;
+  i10 = i5 + (i6 << 4) | 0;
+  i9 = HEAP32[i10 + 4 >> 2] | 0;
+  i8 = i7;
+  HEAP32[i8 >> 2] = HEAP32[i10 >> 2];
+  HEAP32[i8 + 4 >> 2] = i9;
+  HEAP32[i7 + 8 >> 2] = HEAP32[i5 + (i6 << 4) + 8 >> 2];
+  i6 = i6 + 1 | 0;
+  if ((i6 | 0) == (i1 | 0)) {
+   break;
+  }
+  i5 = HEAP32[i3 >> 2] | 0;
+ }
+ STACKTOP = i2;
+ return;
+}
+function _luaM_realloc_(i7, i10, i3, i2) {
+ i7 = i7 | 0;
+ i10 = i10 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0;
+ i5 = STACKTOP;
+ i6 = HEAP32[i7 + 12 >> 2] | 0;
+ i4 = (i10 | 0) != 0;
+ i9 = i6 + 4 | 0;
+ i8 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i9 >> 2] | 0, i10, i3, i2) | 0;
+ if (!((i8 | 0) != 0 | (i2 | 0) == 0)) {
+  if ((HEAP8[i6 + 63 | 0] | 0) == 0) {
+   _luaD_throw(i7, 4);
+  }
+  _luaC_fullgc(i7, 1);
+  i8 = FUNCTION_TABLE_iiiii[HEAP32[i6 >> 2] & 3](HEAP32[i9 >> 2] | 0, i10, i3, i2) | 0;
+  if ((i8 | 0) == 0) {
+   _luaD_throw(i7, 4);
+  } else {
+   i1 = i8;
+  }
+ } else {
+  i1 = i8;
+ }
+ i6 = i6 + 12 | 0;
+ HEAP32[i6 >> 2] = (i4 ? 0 - i3 | 0 : 0) + i2 + (HEAP32[i6 >> 2] | 0);
+ STACKTOP = i5;
+ return i1 | 0;
+}
+function _realloc(i2, i3) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0;
+ i1 = STACKTOP;
+ do {
+  if ((i2 | 0) != 0) {
+   if (i3 >>> 0 > 4294967231) {
+    HEAP32[(___errno_location() | 0) >> 2] = 12;
+    i4 = 0;
+    break;
+   }
+   if (i3 >>> 0 < 11) {
+    i4 = 16;
+   } else {
+    i4 = i3 + 11 & -8;
+   }
+   i4 = _try_realloc_chunk(i2 + -8 | 0, i4) | 0;
+   if ((i4 | 0) != 0) {
+    i4 = i4 + 8 | 0;
+    break;
+   }
+   i4 = _malloc(i3) | 0;
+   if ((i4 | 0) == 0) {
+    i4 = 0;
+   } else {
+    i5 = HEAP32[i2 + -4 >> 2] | 0;
+    i5 = (i5 & -8) - ((i5 & 3 | 0) == 0 ? 8 : 4) | 0;
+    _memcpy(i4 | 0, i2 | 0, (i5 >>> 0 < i3 >>> 0 ? i5 : i3) | 0) | 0;
+    _free(i2);
+   }
+  } else {
+   i4 = _malloc(i3) | 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _lua_setlocal(i3, i5, i4) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ HEAP32[i2 >> 2] = 0;
+ i4 = _findlocal(i3, HEAP32[i5 + 96 >> 2] | 0, i4, i2) | 0;
+ i3 = i3 + 8 | 0;
+ if ((i4 | 0) == 0) {
+  i5 = HEAP32[i3 >> 2] | 0;
+  i5 = i5 + -16 | 0;
+  HEAP32[i3 >> 2] = i5;
+  STACKTOP = i1;
+  return i4 | 0;
+ }
+ i6 = HEAP32[i3 >> 2] | 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ i8 = i6 + -16 | 0;
+ i7 = HEAP32[i8 + 4 >> 2] | 0;
+ i2 = i5;
+ HEAP32[i2 >> 2] = HEAP32[i8 >> 2];
+ HEAP32[i2 + 4 >> 2] = i7;
+ HEAP32[i5 + 8 >> 2] = HEAP32[i6 + -8 >> 2];
+ i5 = HEAP32[i3 >> 2] | 0;
+ i5 = i5 + -16 | 0;
+ HEAP32[i3 >> 2] = i5;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function ___remdi3(i1, i4, i5, i6) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 8 | 0;
+ i2 = i3 | 0;
+ i7 = i4 >> 31 | ((i4 | 0) < 0 ? -1 : 0) << 1;
+ i8 = ((i4 | 0) < 0 ? -1 : 0) >> 31 | ((i4 | 0) < 0 ? -1 : 0) << 1;
+ i9 = i6 >> 31 | ((i6 | 0) < 0 ? -1 : 0) << 1;
+ i10 = ((i6 | 0) < 0 ? -1 : 0) >> 31 | ((i6 | 0) < 0 ? -1 : 0) << 1;
+ i1 = _i64Subtract(i7 ^ i1, i8 ^ i4, i7, i8) | 0;
+ i4 = tempRet0;
+ ___udivmoddi4(i1, i4, _i64Subtract(i9 ^ i5, i10 ^ i6, i9, i10) | 0, tempRet0, i2) | 0;
+ i9 = _i64Subtract(HEAP32[i2 >> 2] ^ i7, HEAP32[i2 + 4 >> 2] ^ i8, i7, i8) | 0;
+ i8 = tempRet0;
+ STACKTOP = i3;
+ return (tempRet0 = i8, i9) | 0;
+}
+function _luaC_barrierproto_(i3, i4, i2) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i5 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i4 + 32 >> 2] | 0) != 0) {
+  i5 = HEAP32[i3 + 12 >> 2] | 0;
+  i3 = i4 + 5 | 0;
+  HEAP8[i3] = HEAP8[i3] & 251;
+  i5 = i5 + 88 | 0;
+  HEAP32[i4 + 72 >> 2] = HEAP32[i5 >> 2];
+  HEAP32[i5 >> 2] = i4;
+  STACKTOP = i1;
+  return;
+ }
+ if ((HEAP8[i2 + 5 | 0] & 3) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i5 = i4 + 5 | 0;
+ i4 = HEAP8[i5] | 0;
+ if ((i4 & 4) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = HEAP32[i3 + 12 >> 2] | 0;
+ if ((HEAPU8[i3 + 61 | 0] | 0) < 2) {
+  _reallymarkobject(i3, i2);
+  STACKTOP = i1;
+  return;
+ } else {
+  HEAP8[i5] = HEAP8[i3 + 60 | 0] & 3 | i4 & 184;
+  STACKTOP = i1;
+  return;
+ }
+}
+function _luaL_openlibs(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_requiref(i1, 2592, 144, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2600, 145, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2608, 146, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2624, 147, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2632, 148, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2640, 149, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2648, 150, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2656, 151, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2664, 152, 1);
+ _lua_settop(i1, -2);
+ _luaL_requiref(i1, 2672, 153, 1);
+ _lua_settop(i1, -2);
+ _luaL_getsubtable(i1, -1001e3, 2576) | 0;
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return;
+}
+function _luaX_token2str(i4, i3) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i5 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ if ((i3 | 0) >= 257) {
+  i5 = HEAP32[12096 + (i3 + -257 << 2) >> 2] | 0;
+  if ((i3 | 0) >= 286) {
+   STACKTOP = i1;
+   return i5 | 0;
+  }
+  i4 = HEAP32[i4 + 52 >> 2] | 0;
+  HEAP32[i2 >> 2] = i5;
+  i5 = _luaO_pushfstring(i4, 12256, i2) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i4 = HEAP32[i4 + 52 >> 2] | 0;
+ if ((HEAP8[i3 + 10913 | 0] & 4) == 0) {
+  HEAP32[i2 >> 2] = i3;
+  i5 = _luaO_pushfstring(i4, 12240, i2) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ } else {
+  HEAP32[i2 >> 2] = i3;
+  i5 = _luaO_pushfstring(i4, 12232, i2) | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _luaL_buffinitsize(i6, i1, i7) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 12 >> 2] = i6;
+ i3 = i1 + 16 | 0;
+ HEAP32[i1 >> 2] = i3;
+ i5 = i1 + 8 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i4 = i1 + 4 | 0;
+ HEAP32[i4 >> 2] = 1024;
+ if (!(i7 >>> 0 > 1024)) {
+  i7 = i3;
+  i8 = 0;
+  i8 = i7 + i8 | 0;
+  STACKTOP = i2;
+  return i8 | 0;
+ }
+ i8 = i7 >>> 0 > 2048 ? i7 : 2048;
+ i7 = _lua_newuserdata(i6, i8) | 0;
+ _memcpy(i7 | 0, HEAP32[i1 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+ if ((HEAP32[i1 >> 2] | 0) != (i3 | 0)) {
+  _lua_remove(i6, -2);
+ }
+ HEAP32[i1 >> 2] = i7;
+ HEAP32[i4 >> 2] = i8;
+ i8 = HEAP32[i5 >> 2] | 0;
+ i8 = i7 + i8 | 0;
+ STACKTOP = i2;
+ return i8 | 0;
+}
+function _luaE_freethread(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ i4 = i3 + 28 | 0;
+ _luaF_close(i3, HEAP32[i4 >> 2] | 0);
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) == 0) {
+  _luaM_realloc_(i1, i3, 112, 0) | 0;
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i3 + 16 >> 2] = i3 + 72;
+ i7 = i3 + 84 | 0;
+ i6 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = 0;
+ if ((i6 | 0) != 0) {
+  while (1) {
+   i5 = HEAP32[i6 + 12 >> 2] | 0;
+   _luaM_realloc_(i3, i6, 40, 0) | 0;
+   if ((i5 | 0) == 0) {
+    break;
+   } else {
+    i6 = i5;
+   }
+  }
+  i5 = HEAP32[i4 >> 2] | 0;
+ }
+ _luaM_realloc_(i3, i5, HEAP32[i3 + 32 >> 2] << 4, 0) | 0;
+ _luaM_realloc_(i1, i3, 112, 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function ___toread(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ i4 = i1 + 74 | 0;
+ i2 = HEAP8[i4] | 0;
+ HEAP8[i4] = i2 + 255 | i2;
+ i4 = i1 + 20 | 0;
+ i2 = i1 + 44 | 0;
+ if ((HEAP32[i4 >> 2] | 0) >>> 0 > (HEAP32[i2 >> 2] | 0) >>> 0) {
+  FUNCTION_TABLE_iiii[HEAP32[i1 + 36 >> 2] & 3](i1, 0, 0) | 0;
+ }
+ HEAP32[i1 + 16 >> 2] = 0;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i4 >> 2] = 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ if ((i4 & 20 | 0) == 0) {
+  i4 = HEAP32[i2 >> 2] | 0;
+  HEAP32[i1 + 8 >> 2] = i4;
+  HEAP32[i1 + 4 >> 2] = i4;
+  i4 = 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ if ((i4 & 4 | 0) == 0) {
+  i4 = -1;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ HEAP32[i1 >> 2] = i4 | 32;
+ i4 = -1;
+ STACKTOP = i3;
+ return i4 | 0;
+}
+function _lua_callk(i3, i7, i4, i6, i5) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i8 = 0;
+ i1 = STACKTOP;
+ i2 = i3 + 8 | 0;
+ i7 = (HEAP32[i2 >> 2] | 0) + (~i7 << 4) | 0;
+ if ((i5 | 0) != 0 ? (HEAP16[i3 + 36 >> 1] | 0) == 0 : 0) {
+  i8 = i3 + 16 | 0;
+  HEAP32[(HEAP32[i8 >> 2] | 0) + 28 >> 2] = i5;
+  HEAP32[(HEAP32[i8 >> 2] | 0) + 24 >> 2] = i6;
+  _luaD_call(i3, i7, i4, 1);
+ } else {
+  _luaD_call(i3, i7, i4, 0);
+ }
+ if (!((i4 | 0) == -1)) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = (HEAP32[i3 + 16 >> 2] | 0) + 4 | 0;
+ i2 = HEAP32[i2 >> 2] | 0;
+ if (!((HEAP32[i3 >> 2] | 0) >>> 0 < i2 >>> 0)) {
+  STACKTOP = i1;
+  return;
+ }
+ HEAP32[i3 >> 2] = i2;
+ STACKTOP = i1;
+ return;
+}
+function _luaX_newstring(i3, i5, i4) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i6 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i3 + 52 >> 2] | 0;
+ i5 = _luaS_newlstr(i2, i5, i4) | 0;
+ i4 = i2 + 8 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = i6 + 16;
+ HEAP32[i6 >> 2] = i5;
+ HEAP32[i6 + 8 >> 2] = HEAPU8[i5 + 4 | 0] | 0 | 64;
+ i6 = _luaH_set(i2, HEAP32[(HEAP32[i3 + 48 >> 2] | 0) + 4 >> 2] | 0, (HEAP32[i4 >> 2] | 0) + -16 | 0) | 0;
+ i3 = i6 + 8 | 0;
+ if ((HEAP32[i3 >> 2] | 0) == 0 ? (HEAP32[i6 >> 2] = 1, HEAP32[i3 >> 2] = 1, (HEAP32[(HEAP32[i2 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) : 0) {
+  _luaC_step(i2);
+ }
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -16;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _strtod(i3, i2) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0, d5 = 0.0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i1;
+ i7 = i4 + 0 | 0;
+ i6 = i7 + 112 | 0;
+ do {
+  HEAP32[i7 >> 2] = 0;
+  i7 = i7 + 4 | 0;
+ } while ((i7 | 0) < (i6 | 0));
+ i6 = i4 + 4 | 0;
+ HEAP32[i6 >> 2] = i3;
+ i7 = i4 + 8 | 0;
+ HEAP32[i7 >> 2] = -1;
+ HEAP32[i4 + 44 >> 2] = i3;
+ HEAP32[i4 + 76 >> 2] = -1;
+ ___shlim(i4, 0);
+ d5 = +___floatscan(i4, 1, 1);
+ i4 = (HEAP32[i6 >> 2] | 0) - (HEAP32[i7 >> 2] | 0) + (HEAP32[i4 + 108 >> 2] | 0) | 0;
+ if ((i2 | 0) == 0) {
+  STACKTOP = i1;
+  return +d5;
+ }
+ if ((i4 | 0) != 0) {
+  i3 = i3 + i4 | 0;
+ }
+ HEAP32[i2 >> 2] = i3;
+ STACKTOP = i1;
+ return +d5;
+}
+function _f_seek(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = 0.0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i3 = HEAP32[i3 >> 2] | 0;
+ i5 = _luaL_checkoption(i1, 2, 3208, 3184) | 0;
+ d6 = +_luaL_optnumber(i1, 3, 0.0);
+ i4 = ~~d6;
+ if (!(+(i4 | 0) == d6)) {
+  _luaL_argerror(i1, 3, 3224) | 0;
+ }
+ if ((_fseek(i3 | 0, i4 | 0, HEAP32[3168 + (i5 << 2) >> 2] | 0) | 0) == 0) {
+  _lua_pushnumber(i1, +(_ftell(i3 | 0) | 0));
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ } else {
+  i5 = _luaL_fileresult(i1, 0, 0) | 0;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _setpath(i1, i4, i8, i7, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i8 = _getenv(i8 | 0) | 0;
+ if ((i8 | 0) == 0) {
+  i7 = _getenv(i7 | 0) | 0;
+  if ((i7 | 0) != 0) {
+   i5 = i7;
+   i6 = 3;
+  }
+ } else {
+  i5 = i8;
+  i6 = 3;
+ }
+ if ((i6 | 0) == 3 ? (_lua_getfield(i1, -1001e3, 4832), i8 = _lua_toboolean(i1, -1) | 0, _lua_settop(i1, -2), (i8 | 0) == 0) : 0) {
+  _luaL_gsub(i1, _luaL_gsub(i1, i5, 4808, 4816) | 0, 4824, i3) | 0;
+  _lua_remove(i1, -2);
+  _lua_setfield(i1, -2, i4);
+  STACKTOP = i2;
+  return;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_setfield(i1, -2, i4);
+ STACKTOP = i2;
+ return;
+}
+function _luaU_header(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ HEAP8[i1] = 1635077147;
+ HEAP8[i1 + 1 | 0] = 6387020;
+ HEAP8[i1 + 2 | 0] = 24949;
+ HEAP8[i1 + 3 | 0] = 97;
+ HEAP8[i1 + 4 | 0] = 82;
+ HEAP8[i1 + 5 | 0] = 0;
+ HEAP8[i1 + 6 | 0] = 1;
+ HEAP8[i1 + 7 | 0] = 4;
+ HEAP8[i1 + 8 | 0] = 4;
+ HEAP8[i1 + 9 | 0] = 4;
+ HEAP8[i1 + 10 | 0] = 8;
+ i3 = i1 + 12 | 0;
+ HEAP8[i1 + 11 | 0] = 0;
+ HEAP8[i3 + 0 | 0] = HEAP8[8816 | 0] | 0;
+ HEAP8[i3 + 1 | 0] = HEAP8[8817 | 0] | 0;
+ HEAP8[i3 + 2 | 0] = HEAP8[8818 | 0] | 0;
+ HEAP8[i3 + 3 | 0] = HEAP8[8819 | 0] | 0;
+ HEAP8[i3 + 4 | 0] = HEAP8[8820 | 0] | 0;
+ HEAP8[i3 + 5 | 0] = HEAP8[8821 | 0] | 0;
+ STACKTOP = i2;
+ return;
+}
+function _db_setlocal(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i3 = i2;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i5 = _lua_tothread(i1, 1) | 0;
+  i4 = 1;
+ } else {
+  i5 = i1;
+  i4 = 0;
+ }
+ i6 = i4 + 1 | 0;
+ if ((_lua_getstack(i5, _luaL_checkinteger(i1, i6) | 0, i3) | 0) == 0) {
+  i6 = _luaL_argerror(i1, i6, 11560) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  i6 = i4 + 3 | 0;
+  _luaL_checkany(i1, i6);
+  _lua_settop(i1, i6);
+  _lua_xmove(i1, i5, 1);
+  _lua_pushstring(i1, _lua_setlocal(i5, i3, _luaL_checkinteger(i1, i4 | 2) | 0) | 0) | 0;
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ return 0;
+}
+function _tremove(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ i3 = _luaL_len(i1, 1) | 0;
+ i4 = _luaL_optinteger(i1, 2, i3) | 0;
+ if ((i4 | 0) != (i3 | 0) ? (i4 | 0) < 1 | (i4 | 0) > (i3 + 1 | 0) : 0) {
+  _luaL_argerror(i1, 1, 8256) | 0;
+ }
+ _lua_rawgeti(i1, 1, i4);
+ if ((i4 | 0) >= (i3 | 0)) {
+  i5 = i4;
+  _lua_pushnil(i1);
+  _lua_rawseti(i1, 1, i5);
+  STACKTOP = i2;
+  return 1;
+ }
+ while (1) {
+  i5 = i4 + 1 | 0;
+  _lua_rawgeti(i1, 1, i5);
+  _lua_rawseti(i1, 1, i4);
+  if ((i5 | 0) == (i3 | 0)) {
+   break;
+  } else {
+   i4 = i5;
+  }
+ }
+ _lua_pushnil(i1);
+ _lua_rawseti(i1, 1, i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaL_checkudata(i1, i7, i5) {
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = _lua_touserdata(i1, i7) | 0;
+ if (((i3 | 0) != 0 ? (_lua_getmetatable(i1, i7) | 0) != 0 : 0) ? (_lua_getfield(i1, -1001e3, i5), i6 = (_lua_rawequal(i1, -1, -2) | 0) == 0, i6 = i6 ? 0 : i3, _lua_settop(i1, -3), (i6 | 0) != 0) : 0) {
+  i7 = i6;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i6 = _lua_typename(i1, _lua_type(i1, i7) | 0) | 0;
+ HEAP32[i4 >> 2] = i5;
+ HEAP32[i4 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i7, _lua_pushfstring(i1, 1744, i4) | 0) | 0;
+ i7 = 0;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _luaL_error(i1, i5, i7) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 128 | 0;
+ i3 = i4;
+ i2 = i4 + 24 | 0;
+ i4 = i4 + 8 | 0;
+ HEAP32[i4 >> 2] = i7;
+ if ((_lua_getstack(i1, 1, i2) | 0) != 0 ? (_lua_getinfo(i1, 1152, i2) | 0, i6 = HEAP32[i2 + 20 >> 2] | 0, (i6 | 0) > 0) : 0) {
+  HEAP32[i3 >> 2] = i2 + 36;
+  HEAP32[i3 + 4 >> 2] = i6;
+  _lua_pushfstring(i1, 1160, i3) | 0;
+  _lua_pushvfstring(i1, i5, i4) | 0;
+  _lua_concat(i1, 2);
+  _lua_error(i1) | 0;
+ }
+ _lua_pushlstring(i1, 1168, 0) | 0;
+ _lua_pushvfstring(i1, i5, i4) | 0;
+ _lua_concat(i1, 2);
+ _lua_error(i1) | 0;
+ return 0;
+}
+function _luaK_infix(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ L1 : do {
+  switch (i4 | 0) {
+  case 6:
+   {
+    _luaK_exp2nextreg(i1, i3);
+    break;
+   }
+  case 5:
+  case 4:
+  case 3:
+  case 2:
+  case 1:
+  case 0:
+   {
+    if (((HEAP32[i3 >> 2] | 0) == 5 ? (HEAP32[i3 + 16 >> 2] | 0) == -1 : 0) ? (HEAP32[i3 + 20 >> 2] | 0) == -1 : 0) {
+     break L1;
+    }
+    _luaK_exp2RK(i1, i3) | 0;
+    break;
+   }
+  case 13:
+   {
+    _luaK_goiftrue(i1, i3);
+    break;
+   }
+  case 14:
+   {
+    _luaK_goiffalse(i1, i3);
+    break;
+   }
+  default:
+   {
+    _luaK_exp2RK(i1, i3) | 0;
+   }
+  }
+ } while (0);
+ STACKTOP = i2;
+ return;
+}
+function _luaD_shrinkstack(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i1 + 8 >> 2] | 0;
+ i3 = HEAP32[i1 + 16 >> 2] | 0;
+ if ((i3 | 0) != 0) {
+  do {
+   i5 = HEAP32[i3 + 4 >> 2] | 0;
+   i4 = i4 >>> 0 < i5 >>> 0 ? i5 : i4;
+   i3 = HEAP32[i3 + 8 >> 2] | 0;
+  } while ((i3 | 0) != 0);
+ }
+ i3 = i4 - (HEAP32[i1 + 28 >> 2] | 0) | 0;
+ i4 = (i3 >> 4) + 1 | 0;
+ i4 = ((i4 | 0) / 8 | 0) + 10 + i4 | 0;
+ i4 = (i4 | 0) > 1e6 ? 1e6 : i4;
+ if ((i3 | 0) > 15999984) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((i4 | 0) >= (HEAP32[i1 + 32 >> 2] | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaD_reallocstack(i1, i4);
+ STACKTOP = i2;
+ return;
+}
+function _luaF_newproto(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _luaC_newobj(i1, 9, 80, 0, 0) | 0;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP32[i1 + 44 >> 2] = 0;
+ HEAP32[i1 + 16 >> 2] = 0;
+ HEAP32[i1 + 56 >> 2] = 0;
+ HEAP32[i1 + 12 >> 2] = 0;
+ HEAP32[i1 + 32 >> 2] = 0;
+ HEAP32[i1 + 48 >> 2] = 0;
+ HEAP32[i1 + 20 >> 2] = 0;
+ HEAP32[i1 + 52 >> 2] = 0;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 40 >> 2] = 0;
+ HEAP8[i1 + 76 | 0] = 0;
+ HEAP8[i1 + 77 | 0] = 0;
+ HEAP8[i1 + 78 | 0] = 0;
+ HEAP32[i1 + 24 >> 2] = 0;
+ HEAP32[i1 + 60 >> 2] = 0;
+ HEAP32[i1 + 64 >> 2] = 0;
+ HEAP32[i1 + 68 >> 2] = 0;
+ HEAP32[i1 + 36 >> 2] = 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaF_freeproto(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _luaM_realloc_(i2, HEAP32[i1 + 12 >> 2] | 0, HEAP32[i1 + 48 >> 2] << 2, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 16 >> 2] | 0, HEAP32[i1 + 56 >> 2] << 2, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 8 >> 2] | 0, HEAP32[i1 + 44 >> 2] << 4, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 20 >> 2] | 0, HEAP32[i1 + 52 >> 2] << 2, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 24 >> 2] | 0, (HEAP32[i1 + 60 >> 2] | 0) * 12 | 0, 0) | 0;
+ _luaM_realloc_(i2, HEAP32[i1 + 28 >> 2] | 0, HEAP32[i1 + 40 >> 2] << 3, 0) | 0;
+ _luaM_realloc_(i2, i1, 80, 0) | 0;
+ STACKTOP = i3;
+ return;
+}
+function _luaK_patchclose(i3, i7, i4) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i5 = 0, i6 = 0, i8 = 0;
+ i2 = STACKTOP;
+ if ((i7 | 0) == -1) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = HEAP32[(HEAP32[i3 >> 2] | 0) + 12 >> 2] | 0;
+ i4 = (i4 << 6) + 64 & 16320;
+ while (1) {
+  i6 = i3 + (i7 << 2) | 0;
+  i5 = HEAP32[i6 >> 2] | 0;
+  i8 = (i5 >>> 14) + -131071 | 0;
+  if ((i8 | 0) == -1) {
+   break;
+  }
+  i7 = i7 + 1 + i8 | 0;
+  HEAP32[i6 >> 2] = i5 & -16321 | i4;
+  if ((i7 | 0) == -1) {
+   i1 = 6;
+   break;
+  }
+ }
+ if ((i1 | 0) == 6) {
+  STACKTOP = i2;
+  return;
+ }
+ HEAP32[i6 >> 2] = i5 & -16321 | i4;
+ STACKTOP = i2;
+ return;
+}
+function _loadfunc(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i6 = _luaL_gsub(i1, i5, 4936, 4944) | 0;
+ i5 = _strchr(i6, 45) | 0;
+ do {
+  if ((i5 | 0) != 0) {
+   HEAP32[i3 >> 2] = _lua_pushlstring(i1, i6, i5 - i6 | 0) | 0;
+   i6 = _ll_loadfunc(i1, i4, _lua_pushfstring(i1, 4952, i3) | 0) | 0;
+   if ((i6 | 0) == 2) {
+    i6 = i5 + 1 | 0;
+    break;
+   } else {
+    STACKTOP = i2;
+    return i6 | 0;
+   }
+  }
+ } while (0);
+ HEAP32[i3 >> 2] = i6;
+ i6 = _ll_loadfunc(i1, i4, _lua_pushfstring(i1, 4952, i3) | 0) | 0;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaK_setlist(i1, i3, i4, i5) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = ((i4 + -1 | 0) / 50 | 0) + 1 | 0;
+ i5 = (i5 | 0) == -1 ? 0 : i5;
+ if ((i4 | 0) < 512) {
+  _luaK_code(i1, i3 << 6 | i5 << 23 | i4 << 14 | 36) | 0;
+  i4 = i3 + 1 | 0;
+  i4 = i4 & 255;
+  i5 = i1 + 48 | 0;
+  HEAP8[i5] = i4;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i4 | 0) >= 67108864) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10576);
+ }
+ _luaK_code(i1, i3 << 6 | i5 << 23 | 36) | 0;
+ _luaK_code(i1, i4 << 6 | 39) | 0;
+ i4 = i3 + 1 | 0;
+ i4 = i4 & 255;
+ i5 = i1 + 48 | 0;
+ HEAP8[i5] = i4;
+ STACKTOP = i2;
+ return;
+}
+function _lua_getstack(i2, i6, i3) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0;
+ i1 = STACKTOP;
+ L1 : do {
+  if ((i6 | 0) >= 0) {
+   i5 = HEAP32[i2 + 16 >> 2] | 0;
+   if ((i6 | 0) > 0) {
+    i4 = i2 + 72 | 0;
+    do {
+     if ((i5 | 0) == (i4 | 0)) {
+      i2 = 0;
+      break L1;
+     }
+     i6 = i6 + -1 | 0;
+     i5 = HEAP32[i5 + 8 >> 2] | 0;
+    } while ((i6 | 0) > 0);
+    if ((i6 | 0) != 0) {
+     i2 = 0;
+     break;
+    }
+   }
+   if ((i5 | 0) != (i2 + 72 | 0)) {
+    HEAP32[i3 + 96 >> 2] = i5;
+    i2 = 1;
+   } else {
+    i2 = 0;
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaC_checkupvalcolor(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = i5 + 5 | 0;
+ i3 = HEAPU8[i4] | 0;
+ if ((i3 & 7 | 0) != 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP8[i1 + 62 | 0] | 0) != 2 ? (HEAPU8[i1 + 61 | 0] | 0) >= 2 : 0) {
+  HEAP8[i4] = HEAP8[i1 + 60 | 0] & 3 | i3 & 184;
+  STACKTOP = i2;
+  return;
+ }
+ HEAP8[i4] = i3 & 187 | 4;
+ i3 = HEAP32[i5 + 8 >> 2] | 0;
+ if ((HEAP32[i3 + 8 >> 2] & 64 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = HEAP32[i3 >> 2] | 0;
+ if ((HEAP8[i3 + 5 | 0] & 3) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _reallymarkobject(i1, i3);
+ STACKTOP = i2;
+ return;
+}
+function _luaB_collectgarbage(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[10160 + ((_luaL_checkoption(i1, 1, 10040, 9976) | 0) << 2) >> 2] | 0;
+ i3 = _lua_gc(i1, i4, _luaL_optinteger(i1, 2, 0) | 0) | 0;
+ if ((i4 | 0) == 3) {
+  i4 = _lua_gc(i1, 4, 0) | 0;
+  _lua_pushnumber(i1, +(i3 | 0) + +(i4 | 0) * .0009765625);
+  _lua_pushinteger(i1, i4);
+  i4 = 2;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else if ((i4 | 0) == 9 | (i4 | 0) == 5) {
+  _lua_pushboolean(i1, i3);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_pushinteger(i1, i3);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _maxn(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0, d4 = 0.0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ _lua_pushnil(i1);
+ L1 : do {
+  if ((_lua_next(i1, 1) | 0) == 0) {
+   d3 = 0.0;
+  } else {
+   d4 = 0.0;
+   while (1) {
+    while (1) {
+     _lua_settop(i1, -2);
+     if ((_lua_type(i1, -1) | 0) == 3 ? (d3 = +_lua_tonumberx(i1, -1, 0), d3 > d4) : 0) {
+      break;
+     }
+     if ((_lua_next(i1, 1) | 0) == 0) {
+      d3 = d4;
+      break L1;
+     }
+    }
+    if ((_lua_next(i1, 1) | 0) == 0) {
+     break;
+    } else {
+     d4 = d3;
+    }
+   }
+  }
+ } while (0);
+ _lua_pushnumber(i1, d3);
+ STACKTOP = i2;
+ return 1;
+}
+function _str_char(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1040 | 0;
+ i4 = i2;
+ i3 = _lua_gettop(i1) | 0;
+ i5 = _luaL_buffinitsize(i1, i4, i3) | 0;
+ if ((i3 | 0) < 1) {
+  _luaL_pushresultsize(i4, i3);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i6 = 1;
+ }
+ while (1) {
+  i7 = _luaL_checkinteger(i1, i6) | 0;
+  if ((i7 & 255 | 0) != (i7 | 0)) {
+   _luaL_argerror(i1, i6, 7920) | 0;
+  }
+  HEAP8[i5 + (i6 + -1) | 0] = i7;
+  if ((i6 | 0) == (i3 | 0)) {
+   break;
+  } else {
+   i6 = i6 + 1 | 0;
+  }
+ }
+ _luaL_pushresultsize(i4, i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _luaK_exp2val(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ i3 = i5 + 16 | 0;
+ i4 = i5 + 20 | 0;
+ if ((HEAP32[i3 >> 2] | 0) == (HEAP32[i4 >> 2] | 0)) {
+  _luaK_dischargevars(i1, i5);
+  STACKTOP = i2;
+  return;
+ }
+ _luaK_dischargevars(i1, i5);
+ if ((HEAP32[i5 >> 2] | 0) == 6) {
+  i6 = HEAP32[i5 + 8 >> 2] | 0;
+  if ((HEAP32[i3 >> 2] | 0) == (HEAP32[i4 >> 2] | 0)) {
+   STACKTOP = i2;
+   return;
+  }
+  if ((i6 | 0) >= (HEAPU8[i1 + 46 | 0] | 0 | 0)) {
+   _exp2reg(i1, i5, i6);
+   STACKTOP = i2;
+   return;
+  }
+ }
+ _luaK_exp2nextreg(i1, i5);
+ STACKTOP = i2;
+ return;
+}
+function _str_reverse(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i2 + 1040 | 0;
+ i1 = i2;
+ i3 = _luaL_checklstring(i5, 1, i4) | 0;
+ i5 = _luaL_buffinitsize(i5, i1, HEAP32[i4 >> 2] | 0) | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  i7 = 0;
+  _luaL_pushresultsize(i1, i7);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i7 = 0;
+ }
+ do {
+  HEAP8[i5 + i7 | 0] = HEAP8[i3 + (i6 + ~i7) | 0] | 0;
+  i7 = i7 + 1 | 0;
+  i6 = HEAP32[i4 >> 2] | 0;
+ } while (i7 >>> 0 < i6 >>> 0);
+ _luaL_pushresultsize(i1, i6);
+ STACKTOP = i2;
+ return 1;
+}
+function _str_upper(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i1 + 1040 | 0;
+ i2 = i1;
+ i3 = _luaL_checklstring(i5, 1, i4) | 0;
+ i5 = _luaL_buffinitsize(i5, i2, HEAP32[i4 >> 2] | 0) | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  i7 = 0;
+  _luaL_pushresultsize(i2, i7);
+  STACKTOP = i1;
+  return 1;
+ } else {
+  i6 = 0;
+ }
+ do {
+  HEAP8[i5 + i6 | 0] = _toupper(HEAPU8[i3 + i6 | 0] | 0 | 0) | 0;
+  i6 = i6 + 1 | 0;
+  i7 = HEAP32[i4 >> 2] | 0;
+ } while (i6 >>> 0 < i7 >>> 0);
+ _luaL_pushresultsize(i2, i7);
+ STACKTOP = i1;
+ return 1;
+}
+function _str_lower(i5) {
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i4 = i1 + 1040 | 0;
+ i2 = i1;
+ i3 = _luaL_checklstring(i5, 1, i4) | 0;
+ i5 = _luaL_buffinitsize(i5, i2, HEAP32[i4 >> 2] | 0) | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  i7 = 0;
+  _luaL_pushresultsize(i2, i7);
+  STACKTOP = i1;
+  return 1;
+ } else {
+  i6 = 0;
+ }
+ do {
+  HEAP8[i5 + i6 | 0] = _tolower(HEAPU8[i3 + i6 | 0] | 0 | 0) | 0;
+  i6 = i6 + 1 | 0;
+  i7 = HEAP32[i4 >> 2] | 0;
+ } while (i6 >>> 0 < i7 >>> 0);
+ _luaL_pushresultsize(i2, i7);
+ STACKTOP = i1;
+ return 1;
+}
+function ___divdi3(i1, i2, i3, i4) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i5 = 0, i6 = 0, i7 = 0, i8 = 0;
+ i5 = i2 >> 31 | ((i2 | 0) < 0 ? -1 : 0) << 1;
+ i6 = ((i2 | 0) < 0 ? -1 : 0) >> 31 | ((i2 | 0) < 0 ? -1 : 0) << 1;
+ i7 = i4 >> 31 | ((i4 | 0) < 0 ? -1 : 0) << 1;
+ i8 = ((i4 | 0) < 0 ? -1 : 0) >> 31 | ((i4 | 0) < 0 ? -1 : 0) << 1;
+ i1 = _i64Subtract(i5 ^ i1, i6 ^ i2, i5, i6) | 0;
+ i2 = tempRet0;
+ i5 = i7 ^ i5;
+ i6 = i8 ^ i6;
+ i7 = _i64Subtract((___udivmoddi4(i1, i2, _i64Subtract(i7 ^ i3, i8 ^ i4, i7, i8) | 0, tempRet0, 0) | 0) ^ i5, tempRet0 ^ i6, i5, i6) | 0;
+ return i7 | 0;
+}
+function _luaK_setoneret(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i4 >> 2] | 0;
+ if ((i3 | 0) == 13) {
+  i3 = (HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i4 + 8 >> 2] << 2) | 0;
+  HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & 8388607 | 16777216;
+  HEAP32[i4 >> 2] = 11;
+  STACKTOP = i2;
+  return;
+ } else if ((i3 | 0) == 12) {
+  HEAP32[i4 >> 2] = 6;
+  i4 = i4 + 8 | 0;
+  HEAP32[i4 >> 2] = (HEAP32[(HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] | 0) + (HEAP32[i4 >> 2] << 2) >> 2] | 0) >>> 6 & 255;
+  STACKTOP = i2;
+  return;
+ } else {
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaV_tostring(i6, i1) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i3 = i2;
+ i4 = i2 + 8 | 0;
+ i5 = i1 + 8 | 0;
+ if ((HEAP32[i5 >> 2] | 0) != 3) {
+  i6 = 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ HEAPF64[tempDoublePtr >> 3] = +HEAPF64[i1 >> 3];
+ HEAP32[i3 >> 2] = HEAP32[tempDoublePtr >> 2];
+ HEAP32[i3 + 4 >> 2] = HEAP32[tempDoublePtr + 4 >> 2];
+ i6 = _luaS_newlstr(i6, i4, _sprintf(i4 | 0, 8936, i3 | 0) | 0) | 0;
+ HEAP32[i1 >> 2] = i6;
+ HEAP32[i5 >> 2] = HEAPU8[i6 + 4 | 0] | 0 | 64;
+ i6 = 1;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _strcmp(i4, i2) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i5 = HEAP8[i4] | 0;
+ i3 = HEAP8[i2] | 0;
+ if (i5 << 24 >> 24 != i3 << 24 >> 24 | i5 << 24 >> 24 == 0 | i3 << 24 >> 24 == 0) {
+  i4 = i5;
+  i5 = i3;
+  i4 = i4 & 255;
+  i5 = i5 & 255;
+  i5 = i4 - i5 | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ do {
+  i4 = i4 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i5 = HEAP8[i4] | 0;
+  i3 = HEAP8[i2] | 0;
+ } while (!(i5 << 24 >> 24 != i3 << 24 >> 24 | i5 << 24 >> 24 == 0 | i3 << 24 >> 24 == 0));
+ i4 = i5 & 255;
+ i5 = i3 & 255;
+ i5 = i4 - i5 | 0;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _lua_pushstring(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == 0) {
+  i3 = i1 + 8 | 0;
+  i1 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i1 + 8 >> 2] = 0;
+  HEAP32[i3 >> 2] = i1 + 16;
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i3 = _luaS_new(i1, i3) | 0;
+ i1 = i1 + 8 | 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i4 + 8 >> 2] = HEAPU8[i3 + 4 | 0] | 0 | 64;
+ HEAP32[i1 >> 2] = (HEAP32[i1 >> 2] | 0) + 16;
+ i3 = i3 + 16 | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaK_exp2anyreg(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ _luaK_dischargevars(i1, i3);
+ if ((HEAP32[i3 >> 2] | 0) == 6) {
+  i5 = i3 + 8 | 0;
+  i4 = HEAP32[i5 >> 2] | 0;
+  if ((HEAP32[i3 + 16 >> 2] | 0) == (HEAP32[i3 + 20 >> 2] | 0)) {
+   i5 = i4;
+   STACKTOP = i2;
+   return i5 | 0;
+  }
+  if ((i4 | 0) >= (HEAPU8[i1 + 46 | 0] | 0 | 0)) {
+   _exp2reg(i1, i3, i4);
+   i5 = HEAP32[i5 >> 2] | 0;
+   STACKTOP = i2;
+   return i5 | 0;
+  }
+ } else {
+  i5 = i3 + 8 | 0;
+ }
+ _luaK_exp2nextreg(i1, i3);
+ i5 = HEAP32[i5 >> 2] | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _check_match(i1, i4, i5, i6) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((HEAP32[i1 + 16 >> 2] | 0) == (i4 | 0)) {
+  _luaX_next(i1);
+  STACKTOP = i2;
+  return;
+ }
+ if ((HEAP32[i1 + 4 >> 2] | 0) == (i6 | 0)) {
+  _error_expected(i1, i4);
+ } else {
+  i2 = HEAP32[i1 + 52 >> 2] | 0;
+  i4 = _luaX_token2str(i1, i4) | 0;
+  i5 = _luaX_token2str(i1, i5) | 0;
+  HEAP32[i3 >> 2] = i4;
+  HEAP32[i3 + 4 >> 2] = i5;
+  HEAP32[i3 + 8 >> 2] = i6;
+  _luaX_syntaxerror(i1, _luaO_pushfstring(i2, 6840, i3) | 0);
+ }
+}
+function _fieldsel(i1, i6) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i2;
+ i5 = i1 + 48 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ _luaK_exp2anyregup(i4, i6);
+ _luaX_next(i1);
+ if ((HEAP32[i1 + 16 >> 2] | 0) == 288) {
+  i7 = HEAP32[i1 + 24 >> 2] | 0;
+  _luaX_next(i1);
+  i5 = _luaK_stringK(HEAP32[i5 >> 2] | 0, i7) | 0;
+  HEAP32[i3 + 16 >> 2] = -1;
+  HEAP32[i3 + 20 >> 2] = -1;
+  HEAP32[i3 >> 2] = 4;
+  HEAP32[i3 + 8 >> 2] = i5;
+  _luaK_indexed(i4, i6, i3);
+  STACKTOP = i2;
+  return;
+ } else {
+  _error_expected(i1, 288);
+ }
+}
+function _luaK_exp2anyregup(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i3 >> 2] | 0) == 8 ? (HEAP32[i3 + 16 >> 2] | 0) == (HEAP32[i3 + 20 >> 2] | 0) : 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaK_dischargevars(i1, i3);
+ if ((HEAP32[i3 >> 2] | 0) == 6) {
+  i4 = HEAP32[i3 + 8 >> 2] | 0;
+  if ((HEAP32[i3 + 16 >> 2] | 0) == (HEAP32[i3 + 20 >> 2] | 0)) {
+   STACKTOP = i2;
+   return;
+  }
+  if ((i4 | 0) >= (HEAPU8[i1 + 46 | 0] | 0 | 0)) {
+   _exp2reg(i1, i3, i4);
+   STACKTOP = i2;
+   return;
+  }
+ }
+ _luaK_exp2nextreg(i1, i3);
+ STACKTOP = i2;
+ return;
+}
+function _lua_settop(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ if (!((i5 | 0) > -1)) {
+  i4 = i3 + 8 | 0;
+  HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + (i5 + 1 << 4);
+  STACKTOP = i1;
+  return;
+ }
+ i2 = i3 + 8 | 0;
+ i4 = HEAP32[i2 >> 2] | 0;
+ i3 = (HEAP32[HEAP32[i3 + 16 >> 2] >> 2] | 0) + (i5 + 1 << 4) | 0;
+ if (i4 >>> 0 < i3 >>> 0) {
+  while (1) {
+   i5 = i4 + 16 | 0;
+   HEAP32[i4 + 8 >> 2] = 0;
+   if (i5 >>> 0 < i3 >>> 0) {
+    i4 = i5;
+   } else {
+    break;
+   }
+  }
+  HEAP32[i2 >> 2] = i5;
+ }
+ HEAP32[i2 >> 2] = i3;
+ STACKTOP = i1;
+ return;
+}
+function _luaL_fileresult(i1, i6, i5) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = HEAP32[(___errno_location() | 0) >> 2] | 0;
+ if ((i6 | 0) != 0) {
+  _lua_pushboolean(i1, 1);
+  i6 = 1;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ _lua_pushnil(i1);
+ i6 = _strerror(i3 | 0) | 0;
+ if ((i5 | 0) == 0) {
+  _lua_pushstring(i1, i6) | 0;
+ } else {
+  HEAP32[i4 >> 2] = i5;
+  HEAP32[i4 + 4 >> 2] = i6;
+  _lua_pushfstring(i1, 1176, i4) | 0;
+ }
+ _lua_pushinteger(i1, i3);
+ i6 = 3;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaL_pushmodule(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ _luaL_findtable(i1, -1001e3, 1432, 1) | 0;
+ _lua_getfield(i1, -1, i4);
+ if ((_lua_type(i1, -1) | 0) == 5) {
+  _lua_remove(i1, -2);
+  STACKTOP = i2;
+  return;
+ }
+ _lua_settop(i1, -2);
+ _lua_rawgeti(i1, -1001e3, 2);
+ if ((_luaL_findtable(i1, 0, i4, i5) | 0) != 0) {
+  HEAP32[i3 >> 2] = i4;
+  _luaL_error(i1, 1440, i3) | 0;
+ }
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -3, i4);
+ _lua_remove(i1, -2);
+ STACKTOP = i2;
+ return;
+}
+function _b_replace(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkunsigned(i1, 1) | 0;
+ i5 = _luaL_checkunsigned(i1, 2) | 0;
+ i4 = _luaL_checkinteger(i1, 3) | 0;
+ i2 = _luaL_optinteger(i1, 4, 1) | 0;
+ if (!((i4 | 0) > -1)) {
+  _luaL_argerror(i1, 3, 10440) | 0;
+ }
+ if ((i2 | 0) <= 0) {
+  _luaL_argerror(i1, 4, 10472) | 0;
+ }
+ if ((i2 + i4 | 0) > 32) {
+  _luaL_error(i1, 10496, i6) | 0;
+ }
+ i2 = ~(-2 << i2 + -1);
+ _lua_pushunsigned(i1, i3 & ~(i2 << i4) | (i5 & i2) << i4);
+ STACKTOP = i6;
+ return 1;
+}
+function _luaT_gettmbyobj(i1, i5, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i5 + 8 >> 2] & 15;
+ if ((i4 | 0) == 5) {
+  i4 = HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] | 0;
+ } else if ((i4 | 0) == 7) {
+  i4 = HEAP32[(HEAP32[i5 >> 2] | 0) + 8 >> 2] | 0;
+ } else {
+  i4 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + (i4 << 2) + 252 >> 2] | 0;
+ }
+ if ((i4 | 0) == 0) {
+  i5 = 5192;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i5 = _luaH_getstr(i4, HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + (i3 << 2) + 184 >> 2] | 0) | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _luaS_eqstr(i2, i3) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i4 = HEAP8[i2 + 4 | 0] | 0;
+ do {
+  if (i4 << 24 >> 24 == (HEAP8[i3 + 4 | 0] | 0)) {
+   if (i4 << 24 >> 24 == 4) {
+    i2 = (i2 | 0) == (i3 | 0);
+    break;
+   }
+   i4 = HEAP32[i2 + 12 >> 2] | 0;
+   if ((i2 | 0) != (i3 | 0)) {
+    if ((i4 | 0) == (HEAP32[i3 + 12 >> 2] | 0)) {
+     i2 = (_memcmp(i2 + 16 | 0, i3 + 16 | 0, i4) | 0) == 0;
+    } else {
+     i2 = 0;
+    }
+   } else {
+    i2 = 1;
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 & 1 | 0;
+}
+function _lua_concat(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) > 1) {
+  if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+   _luaC_step(i1);
+  }
+  _luaV_concat(i1, i3);
+  STACKTOP = i2;
+  return;
+ } else {
+  if ((i3 | 0) != 0) {
+   STACKTOP = i2;
+   return;
+  }
+  i3 = i1 + 8 | 0;
+  i4 = HEAP32[i3 >> 2] | 0;
+  i1 = _luaS_newlstr(i1, 936, 0) | 0;
+  HEAP32[i4 >> 2] = i1;
+  HEAP32[i4 + 8 >> 2] = HEAPU8[i1 + 4 | 0] | 0 | 64;
+  HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 16;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _ll_loadfunc(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_getfield(i1, -1001e3, 4184);
+ _lua_getfield(i1, -1, i4);
+ i4 = _lua_touserdata(i1, -1) | 0;
+ _lua_settop(i1, -3);
+ if ((i4 | 0) == 0) {
+  _lua_pushlstring(i1, 4968, 58) | 0;
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ if ((HEAP8[i3] | 0) == 42) {
+  _lua_pushboolean(i1, 1);
+  i4 = 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_pushlstring(i1, 4968, 58) | 0;
+  i4 = 2;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function _luaD_growstack(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = HEAP32[i1 + 32 >> 2] | 0;
+ if ((i4 | 0) > 1e6) {
+  _luaD_throw(i1, 6);
+ }
+ i3 = i3 + 5 + ((HEAP32[i1 + 8 >> 2] | 0) - (HEAP32[i1 + 28 >> 2] | 0) >> 4) | 0;
+ i4 = i4 << 1;
+ i4 = (i4 | 0) > 1e6 ? 1e6 : i4;
+ i3 = (i4 | 0) < (i3 | 0) ? i3 : i4;
+ if ((i3 | 0) > 1e6) {
+  _luaD_reallocstack(i1, 1000200);
+  _luaG_runerror(i1, 2224, i2);
+ } else {
+  _luaD_reallocstack(i1, i3);
+  STACKTOP = i2;
+  return;
+ }
+}
+function _luaL_callmeta(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = _lua_absindex(i1, i4) | 0;
+ if ((_lua_getmetatable(i1, i4) | 0) == 0) {
+  i4 = 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_rawget(i1, -2);
+ if ((_lua_type(i1, -1) | 0) == 0) {
+  _lua_settop(i1, -3);
+  i4 = 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_remove(i1, -2);
+  _lua_pushvalue(i1, i4);
+  _lua_callk(i1, 1, 1, 0, 0);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _luaK_reserveregs(i8, i7) {
+ i8 = i8 | 0;
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i2 = i8 + 48 | 0;
+ i6 = HEAP8[i2] | 0;
+ i4 = (i6 & 255) + i7 | 0;
+ i5 = (HEAP32[i8 >> 2] | 0) + 78 | 0;
+ do {
+  if ((i4 | 0) > (HEAPU8[i5] | 0 | 0)) {
+   if ((i4 | 0) > 249) {
+    _luaX_syntaxerror(HEAP32[i8 + 12 >> 2] | 0, 10536);
+   } else {
+    HEAP8[i5] = i4;
+    i1 = HEAP8[i2] | 0;
+    break;
+   }
+  } else {
+   i1 = i6;
+  }
+ } while (0);
+ HEAP8[i2] = (i1 & 255) + i7;
+ STACKTOP = i3;
+ return;
+}
+function _aux_lines(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i4 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ i2 = i3 + -1 | 0;
+ if ((i3 | 0) >= 19) {
+  _luaL_argerror(i1, 17, 3320) | 0;
+ }
+ _lua_pushvalue(i1, 1);
+ _lua_pushinteger(i1, i2);
+ _lua_pushboolean(i1, i5);
+ if ((i3 | 0) >= 2) {
+  i5 = 1;
+  while (1) {
+   i6 = i5 + 1 | 0;
+   _lua_pushvalue(i1, i6);
+   if ((i5 | 0) < (i2 | 0)) {
+    i5 = i6;
+   } else {
+    break;
+   }
+  }
+ }
+ _lua_pushcclosure(i1, 155, i3 + 2 | 0);
+ STACKTOP = i4;
+ return;
+}
+function _memcmp(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0, i6 = 0;
+ i1 = STACKTOP;
+ L1 : do {
+  if ((i3 | 0) == 0) {
+   i2 = 0;
+  } else {
+   while (1) {
+    i6 = HEAP8[i2] | 0;
+    i5 = HEAP8[i4] | 0;
+    if (!(i6 << 24 >> 24 == i5 << 24 >> 24)) {
+     break;
+    }
+    i3 = i3 + -1 | 0;
+    if ((i3 | 0) == 0) {
+     i2 = 0;
+     break L1;
+    } else {
+     i2 = i2 + 1 | 0;
+     i4 = i4 + 1 | 0;
+    }
+   }
+   i2 = (i6 & 255) - (i5 & 255) | 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _b_arshift(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkunsigned(i1, 1) | 0;
+ i4 = _luaL_checkinteger(i1, 2) | 0;
+ if ((i4 | 0) > -1 & (i3 | 0) < 0) {
+  if ((i4 | 0) > 31) {
+   i3 = -1;
+  } else {
+   i3 = i3 >>> i4 | ~(-1 >>> i4);
+  }
+  _lua_pushunsigned(i1, i3);
+  STACKTOP = i2;
+  return 1;
+ }
+ i5 = 0 - i4 | 0;
+ if ((i4 | 0) > 0) {
+  i3 = (i4 | 0) > 31 ? 0 : i3 >>> i4;
+ } else {
+  i3 = (i5 | 0) > 31 ? 0 : i3 << i5;
+ }
+ _lua_pushunsigned(i1, i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaL_checkunsigned(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i6 = i3 + 8 | 0;
+ i2 = _lua_tounsignedx(i1, i5, i6) | 0;
+ if ((HEAP32[i6 >> 2] | 0) != 0) {
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ i7 = _lua_typename(i1, 3) | 0;
+ i6 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+ HEAP32[i4 >> 2] = i7;
+ HEAP32[i4 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i5, _lua_pushfstring(i1, 1744, i4) | 0) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaB_loadfile(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i1 = STACKTOP;
+ i4 = _luaL_optlstring(i2, 1, 0, 0) | 0;
+ i5 = _luaL_optlstring(i2, 2, 0, 0) | 0;
+ i3 = (_lua_type(i2, 3) | 0) != -1;
+ i6 = i3 ? 3 : 0;
+ if ((_luaL_loadfilex(i2, i4, i5) | 0) == 0) {
+  if (i3 ? (_lua_pushvalue(i2, i6), (_lua_setupvalue(i2, -2, 1) | 0) == 0) : 0) {
+   _lua_settop(i2, -2);
+   i2 = 1;
+  } else {
+   i2 = 1;
+  }
+ } else {
+  _lua_pushnil(i2);
+  _lua_insert(i2, -2);
+  i2 = 2;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaL_checkinteger(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i6 = i3 + 8 | 0;
+ i2 = _lua_tointegerx(i1, i5, i6) | 0;
+ if ((HEAP32[i6 >> 2] | 0) != 0) {
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ i7 = _lua_typename(i1, 3) | 0;
+ i6 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+ HEAP32[i4 >> 2] = i7;
+ HEAP32[i4 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i5, _lua_pushfstring(i1, 1744, i4) | 0) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaB_select(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ i2 = _lua_gettop(i1) | 0;
+ if ((_lua_type(i1, 1) | 0) == 4 ? (HEAP8[_lua_tolstring(i1, 1, 0) | 0] | 0) == 35 : 0) {
+  _lua_pushinteger(i1, i2 + -1 | 0);
+  i4 = 1;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ i4 = _luaL_checkinteger(i1, 1) | 0;
+ if ((i4 | 0) < 0) {
+  i4 = i4 + i2 | 0;
+ } else {
+  i4 = (i4 | 0) > (i2 | 0) ? i2 : i4;
+ }
+ if ((i4 | 0) <= 0) {
+  _luaL_argerror(i1, 1, 9760) | 0;
+ }
+ i4 = i2 - i4 | 0;
+ STACKTOP = i3;
+ return i4 | 0;
+}
+function _luaX_next(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 8 >> 2] = HEAP32[i1 + 4 >> 2];
+ i3 = i1 + 32 | 0;
+ if ((HEAP32[i3 >> 2] | 0) == 286) {
+  HEAP32[i1 + 16 >> 2] = _llex(i1, i1 + 24 | 0) | 0;
+  STACKTOP = i2;
+  return;
+ } else {
+  i1 = i1 + 16 | 0;
+  HEAP32[i1 + 0 >> 2] = HEAP32[i3 + 0 >> 2];
+  HEAP32[i1 + 4 >> 2] = HEAP32[i3 + 4 >> 2];
+  HEAP32[i1 + 8 >> 2] = HEAP32[i3 + 8 >> 2];
+  HEAP32[i1 + 12 >> 2] = HEAP32[i3 + 12 >> 2];
+  HEAP32[i3 >> 2] = 286;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _lua_setglobal(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i5 = _luaH_getint(HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 40 >> 2] | 0, 2) | 0;
+ i4 = i1 + 8 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = i6 + 16;
+ i2 = _luaS_new(i1, i2) | 0;
+ HEAP32[i6 >> 2] = i2;
+ HEAP32[i6 + 8 >> 2] = HEAPU8[i2 + 4 | 0] | 0 | 64;
+ i2 = HEAP32[i4 >> 2] | 0;
+ _luaV_settable(i1, i5, i2 + -16 | 0, i2 + -32 | 0);
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + -32;
+ STACKTOP = i3;
+ return;
+}
+function _luaL_checknumber(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var d2 = 0.0, i3 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ i6 = i3 + 8 | 0;
+ d2 = +_lua_tonumberx(i1, i5, i6);
+ if ((HEAP32[i6 >> 2] | 0) != 0) {
+  STACKTOP = i3;
+  return +d2;
+ }
+ i7 = _lua_typename(i1, 3) | 0;
+ i6 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+ HEAP32[i4 >> 2] = i7;
+ HEAP32[i4 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i5, _lua_pushfstring(i1, 1744, i4) | 0) | 0;
+ STACKTOP = i3;
+ return +d2;
+}
+function _luaZ_fill(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = FUNCTION_TABLE_iiii[HEAP32[i1 + 8 >> 2] & 3](HEAP32[i1 + 16 >> 2] | 0, HEAP32[i1 + 12 >> 2] | 0, i4) | 0;
+ if ((i3 | 0) == 0) {
+  i4 = -1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ i4 = HEAP32[i4 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  i4 = -1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ HEAP32[i1 >> 2] = i4 + -1;
+ HEAP32[i1 + 4 >> 2] = i3 + 1;
+ i4 = HEAPU8[i3] | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _lua_createtable(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i5 = _luaH_new(i1) | 0;
+ i6 = i1 + 8 | 0;
+ i7 = HEAP32[i6 >> 2] | 0;
+ HEAP32[i7 >> 2] = i5;
+ HEAP32[i7 + 8 >> 2] = 69;
+ HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + 16;
+ if (!((i3 | 0) > 0 | (i4 | 0) > 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ _luaH_resize(i1, i5, i3, i4);
+ STACKTOP = i2;
+ return;
+}
+function _generic_reader(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ _luaL_checkstack(i1, 2, 9888);
+ _lua_pushvalue(i1, 1);
+ _lua_callk(i1, 0, 1, 0, 0);
+ if ((_lua_type(i1, -1) | 0) == 0) {
+  _lua_settop(i1, -2);
+  HEAP32[i2 >> 2] = 0;
+  i2 = 0;
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ if ((_lua_isstring(i1, -1) | 0) == 0) {
+  _luaL_error(i1, 9920, i3) | 0;
+ }
+ _lua_replace(i1, 5);
+ i2 = _lua_tolstring(i1, 5, i2) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaZ_openspace(i5, i1, i6) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = i1 + 8 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ if (!(i3 >>> 0 < i6 >>> 0)) {
+  i6 = HEAP32[i1 >> 2] | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ i6 = i6 >>> 0 < 32 ? 32 : i6;
+ if ((i6 + 1 | 0) >>> 0 > 4294967293) {
+  _luaM_toobig(i5);
+ }
+ i5 = _luaM_realloc_(i5, HEAP32[i1 >> 2] | 0, i3, i6) | 0;
+ HEAP32[i1 >> 2] = i5;
+ HEAP32[i4 >> 2] = i6;
+ i6 = i5;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaH_getstr(i4, i3) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0;
+ i2 = STACKTOP;
+ i4 = (HEAP32[i4 + 16 >> 2] | 0) + (((1 << (HEAPU8[i4 + 7 | 0] | 0)) + -1 & HEAP32[i3 + 8 >> 2]) << 5) | 0;
+ while (1) {
+  if ((HEAP32[i4 + 24 >> 2] | 0) == 68 ? (HEAP32[i4 + 16 >> 2] | 0) == (i3 | 0) : 0) {
+   break;
+  }
+  i4 = HEAP32[i4 + 28 >> 2] | 0;
+  if ((i4 | 0) == 0) {
+   i3 = 5192;
+   i1 = 6;
+   break;
+  }
+ }
+ if ((i1 | 0) == 6) {
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _b_extract(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = _luaL_checkunsigned(i1, 1) | 0;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ i4 = _luaL_optinteger(i1, 3, 1) | 0;
+ if (!((i3 | 0) > -1)) {
+  _luaL_argerror(i1, 2, 10440) | 0;
+ }
+ if ((i4 | 0) <= 0) {
+  _luaL_argerror(i1, 3, 10472) | 0;
+ }
+ if ((i4 + i3 | 0) > 32) {
+  _luaL_error(i1, 10496, i5) | 0;
+ }
+ _lua_pushunsigned(i1, i2 >>> i3 & ~(-2 << i4 + -1));
+ STACKTOP = i5;
+ return 1;
+}
+function _luaL_checklstring(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i6 = 0, i7 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i5 = _lua_tolstring(i1, i4, i5) | 0;
+ if ((i5 | 0) != 0) {
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i7 = _lua_typename(i1, 4) | 0;
+ i6 = _lua_typename(i1, _lua_type(i1, i4) | 0) | 0;
+ HEAP32[i3 >> 2] = i7;
+ HEAP32[i3 + 4 >> 2] = i6;
+ _luaL_argerror(i1, i4, _lua_pushfstring(i1, 1744, i3) | 0) | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _db_traceback(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 8) {
+  i3 = _lua_tothread(i1, 1) | 0;
+  i4 = 1;
+ } else {
+  i3 = i1;
+  i4 = 0;
+ }
+ i5 = i4 + 1 | 0;
+ i6 = _lua_tolstring(i1, i5, 0) | 0;
+ if ((i6 | 0) == 0 ? (_lua_type(i1, i5) | 0) >= 1 : 0) {
+  _lua_pushvalue(i1, i5);
+  STACKTOP = i2;
+  return 1;
+ }
+ _luaL_traceback(i1, i3, i6, _luaL_optinteger(i1, i4 | 2, (i3 | 0) == (i1 | 0) | 0) | 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _f_setvbuf(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i5 = HEAP32[i3 >> 2] | 0;
+ i4 = _luaL_checkoption(i1, 2, 0, 3128) | 0;
+ i3 = _luaL_optinteger(i1, 3, 1024) | 0;
+ i3 = _luaL_fileresult(i1, (_setvbuf(i5 | 0, 0, HEAP32[3112 + (i4 << 2) >> 2] | 0, i3 | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaU_dump(i3, i1, i4, i2, i5) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i6 = 0, i7 = 0, i8 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 48 | 0;
+ i8 = i6 + 20 | 0;
+ i7 = i6;
+ HEAP32[i7 >> 2] = i3;
+ HEAP32[i7 + 4 >> 2] = i4;
+ HEAP32[i7 + 8 >> 2] = i2;
+ HEAP32[i7 + 12 >> 2] = i5;
+ i5 = i7 + 16 | 0;
+ _luaU_header(i8);
+ HEAP32[i5 >> 2] = FUNCTION_TABLE_iiiii[i4 & 3](i3, i8, 18, i2) | 0;
+ _DumpFunction(i1, i7);
+ STACKTOP = i6;
+ return HEAP32[i5 >> 2] | 0;
+}
+function _luaB_setmetatable(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _lua_type(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 5);
+ if (!((i3 | 0) == 0 | (i3 | 0) == 5)) {
+  _luaL_argerror(i1, 2, 9680) | 0;
+ }
+ if ((_luaL_getmetafield(i1, 1, 9704) | 0) == 0) {
+  _lua_settop(i1, 2);
+  _lua_setmetatable(i1, 1) | 0;
+  i3 = 1;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  i3 = _luaL_error(i1, 9720, i2) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _getF(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ i3 = STACKTOP;
+ i4 = HEAP32[i2 >> 2] | 0;
+ if ((i4 | 0) > 0) {
+  HEAP32[i1 >> 2] = i4;
+  HEAP32[i2 >> 2] = 0;
+  i4 = i2 + 8 | 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ i4 = i2 + 4 | 0;
+ if ((_feof(HEAP32[i4 >> 2] | 0) | 0) != 0) {
+  i4 = 0;
+  STACKTOP = i3;
+  return i4 | 0;
+ }
+ i2 = i2 + 8 | 0;
+ HEAP32[i1 >> 2] = _fread(i2 | 0, 1, 1024, HEAP32[i4 >> 2] | 0) | 0;
+ i4 = i2;
+ STACKTOP = i3;
+ return i4 | 0;
+}
+function _luaL_where(i1, i6) {
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i3 = i4;
+ i2 = i4 + 8 | 0;
+ if ((_lua_getstack(i1, i6, i2) | 0) != 0 ? (_lua_getinfo(i1, 1152, i2) | 0, i5 = HEAP32[i2 + 20 >> 2] | 0, (i5 | 0) > 0) : 0) {
+  HEAP32[i3 >> 2] = i2 + 36;
+  HEAP32[i3 + 4 >> 2] = i5;
+  _lua_pushfstring(i1, 1160, i3) | 0;
+  STACKTOP = i4;
+  return;
+ }
+ _lua_pushlstring(i1, 1168, 0) | 0;
+ STACKTOP = i4;
+ return;
+}
+function _hookf(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_getsubtable(i1, -1001e3, 11584) | 0;
+ _lua_pushthread(i1) | 0;
+ _lua_rawget(i1, -2);
+ if ((_lua_type(i1, -1) | 0) != 6) {
+  STACKTOP = i2;
+  return;
+ }
+ _lua_pushstring(i1, HEAP32[11608 + (HEAP32[i3 >> 2] << 2) >> 2] | 0) | 0;
+ i3 = HEAP32[i3 + 20 >> 2] | 0;
+ if ((i3 | 0) > -1) {
+  _lua_pushinteger(i1, i3);
+ } else {
+  _lua_pushnil(i1);
+ }
+ _lua_callk(i1, 2, 0, 0, 0);
+ STACKTOP = i2;
+ return;
+}
+function _luaV_tonumber(i5, i2) {
+ i5 = i5 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ i4 = HEAP32[i5 + 8 >> 2] | 0;
+ if ((i4 | 0) != 3) {
+  if ((i4 & 15 | 0) == 4 ? (i5 = HEAP32[i5 >> 2] | 0, (_luaO_str2d(i5 + 16 | 0, HEAP32[i5 + 12 >> 2] | 0, i3) | 0) != 0) : 0) {
+   HEAPF64[i2 >> 3] = +HEAPF64[i3 >> 3];
+   HEAP32[i2 + 8 >> 2] = 3;
+  } else {
+   i2 = 0;
+  }
+ } else {
+  i2 = i5;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaO_arith(i3, d1, d2) {
+ i3 = i3 | 0;
+ d1 = +d1;
+ d2 = +d2;
+ switch (i3 | 0) {
+ case 4:
+  {
+   d1 = d1 - +Math_floor(+(d1 / d2)) * d2;
+   break;
+  }
+ case 6:
+  {
+   d1 = -d1;
+   break;
+  }
+ case 0:
+  {
+   d1 = d1 + d2;
+   break;
+  }
+ case 1:
+  {
+   d1 = d1 - d2;
+   break;
+  }
+ case 5:
+  {
+   d1 = +Math_pow(+d1, +d2);
+   break;
+  }
+ case 3:
+  {
+   d1 = d1 / d2;
+   break;
+  }
+ case 2:
+  {
+   d1 = d1 * d2;
+   break;
+  }
+ default:
+  {
+   d1 = 0.0;
+  }
+ }
+ return +d1;
+}
+function _luaB_coresume(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_tothread(i1, 1) | 0;
+ if ((i3 | 0) == 0) {
+  _luaL_argerror(i1, 1, 10856) | 0;
+ }
+ i3 = _auxresume(i1, i3, (_lua_gettop(i1) | 0) + -1 | 0) | 0;
+ if ((i3 | 0) < 0) {
+  _lua_pushboolean(i1, 0);
+  _lua_insert(i1, -2);
+  i3 = 2;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _lua_pushboolean(i1, 1);
+  _lua_insert(i1, ~i3);
+  i3 = i3 + 1 | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _pairsmeta(i1, i5, i4, i3) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_luaL_getmetafield(i1, 1, i5) | 0) != 0) {
+  _lua_pushvalue(i1, 1);
+  _lua_callk(i1, 1, 3, 0, 0);
+  STACKTOP = i2;
+  return;
+ }
+ _luaL_checktype(i1, 1, 5);
+ _lua_pushcclosure(i1, i3, 0);
+ _lua_pushvalue(i1, 1);
+ if ((i4 | 0) == 0) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return;
+ } else {
+  _lua_pushinteger(i1, 0);
+  STACKTOP = i2;
+  return;
+ }
+}
+function _io_close(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ if ((_lua_type(i1, 1) | 0) == -1) {
+  _lua_getfield(i1, -1001e3, 2800);
+ }
+ if ((HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i4 = (_luaL_checkudata(i1, 1, 2832) | 0) + 4 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = 0;
+ i1 = FUNCTION_TABLE_ii[i3 & 255](i1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _pack(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ _lua_createtable(i1, i3, 1);
+ _lua_pushinteger(i1, i3);
+ _lua_setfield(i1, -2, 8312);
+ if ((i3 | 0) <= 0) {
+  STACKTOP = i2;
+  return 1;
+ }
+ _lua_pushvalue(i1, 1);
+ _lua_rawseti(i1, -2, 1);
+ _lua_replace(i1, 1);
+ if ((i3 | 0) <= 1) {
+  STACKTOP = i2;
+  return 1;
+ }
+ do {
+  _lua_rawseti(i1, 1, i3);
+  i3 = i3 + -1 | 0;
+ } while ((i3 | 0) > 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaL_execresult(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == -1) {
+  i3 = HEAP32[(___errno_location() | 0) >> 2] | 0;
+  _lua_pushnil(i1);
+  _lua_pushstring(i1, _strerror(i3 | 0) | 0) | 0;
+  _lua_pushinteger(i1, i3);
+  STACKTOP = i2;
+  return 3;
+ } else if ((i3 | 0) == 0) {
+  _lua_pushboolean(i1, 1);
+ } else {
+  _lua_pushnil(i1);
+ }
+ _lua_pushstring(i1, 1184) | 0;
+ _lua_pushinteger(i1, i3);
+ STACKTOP = i2;
+ return 3;
+}
+function _lua_getglobal(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i3 = STACKTOP;
+ i4 = _luaH_getint(HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 40 >> 2] | 0, 2) | 0;
+ i5 = i1 + 8 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i5 >> 2] = i6 + 16;
+ i2 = _luaS_new(i1, i2) | 0;
+ HEAP32[i6 >> 2] = i2;
+ HEAP32[i6 + 8 >> 2] = HEAPU8[i2 + 4 | 0] | 0 | 64;
+ i2 = (HEAP32[i5 >> 2] | 0) + -16 | 0;
+ _luaV_gettable(i1, i4, i2, i2);
+ STACKTOP = i3;
+ return;
+}
+function _luaL_checktype(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_type(i1, i5) | 0) == (i4 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i6 = _lua_typename(i1, i4) | 0;
+ i4 = _lua_typename(i1, _lua_type(i1, i5) | 0) | 0;
+ HEAP32[i3 >> 2] = i6;
+ HEAP32[i3 + 4 >> 2] = i4;
+ _luaL_argerror(i1, i5, _lua_pushfstring(i1, 1744, i3) | 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _luaC_newobj(i7, i4, i6, i5, i1) {
+ i7 = i7 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i7 + 12 >> 2] | 0;
+ i7 = _luaM_realloc_(i7, 0, i4 & 15, i6) | 0;
+ i6 = i7 + i1 | 0;
+ i5 = (i5 | 0) == 0 ? i3 + 68 | 0 : i5;
+ HEAP8[i7 + (i1 + 5) | 0] = HEAP8[i3 + 60 | 0] & 3;
+ HEAP8[i7 + (i1 + 4) | 0] = i4;
+ HEAP32[i6 >> 2] = HEAP32[i5 >> 2];
+ HEAP32[i5 >> 2] = i6;
+ STACKTOP = i2;
+ return i6 | 0;
+}
+function _luaL_requiref(i1, i3, i5, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushcclosure(i1, i5, 0);
+ _lua_pushstring(i1, i3) | 0;
+ _lua_callk(i1, 1, 1, 0, 0);
+ _luaL_getsubtable(i1, -1001e3, 1432) | 0;
+ _lua_pushvalue(i1, -2);
+ _lua_setfield(i1, -2, i3);
+ _lua_settop(i1, -2);
+ if ((i4 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ _lua_pushvalue(i1, -1);
+ _lua_setglobal(i1, i3);
+ STACKTOP = i2;
+ return;
+}
+function _luaG_ordererror(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = HEAP32[8528 + ((HEAP32[i3 + 8 >> 2] & 15) + 1 << 2) >> 2] | 0;
+ i4 = HEAP32[8528 + ((HEAP32[i4 + 8 >> 2] & 15) + 1 << 2) >> 2] | 0;
+ if ((i3 | 0) == (i4 | 0)) {
+  HEAP32[i2 >> 2] = i3;
+  _luaG_runerror(i1, 1952, i2);
+ } else {
+  HEAP32[i2 >> 2] = i3;
+  HEAP32[i2 + 4 >> 2] = i4;
+  _luaG_runerror(i1, 1992, i2);
+ }
+}
+function _io_popen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ _luaL_optlstring(i1, 2, 3480, 0) | 0;
+ i5 = _lua_newuserdata(i1, 8) | 0;
+ i4 = i5 + 4 | 0;
+ HEAP32[i4 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ _luaL_error(i1, 3488, i2) | 0;
+ HEAP32[i5 >> 2] = 0;
+ HEAP32[i4 >> 2] = 157;
+ i1 = _luaL_fileresult(i1, 0, i3) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _sort_comp(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 2) | 0) == 0) {
+  i4 = _lua_compare(i1, i3, i4, 1) | 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_pushvalue(i1, 2);
+  _lua_pushvalue(i1, i3 + -1 | 0);
+  _lua_pushvalue(i1, i4 + -2 | 0);
+  _lua_callk(i1, 2, 1, 0, 0);
+  i4 = _lua_toboolean(i1, -1) | 0;
+  _lua_settop(i1, -2);
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _db_upvalueid(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 112 | 0;
+ i4 = i3;
+ i2 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 6);
+ _lua_pushvalue(i1, 1);
+ _lua_getinfo(i1, 11728, i4) | 0;
+ if (!((i2 | 0) > 0 ? (i2 | 0) <= (HEAPU8[i4 + 32 | 0] | 0 | 0) : 0)) {
+  _luaL_argerror(i1, 2, 11736) | 0;
+ }
+ _lua_pushlightuserdata(i1, _lua_upvalueid(i1, 1, i2) | 0);
+ STACKTOP = i3;
+ return 1;
+}
+function _luaL_getmetafield(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ do {
+  if ((_lua_getmetatable(i2, i4) | 0) != 0) {
+   _lua_pushstring(i2, i3) | 0;
+   _lua_rawget(i2, -2);
+   if ((_lua_type(i2, -1) | 0) == 0) {
+    _lua_settop(i2, -3);
+    i2 = 0;
+    break;
+   } else {
+    _lua_remove(i2, -2);
+    i2 = 1;
+    break;
+   }
+  } else {
+   i2 = 0;
+  }
+ } while (0);
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaF_freeupval(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i3 + 8 >> 2] | 0) == (i3 + 16 | 0)) {
+  _luaM_realloc_(i1, i3, 32, 0) | 0;
+  STACKTOP = i2;
+  return;
+ }
+ i4 = i3 + 16 | 0;
+ i5 = i4 + 4 | 0;
+ HEAP32[(HEAP32[i5 >> 2] | 0) + 16 >> 2] = HEAP32[i4 >> 2];
+ HEAP32[(HEAP32[i4 >> 2] | 0) + 20 >> 2] = HEAP32[i5 >> 2];
+ _luaM_realloc_(i1, i3, 32, 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _luaL_addvalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i5 = HEAP32[i1 + 12 >> 2] | 0;
+ i3 = _lua_tolstring(i5, -1, i4) | 0;
+ i6 = i1 + 16 | 0;
+ if ((HEAP32[i1 >> 2] | 0) != (i6 | 0)) {
+  _lua_insert(i5, -2);
+ }
+ _luaL_addlstring(i1, i3, HEAP32[i4 >> 2] | 0);
+ _lua_remove(i5, (HEAP32[i1 >> 2] | 0) != (i6 | 0) ? -2 : -1);
+ STACKTOP = i2;
+ return;
+}
+function _escerror(i1, i4, i3, i2) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i5 = 0, i6 = 0;
+ HEAP32[(HEAP32[i1 + 60 >> 2] | 0) + 4 >> 2] = 0;
+ _save(i1, 92);
+ L1 : do {
+  if ((i3 | 0) > 0) {
+   i5 = 0;
+   do {
+    i6 = HEAP32[i4 + (i5 << 2) >> 2] | 0;
+    if ((i6 | 0) == -1) {
+     break L1;
+    }
+    _save(i1, i6);
+    i5 = i5 + 1 | 0;
+   } while ((i5 | 0) < (i3 | 0));
+  }
+ } while (0);
+ _lexerror(i1, i2, 289);
+}
+function _pushglobalfuncname(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ _lua_getinfo(i1, 1768, i4) | 0;
+ _lua_rawgeti(i1, -1001e3, 2);
+ i4 = i3 + 1 | 0;
+ if ((_findfield(i1, i4, 2) | 0) == 0) {
+  _lua_settop(i1, i3);
+  i4 = 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  _lua_copy(i1, -1, i4);
+  _lua_settop(i1, -3);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function _lua_pushlstring(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i4 = _luaS_newlstr(i1, i3, i4) | 0;
+ i3 = i1 + 8 | 0;
+ i1 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i1 >> 2] = i4;
+ HEAP32[i1 + 8 >> 2] = HEAPU8[i4 + 4 | 0] | 0 | 64;
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return i4 + 16 | 0;
+}
+function _ll_searchpath(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i5 = _luaL_checklstring(i1, 1, 0) | 0;
+ i4 = _luaL_checklstring(i1, 2, 0) | 0;
+ i3 = _luaL_optlstring(i1, 3, 4936, 0) | 0;
+ if ((_searchpath(i1, i5, i4, i3, _luaL_optlstring(i1, 4, 4848, 0) | 0) | 0) != 0) {
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ _lua_pushnil(i1);
+ _lua_insert(i1, -2);
+ i5 = 2;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _math_log(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0, d4 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ do {
+  if ((_lua_type(i1, 2) | 0) >= 1) {
+   d4 = +_luaL_checknumber(i1, 2);
+   if (d4 == 10.0) {
+    d3 = +_log10(+d3);
+    break;
+   } else {
+    d3 = +Math_log(+d3) / +Math_log(+d4);
+    break;
+   }
+  } else {
+   d3 = +Math_log(+d3);
+  }
+ } while (0);
+ _lua_pushnumber(i1, d3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaT_init(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 12 | 0;
+ i4 = 0;
+ do {
+  i5 = _luaS_new(i1, HEAP32[8576 + (i4 << 2) >> 2] | 0) | 0;
+  HEAP32[(HEAP32[i3 >> 2] | 0) + (i4 << 2) + 184 >> 2] = i5;
+  i5 = (HEAP32[(HEAP32[i3 >> 2] | 0) + (i4 << 2) + 184 >> 2] | 0) + 5 | 0;
+  HEAP8[i5] = HEAPU8[i5] | 0 | 32;
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) != 17);
+ STACKTOP = i2;
+ return;
+}
+function _f_gc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return 0;
+ }
+ if ((HEAP32[i3 >> 2] | 0) == 0) {
+  STACKTOP = i2;
+  return 0;
+ }
+ i4 = (_luaL_checkudata(i1, 1, 2832) | 0) + 4 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = 0;
+ FUNCTION_TABLE_ii[i3 & 255](i1) | 0;
+ STACKTOP = i2;
+ return 0;
+}
+function ___shlim(i1, i5) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i6 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 104 >> 2] = i5;
+ i4 = HEAP32[i1 + 8 >> 2] | 0;
+ i3 = HEAP32[i1 + 4 >> 2] | 0;
+ i6 = i4 - i3 | 0;
+ HEAP32[i1 + 108 >> 2] = i6;
+ if ((i5 | 0) != 0 & (i6 | 0) > (i5 | 0)) {
+  HEAP32[i1 + 100 >> 2] = i3 + i5;
+  STACKTOP = i2;
+  return;
+ } else {
+  HEAP32[i1 + 100 >> 2] = i4;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _lua_sethook(i4, i6, i1, i5) {
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = (i6 | 0) == 0 | (i1 | 0) == 0;
+ i3 = HEAP32[i4 + 16 >> 2] | 0;
+ if (!((HEAP8[i3 + 18 | 0] & 1) == 0)) {
+  HEAP32[i4 + 20 >> 2] = HEAP32[i3 + 28 >> 2];
+ }
+ HEAP32[i4 + 52 >> 2] = i2 ? 0 : i6;
+ HEAP32[i4 + 44 >> 2] = i5;
+ HEAP32[i4 + 48 >> 2] = i5;
+ HEAP8[i4 + 40 | 0] = i2 ? 0 : i1 & 255;
+ return 1;
+}
+function _io_tmpfile(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = _lua_newuserdata(i1, 8) | 0;
+ i3 = i4 + 4 | 0;
+ HEAP32[i3 >> 2] = 0;
+ _luaL_setmetatable(i1, 2832);
+ HEAP32[i4 >> 2] = 0;
+ HEAP32[i3 >> 2] = 156;
+ i3 = _tmpfile() | 0;
+ HEAP32[i4 >> 2] = i3;
+ if ((i3 | 0) != 0) {
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ i4 = _luaL_fileresult(i1, 0, 0) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _luaL_checkstack(i1, i5, i4) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_checkstack(i1, i5 + 20 | 0) | 0) != 0) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((i4 | 0) == 0) {
+  _luaL_error(i1, 1240, i3) | 0;
+  STACKTOP = i2;
+  return;
+ } else {
+  HEAP32[i3 >> 2] = i4;
+  _luaL_error(i1, 1216, i3) | 0;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _b_rshift(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i4 = _luaL_checkunsigned(i1, 1) | 0;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ i5 = 0 - i3 | 0;
+ if ((i3 | 0) > 0) {
+  i5 = (i3 | 0) > 31 ? 0 : i4 >>> i3;
+  _lua_pushunsigned(i1, i5);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i5 = (i5 | 0) > 31 ? 0 : i4 << i5;
+  _lua_pushunsigned(i1, i5);
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _b_lshift(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkunsigned(i1, 1) | 0;
+ i4 = _luaL_checkinteger(i1, 2) | 0;
+ if ((i4 | 0) < 0) {
+  i4 = 0 - i4 | 0;
+  i4 = (i4 | 0) > 31 ? 0 : i3 >>> i4;
+  _lua_pushunsigned(i1, i4);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  i4 = (i4 | 0) > 31 ? 0 : i3 << i4;
+  _lua_pushunsigned(i1, i4);
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _math_min(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ d5 = +_luaL_checknumber(i1, 1);
+ if ((i3 | 0) >= 2) {
+  i4 = 2;
+  while (1) {
+   d6 = +_luaL_checknumber(i1, i4);
+   d5 = d6 < d5 ? d6 : d5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushnumber(i1, d5);
+ STACKTOP = i2;
+ return 1;
+}
+function _math_max(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, d5 = 0.0, d6 = 0.0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ d5 = +_luaL_checknumber(i1, 1);
+ if ((i3 | 0) >= 2) {
+  i4 = 2;
+  while (1) {
+   d6 = +_luaL_checknumber(i1, i4);
+   d5 = d6 > d5 ? d6 : d5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushnumber(i1, d5);
+ STACKTOP = i2;
+ return 1;
+}
+function _io_type(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ i3 = _luaL_testudata(i1, 1, 2832) | 0;
+ if ((i3 | 0) == 0) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return 1;
+ }
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _lua_pushlstring(i1, 3456, 11) | 0;
+  STACKTOP = i2;
+  return 1;
+ } else {
+  _lua_pushlstring(i1, 3472, 4) | 0;
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _luaF_newLclosure(i3, i2) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i3 = _luaC_newobj(i3, 6, (i2 << 2) + 16 | 0, 0, 0) | 0;
+ HEAP32[i3 + 12 >> 2] = 0;
+ HEAP8[i3 + 6 | 0] = i2;
+ if ((i2 | 0) == 0) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ i4 = i3 + 16 | 0;
+ do {
+  i2 = i2 + -1 | 0;
+  HEAP32[i4 + (i2 << 2) >> 2] = 0;
+ } while ((i2 | 0) != 0);
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function _io_flush(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ _lua_getfield(i1, -1001e3, 2800);
+ i3 = _lua_touserdata(i1, -1) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  HEAP32[i4 >> 2] = 2804;
+  _luaL_error(i1, 3424, i4) | 0;
+ }
+ i4 = _luaL_fileresult(i1, (_fflush(HEAP32[i3 >> 2] | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _b_test(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) < 1) {
+  i3 = 1;
+ } else {
+  i4 = 1;
+  i5 = -1;
+  while (1) {
+   i5 = (_luaL_checkunsigned(i1, i4) | 0) & i5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+  i3 = (i5 | 0) != 0;
+ }
+ _lua_pushboolean(i1, i3 & 1);
+ STACKTOP = i2;
+ return 1;
+}
+function ___muldsi3(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0, i4 = 0, i5 = 0, i6 = 0;
+ i6 = i2 & 65535;
+ i4 = i1 & 65535;
+ i3 = Math_imul(i4, i6) | 0;
+ i5 = i2 >>> 16;
+ i4 = (i3 >>> 16) + (Math_imul(i4, i5) | 0) | 0;
+ i1 = i1 >>> 16;
+ i2 = Math_imul(i1, i6) | 0;
+ return (tempRet0 = (i4 >>> 16) + (Math_imul(i1, i5) | 0) + (((i4 & 65535) + i2 | 0) >>> 16) | 0, i4 + i2 << 16 | i3 & 65535 | 0) | 0;
+}
+function _str_dump(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 1056 | 0;
+ i3 = i2 + 8 | 0;
+ _luaL_checktype(i1, 1, 6);
+ _lua_settop(i1, 1);
+ _luaL_buffinit(i1, i3);
+ if ((_lua_dump(i1, 2, i3) | 0) == 0) {
+  _luaL_pushresult(i3);
+  i3 = 1;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  i3 = _luaL_error(i1, 7888, i2) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function ___memrchr(i2, i3, i5) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i3 = i3 & 255;
+ while (1) {
+  i4 = i5 + -1 | 0;
+  if ((i5 | 0) == 0) {
+   i5 = 0;
+   i2 = 4;
+   break;
+  }
+  i5 = i2 + i4 | 0;
+  if ((HEAP8[i5] | 0) == i3 << 24 >> 24) {
+   i2 = 4;
+   break;
+  } else {
+   i5 = i4;
+  }
+ }
+ if ((i2 | 0) == 4) {
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ return 0;
+}
+function _luaL_getsubtable(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_getfield(i1, i3, i4);
+ if ((_lua_type(i1, -1) | 0) == 5) {
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ _lua_settop(i1, -2);
+ i3 = _lua_absindex(i1, i3) | 0;
+ _lua_createtable(i1, 0, 0);
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, i3, i4);
+ i4 = 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _luaE_freeCI(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = (HEAP32[i1 + 16 >> 2] | 0) + 12 | 0;
+ i3 = HEAP32[i4 >> 2] | 0;
+ HEAP32[i4 >> 2] = 0;
+ if ((i3 | 0) == 0) {
+  STACKTOP = i2;
+  return;
+ }
+ while (1) {
+  i4 = HEAP32[i3 + 12 >> 2] | 0;
+  _luaM_realloc_(i1, i3, 40, 0) | 0;
+  if ((i4 | 0) == 0) {
+   break;
+  } else {
+   i3 = i4;
+  }
+ }
+ STACKTOP = i2;
+ return;
+}
+function _f_tostring(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ i4 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i4 + 4 >> 2] | 0) == 0) {
+  _lua_pushlstring(i1, 3040, 13) | 0;
+  STACKTOP = i2;
+  return 1;
+ } else {
+  HEAP32[i3 >> 2] = HEAP32[i4 >> 2];
+  _lua_pushfstring(i1, 3056, i3) | 0;
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _lua_newuserdata(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i3 = _luaS_newudata(i1, i3, 0) | 0;
+ i1 = i1 + 8 | 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i4 >> 2] = i3;
+ HEAP32[i4 + 8 >> 2] = 71;
+ HEAP32[i1 >> 2] = (HEAP32[i1 >> 2] | 0) + 16;
+ STACKTOP = i2;
+ return i3 + 24 | 0;
+}
+function _luaL_pushresultsize(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i5 = i1 + 8 | 0;
+ i4 = (HEAP32[i5 >> 2] | 0) + i3 | 0;
+ HEAP32[i5 >> 2] = i4;
+ i3 = HEAP32[i1 + 12 >> 2] | 0;
+ _lua_pushlstring(i3, HEAP32[i1 >> 2] | 0, i4) | 0;
+ if ((HEAP32[i1 >> 2] | 0) == (i1 + 16 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ _lua_remove(i3, -2);
+ STACKTOP = i2;
+ return;
+}
+function _luaL_testudata(i2, i5, i4) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = _lua_touserdata(i2, i5) | 0;
+ if ((i3 | 0) != 0 ? (_lua_getmetatable(i2, i5) | 0) != 0 : 0) {
+  _lua_getfield(i2, -1001e3, i4);
+  i5 = (_lua_rawequal(i2, -1, -2) | 0) == 0;
+  _lua_settop(i2, -3);
+  i2 = i5 ? 0 : i3;
+ } else {
+  i2 = 0;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _finishpcall(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_checkstack(i1, 1) | 0) == 0) {
+  _lua_settop(i1, 0);
+  _lua_pushboolean(i1, 0);
+  _lua_pushstring(i1, 9632) | 0;
+  i3 = 2;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _lua_pushboolean(i1, i3);
+  _lua_replace(i1, 1);
+  i3 = _lua_gettop(i1) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _searcher_preload(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ _lua_getfield(i1, -1001e3, 4592);
+ _lua_getfield(i1, -1, i3);
+ if ((_lua_type(i1, -1) | 0) != 0) {
+  STACKTOP = i2;
+  return 1;
+ }
+ HEAP32[i4 >> 2] = i3;
+ _lua_pushfstring(i1, 5096, i4) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_auxwrap(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i3 = STACKTOP;
+ i2 = _lua_tothread(i1, -1001001) | 0;
+ i2 = _auxresume(i1, i2, _lua_gettop(i1) | 0) | 0;
+ if ((i2 | 0) >= 0) {
+  STACKTOP = i3;
+  return i2 | 0;
+ }
+ if ((_lua_isstring(i1, -1) | 0) == 0) {
+  _lua_error(i1) | 0;
+ }
+ _luaL_where(i1, 1);
+ _lua_insert(i1, -2);
+ _lua_concat(i1, 2);
+ _lua_error(i1) | 0;
+ return 0;
+}
+function _ll_loadlib(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ i3 = _ll_loadfunc(i1, i3, _luaL_checklstring(i1, 2, 0) | 0) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 1;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_pushnil(i1);
+ _lua_insert(i1, -2);
+ _lua_pushstring(i1, (i3 | 0) == 1 ? 5176 : 5184) | 0;
+ i3 = 3;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaS_hash(i2, i4, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i5 = i3 ^ i4;
+ i3 = (i4 >>> 5) + 1 | 0;
+ if (i3 >>> 0 > i4 >>> 0) {
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ do {
+  i5 = (i5 << 5) + (i5 >>> 2) + (HEAPU8[i2 + (i4 + -1) | 0] | 0) ^ i5;
+  i4 = i4 - i3 | 0;
+ } while (!(i4 >>> 0 < i3 >>> 0));
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _b_and(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) < 1) {
+  i5 = -1;
+ } else {
+  i4 = 1;
+  i5 = -1;
+  while (1) {
+   i5 = (_luaL_checkunsigned(i1, i4) | 0) & i5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushunsigned(i1, i5);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaopen_string(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 14);
+ _luaL_setfuncs(i1, 6920, 0);
+ _lua_createtable(i1, 0, 1);
+ _lua_pushlstring(i1, 7040, 0) | 0;
+ _lua_pushvalue(i1, -2);
+ _lua_setmetatable(i1, -2) | 0;
+ _lua_settop(i1, -2);
+ _lua_pushvalue(i1, -2);
+ _lua_setfield(i1, -2, 7048);
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return 1;
+}
+function _b_xor(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) < 1) {
+  i5 = 0;
+ } else {
+  i4 = 1;
+  i5 = 0;
+  while (1) {
+   i5 = (_luaL_checkunsigned(i1, i4) | 0) ^ i5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushunsigned(i1, i5);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_assert(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((_lua_toboolean(i1, 1) | 0) == 0) {
+  HEAP32[i3 >> 2] = _luaL_optlstring(i1, 2, 10216, 0) | 0;
+  i3 = _luaL_error(i1, 10208, i3) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  i3 = _lua_gettop(i1) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _b_or(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) < 1) {
+  i5 = 0;
+ } else {
+  i4 = 1;
+  i5 = 0;
+  while (1) {
+   i5 = _luaL_checkunsigned(i1, i4) | 0 | i5;
+   if ((i4 | 0) == (i3 | 0)) {
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+   }
+  }
+ }
+ _lua_pushunsigned(i1, i5);
+ STACKTOP = i2;
+ return 1;
+}
+function _io_write(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ _lua_getfield(i1, -1001e3, 2800);
+ i3 = _lua_touserdata(i1, -1) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  HEAP32[i4 >> 2] = 2804;
+  _luaL_error(i1, 3424, i4) | 0;
+ }
+ i4 = _g_write(i1, HEAP32[i3 >> 2] | 0, 1) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _luaK_checkstack(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = (HEAPU8[i1 + 48 | 0] | 0) + i3 | 0;
+ i4 = (HEAP32[i1 >> 2] | 0) + 78 | 0;
+ if ((i3 | 0) <= (HEAPU8[i4] | 0 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ if ((i3 | 0) > 249) {
+  _luaX_syntaxerror(HEAP32[i1 + 12 >> 2] | 0, 10536);
+ }
+ HEAP8[i4] = i3;
+ STACKTOP = i2;
+ return;
+}
+function _io_read(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ _lua_getfield(i1, -1001e3, 2776);
+ i3 = _lua_touserdata(i1, -1) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  HEAP32[i4 >> 2] = 2780;
+  _luaL_error(i1, 3424, i4) | 0;
+ }
+ i4 = _g_read(i1, HEAP32[i3 >> 2] | 0, 1) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _db_setupvalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 3);
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 6);
+ i3 = _lua_setupvalue(i1, 1, i3) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_insert(i1, -1);
+ i3 = 1;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function ___uflow(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i1;
+ if ((HEAP32[i2 + 8 >> 2] | 0) == 0 ? (___toread(i2) | 0) != 0 : 0) {
+  i2 = -1;
+ } else {
+  if ((FUNCTION_TABLE_iiii[HEAP32[i2 + 32 >> 2] & 3](i2, i3, 1) | 0) == 1) {
+   i2 = HEAPU8[i3] | 0;
+  } else {
+   i2 = -1;
+  }
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _llvm_cttz_i32(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = HEAP8[cttz_i8 + (i1 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 | 0;
+ i2 = HEAP8[cttz_i8 + (i1 >> 8 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 + 8 | 0;
+ i2 = HEAP8[cttz_i8 + (i1 >> 16 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 + 16 | 0;
+ return (HEAP8[cttz_i8 + (i1 >>> 24) | 0] | 0) + 24 | 0;
+}
+function _llvm_ctlz_i32(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = HEAP8[ctlz_i8 + (i1 >>> 24) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 | 0;
+ i2 = HEAP8[ctlz_i8 + (i1 >> 16 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 + 8 | 0;
+ i2 = HEAP8[ctlz_i8 + (i1 >> 8 & 255) | 0] | 0;
+ if ((i2 | 0) < 8) return i2 + 16 | 0;
+ return (HEAP8[ctlz_i8 + (i1 & 255) | 0] | 0) + 24 | 0;
+}
+function _luaO_ceillog2(i2) {
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i4 = 0;
+ i1 = STACKTOP;
+ i2 = i2 + -1 | 0;
+ if (i2 >>> 0 > 255) {
+  i3 = 0;
+  while (1) {
+   i3 = i3 + 8 | 0;
+   i4 = i2 >>> 8;
+   if (i2 >>> 0 > 65535) {
+    i2 = i4;
+   } else {
+    i2 = i4;
+    break;
+   }
+  }
+ } else {
+  i3 = 0;
+ }
+ STACKTOP = i1;
+ return (HEAPU8[5208 + i2 | 0] | 0) + i3 | 0;
+}
+function _os_exit(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 1) {
+  i3 = (_lua_toboolean(i1, 1) | 0) == 0 | 0;
+ } else {
+  i3 = _luaL_optinteger(i1, 1, 0) | 0;
+ }
+ if ((_lua_toboolean(i1, 2) | 0) != 0) {
+  _lua_close(i1);
+ }
+ if ((i1 | 0) == 0) {
+  STACKTOP = i2;
+  return 0;
+ } else {
+  _exit(i3 | 0);
+ }
+ return 0;
+}
+function _luaL_newmetatable(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_getfield(i1, -1001e3, i3);
+ if ((_lua_type(i1, -1) | 0) != 0) {
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_settop(i1, -2);
+ _lua_createtable(i1, 0, 0);
+ _lua_pushvalue(i1, -1);
+ _lua_setfield(i1, -1001e3, i3);
+ i3 = 1;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaH_free(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i4 + 16 >> 2] | 0;
+ if ((i3 | 0) != 8016) {
+  _luaM_realloc_(i1, i3, 32 << (HEAPU8[i4 + 7 | 0] | 0), 0) | 0;
+ }
+ _luaM_realloc_(i1, HEAP32[i4 + 12 >> 2] | 0, HEAP32[i4 + 28 >> 2] << 4, 0) | 0;
+ _luaM_realloc_(i1, i4, 32, 0) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _luaO_int2fb(i3) {
+ i3 = i3 | 0;
+ var i1 = 0, i2 = 0, i4 = 0;
+ i1 = STACKTOP;
+ if (i3 >>> 0 < 8) {
+  STACKTOP = i1;
+  return i3 | 0;
+ }
+ if (i3 >>> 0 > 15) {
+  i2 = 1;
+  do {
+   i4 = i3 + 1 | 0;
+   i3 = i4 >>> 1;
+   i2 = i2 + 1 | 0;
+  } while (i4 >>> 0 > 31);
+  i2 = i2 << 3;
+ } else {
+  i2 = 8;
+ }
+ i4 = i2 | i3 + -8;
+ STACKTOP = i1;
+ return i4 | 0;
+}
+function _luaK_codek(i3, i4, i1) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = i4 << 6;
+ if ((i1 | 0) < 262144) {
+  i4 = _luaK_code(i3, i4 | i1 << 14 | 1) | 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  i4 = _luaK_code(i3, i4 | 2) | 0;
+  _luaK_code(i3, i1 << 6 | 39) | 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _luaB_xpcall(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_gettop(i1) | 0;
+ if ((i3 | 0) <= 1) {
+  _luaL_argerror(i1, 2, 9616) | 0;
+ }
+ _lua_pushvalue(i1, 1);
+ _lua_copy(i1, 2, 1);
+ _lua_replace(i1, 2);
+ i3 = _finishpcall(i1, (_lua_pcallk(i1, i3 + -2 | 0, -1, 1, 0, 166) | 0) == 0 | 0) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _luaS_newudata(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if (i3 >>> 0 > 4294967269) {
+  _luaM_toobig(i1);
+ } else {
+  i1 = _luaC_newobj(i1, 7, i3 + 24 | 0, 0, 0) | 0;
+  HEAP32[i1 + 16 >> 2] = i3;
+  HEAP32[i1 + 8 >> 2] = 0;
+  HEAP32[i1 + 12 >> 2] = i4;
+  STACKTOP = i2;
+  return i1 | 0;
+ }
+ return 0;
+}
+function _lua_dump(i1, i4, i5) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 8 >> 2] | 0;
+ if ((HEAP32[i3 + -8 >> 2] | 0) != 70) {
+  i5 = 1;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i5 = _luaU_dump(i1, HEAP32[(HEAP32[i3 + -16 >> 2] | 0) + 12 >> 2] | 0, i4, i5, 0) | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _luaS_eqlngstr(i2, i4) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = HEAP32[i2 + 12 >> 2] | 0;
+ if ((i2 | 0) != (i4 | 0)) {
+  if ((i3 | 0) == (HEAP32[i4 + 12 >> 2] | 0)) {
+   i2 = (_memcmp(i2 + 16 | 0, i4 + 16 | 0, i3) | 0) == 0;
+  } else {
+   i2 = 0;
+  }
+ } else {
+  i2 = 1;
+ }
+ STACKTOP = i1;
+ return i2 & 1 | 0;
+}
+function _luaC_barrier_(i4, i3, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = HEAP32[i4 + 12 >> 2] | 0;
+ if ((HEAPU8[i4 + 61 | 0] | 0) < 2) {
+  _reallymarkobject(i4, i1);
+  STACKTOP = i2;
+  return;
+ } else {
+  i3 = i3 + 5 | 0;
+  HEAP8[i3] = HEAP8[i4 + 60 | 0] & 3 | HEAP8[i3] & 184;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _db_getupvalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 6);
+ i3 = _lua_getupvalue(i1, 1, i3) | 0;
+ if ((i3 | 0) == 0) {
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ _lua_pushstring(i1, i3) | 0;
+ _lua_insert(i1, -2);
+ i3 = 2;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _os_execute(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i4 = _luaL_optlstring(i1, 1, 0, 0) | 0;
+ i3 = _system(i4 | 0) | 0;
+ if ((i4 | 0) == 0) {
+  _lua_pushboolean(i1, i3);
+  i4 = 1;
+  STACKTOP = i2;
+  return i4 | 0;
+ } else {
+  i4 = _luaL_execresult(i1, i3) | 0;
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ return 0;
+}
+function _lua_pushfstring(i4, i5, i1) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ if ((HEAP32[(HEAP32[i4 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i4);
+ }
+ HEAP32[i3 >> 2] = i1;
+ i5 = _luaO_pushvfstring(i4, i5, i3) | 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _luaB_dofile(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_optlstring(i1, 1, 0, 0) | 0;
+ _lua_settop(i1, 1);
+ if ((_luaL_loadfilex(i1, i3, 0) | 0) == 0) {
+  _lua_callk(i1, 0, -1, 0, 164);
+  i3 = (_lua_gettop(i1) | 0) + -1 | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _lua_error(i1) | 0;
+ }
+ return 0;
+}
+function _f_write(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i3 = HEAP32[i3 >> 2] | 0;
+ _lua_pushvalue(i1, 1);
+ i3 = _g_write(i1, i3, 2) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _lua_getctx(i3, i1) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i3 + 16 >> 2] | 0;
+ if ((HEAP8[i3 + 18 | 0] & 8) == 0) {
+  i3 = 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ if ((i1 | 0) != 0) {
+  HEAP32[i1 >> 2] = HEAP32[i3 + 24 >> 2];
+ }
+ i3 = HEAPU8[i3 + 37 | 0] | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _f_flush(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i3 = _luaL_fileresult(i1, (_fflush(HEAP32[i3 >> 2] | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _os_tmpname(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i3 = i2 + 4 | 0;
+ if ((_tmpnam(i3 | 0) | 0) == 0) {
+  i3 = _luaL_error(i1, 5824, i2) | 0;
+  STACKTOP = i2;
+  return i3 | 0;
+ } else {
+  _lua_pushstring(i1, i3) | 0;
+  i3 = 1;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ return 0;
+}
+function _traceback(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_tolstring(i1, 1, 0) | 0;
+ if ((i3 | 0) == 0) {
+  if ((_lua_type(i1, 1) | 0) >= 1 ? (_luaL_callmeta(i1, 1, 216) | 0) == 0 : 0) {
+   _lua_pushlstring(i1, 232, 18) | 0;
+  }
+ } else {
+  _luaL_traceback(i1, i1, i3, 1);
+ }
+ STACKTOP = i2;
+ return 1;
+}
+function _luaH_new(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _luaC_newobj(i1, 5, 32, 0, 0) | 0;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP8[i1 + 6 | 0] = -1;
+ HEAP32[i1 + 12 >> 2] = 0;
+ HEAP32[i1 + 28 >> 2] = 0;
+ HEAP32[i1 + 16 >> 2] = 8016;
+ HEAP8[i1 + 7 | 0] = 0;
+ HEAP32[i1 + 20 >> 2] = 8016;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaL_len(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2 + 4 | 0;
+ _lua_len(i1, i3);
+ i3 = _lua_tointegerx(i1, -1, i4) | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 1352, i2) | 0;
+ }
+ _lua_settop(i1, -2);
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _getS(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0, i5 = 0;
+ i3 = STACKTOP;
+ i5 = i2 + 4 | 0;
+ i4 = HEAP32[i5 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i3;
+  return i5 | 0;
+ }
+ HEAP32[i1 >> 2] = i4;
+ HEAP32[i5 >> 2] = 0;
+ i5 = HEAP32[i2 >> 2] | 0;
+ STACKTOP = i3;
+ return i5 | 0;
+}
+function _luaC_runtilstate(i1, i4) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = (HEAP32[i1 + 12 >> 2] | 0) + 61 | 0;
+ if ((1 << (HEAPU8[i3] | 0) & i4 | 0) != 0) {
+  STACKTOP = i2;
+  return;
+ }
+ do {
+  _singlestep(i1) | 0;
+ } while ((1 << (HEAPU8[i3] | 0) & i4 | 0) == 0);
+ STACKTOP = i2;
+ return;
+}
+function _luaX_init(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ i3 = 0;
+ do {
+  i4 = _luaS_new(i1, HEAP32[12096 + (i3 << 2) >> 2] | 0) | 0;
+  i5 = i4 + 5 | 0;
+  HEAP8[i5] = HEAPU8[i5] | 0 | 32;
+  i3 = i3 + 1 | 0;
+  HEAP8[i4 + 6 | 0] = i3;
+ } while ((i3 | 0) != 22);
+ STACKTOP = i2;
+ return;
+}
+function _luaK_indexed(i5, i1, i4) {
+ i5 = i5 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i3 = 0;
+ i3 = STACKTOP;
+ i2 = i1 + 8 | 0;
+ HEAP8[i2 + 2 | 0] = HEAP32[i2 >> 2];
+ HEAP16[i2 >> 1] = _luaK_exp2RK(i5, i4) | 0;
+ HEAP8[i2 + 3 | 0] = (HEAP32[i1 >> 2] | 0) == 8 ? 8 : 7;
+ HEAP32[i1 >> 2] = 9;
+ STACKTOP = i3;
+ return;
+}
+function _db_setuservalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 2) {
+  _luaL_argerror(i1, 1, 11680) | 0;
+ }
+ _luaL_checktype(i1, 1, 7);
+ if ((_lua_type(i1, 2) | 0) >= 1) {
+  _luaL_checktype(i1, 2, 5);
+ }
+ _lua_settop(i1, 2);
+ _lua_setuservalue(i1, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _ll_seeall(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ if ((_lua_getmetatable(i1, 1) | 0) == 0) {
+  _lua_createtable(i1, 0, 1);
+  _lua_pushvalue(i1, -1);
+  _lua_setmetatable(i1, 1) | 0;
+ }
+ _lua_rawgeti(i1, -1001e3, 2);
+ _lua_setfield(i1, -2, 5168);
+ STACKTOP = i2;
+ return 0;
+}
+function _luaL_loadbufferx(i3, i5, i4, i2, i1) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i6 = 0, i7 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i7 = i6;
+ HEAP32[i7 >> 2] = i5;
+ HEAP32[i7 + 4 >> 2] = i4;
+ i5 = _lua_load(i3, 2, i7, i2, i1) | 0;
+ STACKTOP = i6;
+ return i5 | 0;
+}
+function _luaT_gettm(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i4 = _luaH_getstr(i1, i4) | 0;
+ if ((HEAP32[i4 + 8 >> 2] | 0) != 0) {
+  STACKTOP = i2;
+  return i4 | 0;
+ }
+ i4 = i1 + 6 | 0;
+ HEAP8[i4] = HEAPU8[i4] | 0 | 1 << i3;
+ i4 = 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _luaL_pushresult(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 12 >> 2] | 0;
+ _lua_pushlstring(i3, HEAP32[i1 >> 2] | 0, HEAP32[i1 + 8 >> 2] | 0) | 0;
+ if ((HEAP32[i1 >> 2] | 0) == (i1 + 16 | 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ _lua_remove(i3, -2);
+ STACKTOP = i2;
+ return;
+}
+function _resume_error(i1, i3, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ var i4 = 0;
+ i4 = i1 + 8 | 0;
+ HEAP32[i4 >> 2] = i2;
+ i3 = _luaS_new(i1, i3) | 0;
+ HEAP32[i2 >> 2] = i3;
+ HEAP32[i2 + 8 >> 2] = HEAPU8[i3 + 4 | 0] | 0 | 64;
+ HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + 16;
+ _luaD_throw(i1, -1);
+}
+function _lua_absindex(i3, i1) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((i1 + 1000999 | 0) >>> 0 > 1000999) {
+  i3 = i1;
+  STACKTOP = i2;
+  return i3 | 0;
+ }
+ i3 = ((HEAP32[i3 + 8 >> 2] | 0) - (HEAP32[HEAP32[i3 + 16 >> 2] >> 2] | 0) >> 4) + i1 | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function ___uremdi3(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i5 = 0, i6 = 0;
+ i6 = STACKTOP;
+ STACKTOP = STACKTOP + 8 | 0;
+ i5 = i6 | 0;
+ ___udivmoddi4(i4, i3, i2, i1, i5) | 0;
+ STACKTOP = i6;
+ return (tempRet0 = HEAP32[i5 + 4 >> 2] | 0, HEAP32[i5 >> 2] | 0) | 0;
+}
+function _f_read(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = _luaL_checkudata(i1, 1, 2832) | 0;
+ if ((HEAP32[i3 + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ i3 = _g_read(i1, HEAP32[i3 >> 2] | 0, 2) | 0;
+ STACKTOP = i2;
+ return i3 | 0;
+}
+function _sort(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ i3 = _luaL_len(i1, 1) | 0;
+ _luaL_checkstack(i1, 40, 8208);
+ if ((_lua_type(i1, 2) | 0) >= 1) {
+  _luaL_checktype(i1, 2, 6);
+ }
+ _lua_settop(i1, 2);
+ _auxsort(i1, 1, i3);
+ STACKTOP = i2;
+ return 0;
+}
+function _luaB_error(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = _luaL_optinteger(i1, 2, 1) | 0;
+ _lua_settop(i1, 1);
+ if (!((_lua_isstring(i1, 1) | 0) != 0 & (i2 | 0) > 0)) {
+  _lua_error(i1) | 0;
+ }
+ _luaL_where(i1, i2);
+ _lua_pushvalue(i1, 1);
+ _lua_concat(i1, 2);
+ _lua_error(i1) | 0;
+ return 0;
+}
+function _error(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i3 >> 2] = HEAP32[i1 + 12 >> 2];
+ HEAP32[i3 + 4 >> 2] = i2;
+ _luaO_pushfstring(i4, 8840, i3) | 0;
+ _luaD_throw(HEAP32[i1 >> 2] | 0, 3);
+}
+function _ipairsaux(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ _luaL_checktype(i1, 1, 5);
+ i3 = i3 + 1 | 0;
+ _lua_pushinteger(i1, i3);
+ _lua_rawgeti(i1, 1, i3);
+ i1 = (_lua_type(i1, -1) | 0) == 0;
+ STACKTOP = i2;
+ return (i1 ? 1 : 2) | 0;
+}
+function _panic(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ i3 = HEAP32[_stderr >> 2] | 0;
+ HEAP32[i4 >> 2] = _lua_tolstring(i1, -1, 0) | 0;
+ _fprintf(i3 | 0, 1656, i4 | 0) | 0;
+ _fflush(i3 | 0) | 0;
+ STACKTOP = i2;
+ return 0;
+}
+function _testSetjmp(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0;
+ while ((i3 | 0) < 20) {
+  i4 = HEAP32[i2 + (i3 << 2) >> 2] | 0;
+  if ((i4 | 0) == 0) break;
+  if ((i4 | 0) == (i1 | 0)) {
+   return HEAP32[i2 + ((i3 << 2) + 4) >> 2] | 0;
+  }
+  i3 = i3 + 2 | 0;
+ }
+ return 0;
+}
+function _luaopen_math(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 28);
+ _luaL_setfuncs(i1, 3576, 0);
+ _lua_pushnumber(i1, 3.141592653589793);
+ _lua_setfield(i1, -2, 3808);
+ _lua_pushnumber(i1, inf);
+ _lua_setfield(i1, -2, 3816);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaopen_base(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_rawgeti(i1, -1001e3, 2);
+ _lua_rawgeti(i1, -1001e3, 2);
+ _lua_setfield(i1, -2, 9144);
+ _luaL_setfuncs(i1, 9152, 0);
+ _lua_pushlstring(i1, 9344, 7) | 0;
+ _lua_setfield(i1, -2, 9352);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaE_extendCI(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i3 = STACKTOP;
+ i2 = _luaM_realloc_(i1, 0, 0, 40) | 0;
+ i1 = i1 + 16 | 0;
+ HEAP32[(HEAP32[i1 >> 2] | 0) + 12 >> 2] = i2;
+ HEAP32[i2 + 8 >> 2] = HEAP32[i1 >> 2];
+ HEAP32[i2 + 12 >> 2] = 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaB_getmetatable(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ if ((_lua_getmetatable(i1, 1) | 0) == 0) {
+  _lua_pushnil(i1);
+  STACKTOP = i2;
+  return 1;
+ } else {
+  _luaL_getmetafield(i1, 1, 9704) | 0;
+  STACKTOP = i2;
+  return 1;
+ }
+ return 0;
+}
+function _lua_pushunsigned(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var d3 = 0.0;
+ if ((i2 | 0) > -1) {
+  d3 = +(i2 | 0);
+ } else {
+  d3 = +(i2 >>> 0);
+ }
+ i2 = i1 + 8 | 0;
+ i1 = HEAP32[i2 >> 2] | 0;
+ HEAPF64[i1 >> 3] = d3;
+ HEAP32[i1 + 8 >> 2] = 3;
+ HEAP32[i2 >> 2] = i1 + 16;
+ return;
+}
+function _lua_pushthread(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = i1 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i3 >> 2] = i1;
+ HEAP32[i3 + 8 >> 2] = 72;
+ HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + 16;
+ return (HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 172 >> 2] | 0) == (i1 | 0) | 0;
+}
+function _gctm(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_len(i1, 1) | 0;
+ if ((i3 | 0) <= 0) {
+  STACKTOP = i2;
+  return 0;
+ }
+ do {
+  _lua_rawgeti(i1, 1, i3);
+  _lua_settop(i1, -2);
+  i3 = i3 + -1 | 0;
+ } while ((i3 | 0) > 0);
+ STACKTOP = i2;
+ return 0;
+}
+function ___muldi3(i4, i2, i3, i1) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0, i6 = 0;
+ i5 = i4;
+ i6 = i3;
+ i4 = ___muldsi3(i5, i6) | 0;
+ i3 = tempRet0;
+ return (tempRet0 = (Math_imul(i2, i6) | 0) + (Math_imul(i1, i5) | 0) + i3 | i3 & 0, i4 | 0 | 0) | 0;
+}
+function _luaH_resizearray(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i5 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[i3 + 16 >> 2] | 0) == 8016) {
+  i5 = 0;
+ } else {
+  i5 = 1 << (HEAPU8[i3 + 7 | 0] | 0);
+ }
+ _luaH_resize(i1, i3, i4, i5);
+ STACKTOP = i2;
+ return;
+}
+function _luaK_stringK(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i3;
+ HEAP32[i4 >> 2] = i2;
+ HEAP32[i4 + 8 >> 2] = HEAPU8[i2 + 4 | 0] | 0 | 64;
+ i2 = _addk(i1, i4, i4) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _math_modf(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i2;
+ d3 = +_modf(+(+_luaL_checknumber(i1, 1)), i4 | 0);
+ _lua_pushnumber(i1, +HEAPF64[i4 >> 3]);
+ _lua_pushnumber(i1, d3);
+ STACKTOP = i2;
+ return 2;
+}
+function _os_setlocale(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_optlstring(i1, 1, 0, 0) | 0;
+ _lua_pushstring(i1, _setlocale(HEAP32[5960 + ((_luaL_checkoption(i1, 2, 6016, 5984) | 0) << 2) >> 2] | 0, i3 | 0) | 0) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_pcall(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ _lua_pushnil(i1);
+ _lua_insert(i1, 1);
+ i1 = _finishpcall(i1, (_lua_pcallk(i1, (_lua_gettop(i1) | 0) + -2 | 0, -1, 0, 0, 166) | 0) == 0 | 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _error_expected(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0, i4 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = HEAP32[i1 + 52 >> 2] | 0;
+ HEAP32[i3 >> 2] = _luaX_token2str(i1, i2) | 0;
+ _luaX_syntaxerror(i1, _luaO_pushfstring(i4, 6328, i3) | 0);
+}
+function _lua_pushvfstring(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 12 >> 2] | 0) > 0) {
+  _luaC_step(i1);
+ }
+ i4 = _luaO_pushvfstring(i1, i3, i4) | 0;
+ STACKTOP = i2;
+ return i4 | 0;
+}
+function _db_setmetatable(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _lua_type(i1, 2) | 0;
+ if (!((i3 | 0) == 0 | (i3 | 0) == 5)) {
+  _luaL_argerror(i1, 2, 11536) | 0;
+ }
+ _lua_settop(i1, 2);
+ _lua_setmetatable(i1, 1) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _b_rrot(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = 0 - (_luaL_checkinteger(i1, 2) | 0) | 0;
+ i4 = _luaL_checkunsigned(i1, 1) | 0;
+ i3 = i3 & 31;
+ _lua_pushunsigned(i1, i4 >>> (32 - i3 | 0) | i4 << i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaC_step(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = HEAP32[i1 + 12 >> 2] | 0;
+ if ((HEAP8[i3 + 63 | 0] | 0) == 0) {
+  _luaE_setdebt(i3, -1600);
+  STACKTOP = i2;
+  return;
+ } else {
+  _luaC_forcestep(i1);
+  STACKTOP = i2;
+  return;
+ }
+}
+function _math_frexp(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ _lua_pushnumber(i1, +_frexp(+(+_luaL_checknumber(i1, 1)), i3 | 0));
+ _lua_pushinteger(i1, HEAP32[i3 >> 2] | 0);
+ STACKTOP = i2;
+ return 2;
+}
+function _luaO_pushfstring(i2, i1, i3) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i4 = 0, i5 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i5 = i4;
+ HEAP32[i5 >> 2] = i3;
+ i3 = _luaO_pushvfstring(i2, i1, i5) | 0;
+ STACKTOP = i4;
+ return i3 | 0;
+}
+function _luaO_hexavalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((HEAP8[i1 + 10913 | 0] & 2) == 0) {
+  i1 = (i1 | 32) + -87 | 0;
+  STACKTOP = i2;
+  return i1 | 0;
+ } else {
+  i1 = i1 + -48 | 0;
+  STACKTOP = i2;
+  return i1 | 0;
+ }
+ return 0;
+}
+function _b_lrot(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checkinteger(i1, 2) | 0;
+ i4 = _luaL_checkunsigned(i1, 1) | 0;
+ i3 = i3 & 31;
+ _lua_pushunsigned(i1, i4 >>> (32 - i3 | 0) | i4 << i3);
+ STACKTOP = i2;
+ return 1;
+}
+function _f_lines(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ if ((HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) + 4 >> 2] | 0) == 0) {
+  _luaL_error(i1, 3080, i2) | 0;
+ }
+ _aux_lines(i1, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaC_barrierback_(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i2 = HEAP32[i2 + 12 >> 2] | 0;
+ i3 = i1 + 5 | 0;
+ HEAP8[i3] = HEAP8[i3] & 251;
+ i2 = i2 + 88 | 0;
+ HEAP32[i1 + 24 >> 2] = HEAP32[i2 >> 2];
+ HEAP32[i2 >> 2] = i1;
+ return;
+}
+function _os_rename(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ i1 = _luaL_fileresult(i1, (_rename(i3 | 0, _luaL_checklstring(i1, 2, 0) | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _bitshift64Ashr(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ if ((i1 | 0) < 32) {
+  tempRet0 = i2 >> i1;
+  return i3 >>> i1 | (i2 & (1 << i1) - 1) << 32 - i1;
+ }
+ tempRet0 = (i2 | 0) < 0 ? -1 : 0;
+ return i2 >> i1 - 32 | 0;
+}
+function _luaB_cowrap(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 6);
+ i3 = _lua_newthread(i1) | 0;
+ _lua_pushvalue(i1, 1);
+ _lua_xmove(i1, i3, 1);
+ _lua_pushcclosure(i1, 167, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _gmatch(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checklstring(i1, 1, 0) | 0;
+ _luaL_checklstring(i1, 2, 0) | 0;
+ _lua_settop(i1, 2);
+ _lua_pushinteger(i1, 0);
+ _lua_pushcclosure(i1, 163, 3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_next(i2) {
+ i2 = i2 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ _luaL_checktype(i2, 1, 5);
+ _lua_settop(i2, 2);
+ if ((_lua_next(i2, 1) | 0) == 0) {
+  _lua_pushnil(i2);
+  i2 = 1;
+ } else {
+  i2 = 2;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _luaK_codeABC(i5, i3, i4, i2, i1) {
+ i5 = i5 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i6 = 0;
+ i6 = STACKTOP;
+ i5 = _luaK_code(i5, i4 << 6 | i3 | i2 << 23 | i1 << 14) | 0;
+ STACKTOP = i6;
+ return i5 | 0;
+}
+function _luaH_set(i2, i4, i5) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0;
+ i1 = STACKTOP;
+ i3 = _luaH_get(i4, i5) | 0;
+ if ((i3 | 0) == 5192) {
+  i3 = _luaH_newkey(i2, i4, i5) | 0;
+ }
+ STACKTOP = i1;
+ return i3 | 0;
+}
+function _luaZ_init(i4, i1, i3, i2) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ HEAP32[i1 + 16 >> 2] = i4;
+ HEAP32[i1 + 8 >> 2] = i3;
+ HEAP32[i1 + 12 >> 2] = i2;
+ HEAP32[i1 >> 2] = 0;
+ HEAP32[i1 + 4 >> 2] = 0;
+ return;
+}
+function _lua_pushlightuserdata(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i2 = i2 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i3 >> 2] = i1;
+ HEAP32[i3 + 8 >> 2] = 2;
+ HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + 16;
+ return;
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function _bitshift64Shl(i2, i3, i1) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ if ((i1 | 0) < 32) {
+  tempRet0 = i3 << i1 | (i2 & (1 << i1) - 1 << 32 - i1) >>> 32 - i1;
+  return i2 << i1;
+ }
+ tempRet0 = i2 << i1 - 32;
+ return 0;
+}
+function _luaB_rawlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if (((_lua_type(i1, 1) | 0) & -2 | 0) != 4) {
+  _luaL_argerror(i1, 1, 9784) | 0;
+ }
+ _lua_pushinteger(i1, _lua_rawlen(i1, 1) | 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _l_alloc(i3, i1, i4, i2) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i3 = STACKTOP;
+ if ((i2 | 0) == 0) {
+  _free(i1);
+  i1 = 0;
+ } else {
+  i1 = _realloc(i1, i2) | 0;
+ }
+ STACKTOP = i3;
+ return i1 | 0;
+}
+function _bitshift64Lshr(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ if ((i1 | 0) < 32) {
+  tempRet0 = i2 >>> i1;
+  return i3 >>> i1 | (i2 & (1 << i1) - 1) << 32 - i1;
+ }
+ tempRet0 = 0;
+ return i2 >>> i1 - 32 | 0;
+}
+function _luaG_aritherror(i3, i1, i2) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i4 = 0;
+ i4 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = (_luaV_tonumber(i1, i4) | 0) == 0;
+ _luaG_typeerror(i3, i4 ? i1 : i2, 1928);
+}
+function _str_len(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i3 = i2;
+ _luaL_checklstring(i1, 1, i3) | 0;
+ _lua_pushinteger(i1, HEAP32[i3 >> 2] | 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaL_optinteger(i3, i4, i2) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0;
+ i1 = STACKTOP;
+ if ((_lua_type(i3, i4) | 0) >= 1) {
+  i2 = _luaL_checkinteger(i3, i4) | 0;
+ }
+ STACKTOP = i1;
+ return i2 | 0;
+}
+function _os_difftime(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = ~~+_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +_difftime(i3 | 0, ~~+_luaL_optnumber(i1, 2, 0.0) | 0));
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_pushboolean(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i2 = i2 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAP32[i3 >> 2] = (i1 | 0) != 0;
+ HEAP32[i3 + 8 >> 2] = 1;
+ HEAP32[i2 >> 2] = i3 + 16;
+ return;
+}
+function _os_remove(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = _luaL_checklstring(i1, 1, 0) | 0;
+ i1 = _luaL_fileresult(i1, (_remove(i3 | 0) | 0) == 0 | 0, i3) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaopen_table(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 7);
+ _luaL_setfuncs(i1, 8088, 0);
+ _lua_getfield(i1, -1, 8152);
+ _lua_setglobal(i1, 8152);
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_pushinteger(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i2 = i2 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAPF64[i3 >> 3] = +(i1 | 0);
+ HEAP32[i3 + 8 >> 2] = 3;
+ HEAP32[i2 >> 2] = i3 + 16;
+ return;
+}
+function _luaB_rawset(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ _luaL_checkany(i1, 2);
+ _luaL_checkany(i1, 3);
+ _lua_settop(i1, 3);
+ _lua_rawset(i1, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaE_setdebt(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = i2 + 12 | 0;
+ i2 = i2 + 8 | 0;
+ HEAP32[i2 >> 2] = (HEAP32[i3 >> 2] | 0) - i1 + (HEAP32[i2 >> 2] | 0);
+ HEAP32[i3 >> 2] = i1;
+ return;
+}
+function _luaB_cocreate(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 6);
+ i3 = _lua_newthread(i1) | 0;
+ _lua_pushvalue(i1, 1);
+ _lua_xmove(i1, i3, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _io_noclose(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) + 4 >> 2] = 154;
+ _lua_pushnil(i1);
+ _lua_pushlstring(i1, 2840, 26) | 0;
+ STACKTOP = i2;
+ return 2;
+}
+function _io_fclose(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _luaL_fileresult(i1, (_fclose(HEAP32[(_luaL_checkudata(i1, 1, 2832) | 0) >> 2] | 0) | 0) == 0 | 0, 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaL_optnumber(i3, i4, d2) {
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ d2 = +d2;
+ var i1 = 0;
+ i1 = STACKTOP;
+ if ((_lua_type(i3, i4) | 0) >= 1) {
+  d2 = +_luaL_checknumber(i3, i4);
+ }
+ STACKTOP = i1;
+ return +d2;
+}
+function _math_atan2(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +Math_atan2(+d3, +(+_luaL_checknumber(i1, 2))));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaK_codeABx(i4, i2, i3, i1) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ i4 = _luaK_code(i4, i3 << 6 | i2 | i1 << 14) | 0;
+ STACKTOP = i5;
+ return i4 | 0;
+}
+function _luaF_newCclosure(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = _luaC_newobj(i2, 38, (i1 << 4) + 16 | 0, 0, 0) | 0;
+ HEAP8[i2 + 6 | 0] = i1;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _math_pow(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +Math_pow(+d3, +(+_luaL_checknumber(i1, 2))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_ldexp(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +_ldexp(d3, _luaL_checkinteger(i1, 2) | 0));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaF_newupval(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _luaC_newobj(i1, 10, 32, 0, 0) | 0;
+ HEAP32[i1 + 8 >> 2] = i1 + 16;
+ HEAP32[i1 + 24 >> 2] = 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _lua_pushnumber(i2, d1) {
+ i2 = i2 | 0;
+ d1 = +d1;
+ var i3 = 0;
+ i2 = i2 + 8 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ HEAPF64[i3 >> 3] = d1;
+ HEAP32[i3 + 8 >> 2] = 3;
+ HEAP32[i2 >> 2] = i3 + 16;
+ return;
+}
+function _math_fmod(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, d3 = 0.0;
+ i2 = STACKTOP;
+ d3 = +_luaL_checknumber(i1, 1);
+ _lua_pushnumber(i1, +_fmod(+d3, +(+_luaL_checknumber(i1, 2))));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaG_concaterror(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ i4 = HEAP32[i2 + 8 >> 2] | 0;
+ _luaG_typeerror(i3, (i4 & 15 | 0) == 4 | (i4 | 0) == 3 ? i1 : i2, 1912);
+}
+function _luaB_rawequal(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ _luaL_checkany(i1, 2);
+ _lua_pushboolean(i1, _lua_rawequal(i1, 1, 2) | 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _db_getuservalue(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, 1) | 0) == 7) {
+  _lua_getuservalue(i1, 1);
+ } else {
+  _lua_pushnil(i1);
+ }
+ STACKTOP = i2;
+ return 1;
+}
+function _strchr(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = ___strchrnul(i2, i1) | 0;
+ STACKTOP = i3;
+ return ((HEAP8[i2] | 0) == (i1 & 255) << 24 >> 24 ? i2 : 0) | 0;
+}
+function runPostSets() {}
+function _rand_r(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = (Math_imul(HEAP32[i1 >> 2] | 0, 31010991) | 0) + 1735287159 & 2147483647;
+ HEAP32[i1 >> 2] = i2;
+ return i2 | 0;
+}
+function _luaL_checkany(i1, i3) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ if ((_lua_type(i1, i3) | 0) == -1) {
+  _luaL_argerror(i1, i3, 1256) | 0;
+ }
+ STACKTOP = i2;
+ return;
+}
+function _i64Subtract(i2, i4, i1, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 - i3 - (i1 >>> 0 > i2 >>> 0 | 0) >>> 0;
+ return (tempRet0 = i4, i2 - i1 >>> 0 | 0) | 0;
+}
+function _db_getmetatable(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ if ((_lua_getmetatable(i1, 1) | 0) == 0) {
+  _lua_pushnil(i1);
+ }
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_rawget(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checktype(i1, 1, 5);
+ _luaL_checkany(i1, 2);
+ _lua_settop(i1, 2);
+ _lua_rawget(i1, 1);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_type(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ _lua_pushstring(i1, _lua_typename(i1, _lua_type(i1, 1) | 0) | 0) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function dynCall_iiiii(i5, i4, i3, i2, i1) {
+ i5 = i5 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiiii[i5 & 3](i4 | 0, i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function _lstop(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ _lua_sethook(i1, 0, 0, 0) | 0;
+ _luaL_error(i1, 200, i2) | 0;
+ STACKTOP = i2;
+ return;
+}
+function _i64Add(i1, i3, i4, i2) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i4 = i1 + i4 >>> 0;
+ return (tempRet0 = i3 + i2 + (i4 >>> 0 < i1 >>> 0 | 0) >>> 0, i4 | 0) | 0;
+}
+function _luaK_ret(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ i4 = STACKTOP;
+ _luaK_code(i3, i2 << 6 | (i1 << 23) + 8388608 | 31) | 0;
+ STACKTOP = i4;
+ return;
+}
+function _strpbrk(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i1 = i2 + (_strcspn(i2, i1) | 0) | 0;
+ STACKTOP = i3;
+ return ((HEAP8[i1] | 0) != 0 ? i1 : 0) | 0;
+}
+function _luaL_setmetatable(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _lua_getfield(i1, -1001e3, i2);
+ _lua_setmetatable(i1, -2) | 0;
+ STACKTOP = i3;
+ return;
+}
+function _lua_atpanic(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = (HEAP32[i2 + 12 >> 2] | 0) + 168 | 0;
+ i2 = HEAP32[i3 >> 2] | 0;
+ HEAP32[i3 >> 2] = i1;
+ return i2 | 0;
+}
+function _luaL_newstate() {
+ var i1 = 0, i2 = 0;
+ i2 = STACKTOP;
+ i1 = _lua_newstate(1, 0) | 0;
+ if ((i1 | 0) != 0) {
+  _lua_atpanic(i1, 143) | 0;
+ }
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaL_buffinit(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ HEAP32[i1 + 12 >> 2] = i2;
+ HEAP32[i1 >> 2] = i1 + 16;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP32[i1 + 4 >> 2] = 1024;
+ return;
+}
+function _strrchr(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = ___memrchr(i1, i2, (_strlen(i1 | 0) | 0) + 1 | 0) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _luaK_fixline(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ HEAP32[(HEAP32[(HEAP32[i1 >> 2] | 0) + 20 >> 2] | 0) + ((HEAP32[i1 + 20 >> 2] | 0) + -1 << 2) >> 2] = i2;
+ return;
+}
+function _luaX_lookahead(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i3 = STACKTOP;
+ i2 = _llex(i1, i1 + 40 | 0) | 0;
+ HEAP32[i1 + 32 >> 2] = i2;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _f_call(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _luaD_call(i2, HEAP32[i1 >> 2] | 0, HEAP32[i1 + 4 >> 2] | 0, 0);
+ STACKTOP = i3;
+ return;
+}
+function _io_pclose(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkudata(i1, 1, 2832) | 0;
+ i1 = _luaL_execresult(i1, -1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaS_new(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = _luaS_newlstr(i2, i1, _strlen(i1 | 0) | 0) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _os_getenv(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushstring(i1, _getenv(_luaL_checklstring(i1, 1, 0) | 0) | 0) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _math_rad(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_luaL_checknumber(i1, 1) * .017453292519943295);
+ STACKTOP = i2;
+ return 1;
+}
+function _math_deg(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_luaL_checknumber(i1, 1) / .017453292519943295);
+ STACKTOP = i2;
+ return 1;
+}
+function _writer(i4, i2, i1, i3) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = STACKTOP;
+ _luaL_addlstring(i3, i2, i1);
+ STACKTOP = i4;
+ return 0;
+}
+function _luaL_addstring(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _luaL_addlstring(i2, i1, _strlen(i1 | 0) | 0);
+ STACKTOP = i3;
+ return;
+}
+function _pcallcont(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _finishpcall(i1, (_lua_getctx(i1, 0) | 0) == 1 | 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaopen_coroutine(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 6);
+ _luaL_setfuncs(i1, 10656, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_version(i1) {
+ i1 = i1 | 0;
+ if ((i1 | 0) == 0) {
+  i1 = 920;
+ } else {
+  i1 = HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 176 >> 2] | 0;
+ }
+ return i1 | 0;
+}
+function _lua_pushnil(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i1 = i1 + 8 | 0;
+ i2 = HEAP32[i1 >> 2] | 0;
+ HEAP32[i2 + 8 >> 2] = 0;
+ HEAP32[i1 >> 2] = i2 + 16;
+ return;
+}
+function _math_floor(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_floor(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _laction(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _signal(i1 | 0, 0) | 0;
+ _lua_sethook(HEAP32[48] | 0, 1, 11, 1) | 0;
+ STACKTOP = i2;
+ return;
+}
+function dynCall_iiii(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiii[i4 & 3](i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function _luaopen_debug(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 16);
+ _luaL_setfuncs(i1, 11176, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaopen_bit32(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 12);
+ _luaL_setfuncs(i1, 10240, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _math_sqrt(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_sqrt(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_ceil(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_ceil(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_atan(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_atan(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_asin(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_asin(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_acos(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_acos(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _lua_close(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _close_state(HEAP32[(HEAP32[i1 + 12 >> 2] | 0) + 172 >> 2] | 0);
+ STACKTOP = i2;
+ return;
+}
+function _dothecall(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i2 = STACKTOP;
+ _luaD_call(i1, (HEAP32[i1 + 8 >> 2] | 0) + -32 | 0, 0, 0);
+ STACKTOP = i2;
+ return;
+}
+function _math_tan(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_tan(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_sin(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_sin(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_log10(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_log10(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_exp(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_exp(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_cos(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_cos(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_abs(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +Math_abs(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_randomseed(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _srand(_luaL_checkunsigned(i1, 1) | 0);
+ _rand() | 0;
+ STACKTOP = i2;
+ return 0;
+}
+function _luaopen_os(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_createtable(i1, 0, 11);
+ _luaL_setfuncs(i1, 5624, 0);
+ STACKTOP = i2;
+ return 1;
+}
+function _math_tanh(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_tanh(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_sinh(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_sinh(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _math_cosh(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +_cosh(+(+_luaL_checknumber(i1, 1))));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_yield(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _lua_yieldk(i1, _lua_gettop(i1) | 0, 0, 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaB_tostring(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _luaL_checkany(i1, 1);
+ _luaL_tolstring(i1, 1, 0) | 0;
+ STACKTOP = i2;
+ return 1;
+}
+function _growstack(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ _luaD_growstack(i2, HEAP32[i1 >> 2] | 0);
+ STACKTOP = i3;
+ return;
+}
+function ___udivdi3(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i4 = ___udivmoddi4(i4, i3, i2, i1, 0) | 0;
+ return i4 | 0;
+}
+function _b_not(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushunsigned(i1, ~(_luaL_checkunsigned(i1, 1) | 0));
+ STACKTOP = i2;
+ return 1;
+}
+function _luaO_fb2int(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1 >>> 3 & 31;
+ if ((i2 | 0) != 0) {
+  i1 = (i1 & 7 | 8) << i2 + -1;
+ }
+ return i1 | 0;
+}
+function _luaB_corunning(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushboolean(i1, _lua_pushthread(i1) | 0);
+ STACKTOP = i2;
+ return 2;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function _strcoll(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ i2 = _strcmp(i2, i1) | 0;
+ STACKTOP = i3;
+ return i2 | 0;
+}
+function _os_clock(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushnumber(i1, +(_clock() | 0) / 1.0e6);
+ STACKTOP = i2;
+ return 1;
+}
+function _dofilecont(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = (_lua_gettop(i1) | 0) + -1 | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _scalbnl(d2, i1) {
+ d2 = +d2;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ d2 = +_scalbn(d2, i1);
+ STACKTOP = i3;
+ return +d2;
+}
+function _tolower(i1) {
+ i1 = i1 | 0;
+ if ((i1 | 0) < 65) return i1 | 0;
+ if ((i1 | 0) > 90) return i1 | 0;
+ return i1 - 65 + 97 | 0;
+}
+function _lua_gettop(i1) {
+ i1 = i1 | 0;
+ return (HEAP32[i1 + 8 >> 2] | 0) - ((HEAP32[HEAP32[i1 + 16 >> 2] >> 2] | 0) + 16) >> 4 | 0;
+}
+function dynCall_iii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iii[i3 & 1](i2 | 0, i1 | 0) | 0;
+}
+function _str_match(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _str_find_aux(i1, 0) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _luaM_toobig(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ _luaG_runerror(i1, 4144, i2);
+}
+function _luaK_getlabel(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = HEAP32[i1 + 20 >> 2] | 0;
+ HEAP32[i1 + 24 >> 2] = i2;
+ return i2 | 0;
+}
+function _ldexp(d2, i1) {
+ d2 = +d2;
+ i1 = i1 | 0;
+ var i3 = 0;
+ i3 = STACKTOP;
+ d2 = +_scalbn(d2, i1);
+ STACKTOP = i3;
+ return +d2;
+}
+function _str_find(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ i1 = _str_find_aux(i1, 1) | 0;
+ STACKTOP = i2;
+ return i1 | 0;
+}
+function _db_getregistry(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _lua_pushvalue(i1, -1001e3);
+ STACKTOP = i2;
+ return 1;
+}
+function _luaB_ipairs(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _pairsmeta(i1, 9960, 1, 165);
+ STACKTOP = i2;
+ return 3;
+}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function _luaB_pairs(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _pairsmeta(i1, 9864, 0, 93);
+ STACKTOP = i2;
+ return 3;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function _io_output(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _g_iofile(i1, 2800, 3512);
+ STACKTOP = i2;
+ return 1;
+}
+function dynCall_vii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vii[i3 & 15](i2 | 0, i1 | 0);
+}
+function _io_input(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ _g_iofile(i1, 2776, 3480);
+ STACKTOP = i2;
+ return 1;
+}
+function _semerror(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ _luaX_syntaxerror(i2, i1);
+}
+function _luaX_syntaxerror(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ _lexerror(i1, i2, HEAP32[i1 + 16 >> 2] | 0);
+}
+function b4(i1, i2, i3, i4) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ abort(4);
+ return 0;
+}
+function _lua_typename(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return HEAP32[8528 + (i1 + 1 << 2) >> 2] | 0;
+}
+function dynCall_ii(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_ii[i2 & 255](i1 | 0) | 0;
+}
+function dynCall_vi(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vi[i2 & 1](i1 | 0);
+}
+function b0(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ abort(0);
+ return 0;
+}
+function _lua_gethookmask(i1) {
+ i1 = i1 | 0;
+ return HEAPU8[i1 + 40 | 0] | 0 | 0;
+}
+function _lua_gethookcount(i1) {
+ i1 = i1 | 0;
+ return HEAP32[i1 + 44 >> 2] | 0;
+}
+function _lua_status(i1) {
+ i1 = i1 | 0;
+ return HEAPU8[i1 + 6 | 0] | 0 | 0;
+}
+function _lua_gethook(i1) {
+ i1 = i1 | 0;
+ return HEAP32[i1 + 52 >> 2] | 0;
+}
+function b5(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(5);
+ return 0;
+}
+function _lua_error(i1) {
+ i1 = i1 | 0;
+ _luaG_errormsg(i1);
+ return 0;
+}
+function b2(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(2);
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function b3(i1) {
+ i1 = i1 | 0;
+ abort(3);
+ return 0;
+}
+function _rand() {
+ return _rand_r(___rand_seed) | 0;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+function b1(i1) {
+ i1 = i1 | 0;
+ abort(1);
+}
+
+// EMSCRIPTEN_END_FUNCS
+  var FUNCTION_TABLE_iiii = [b0,_getF,_getS,_generic_reader];
+  var FUNCTION_TABLE_vi = [b1,_laction];
+  var FUNCTION_TABLE_vii = [b2,_lstop,_growstack,_f_call,_resume,_unroll,_f_parser,_dothecall,_f_luaopen,_hookf,b2,b2,b2,b2,b2,b2];
+  var FUNCTION_TABLE_ii = [b3,_io_close,_io_flush,_io_input,_io_lines,_io_open,_io_output,_io_popen,_io_read,_io_tmpfile,_io_type,_io_write,_f_flush,_f_lines,_f_read,_f_seek,_f_setvbuf,_f_write,_f_gc,_f_tostring,_math_abs,_math_acos,_math_asin,_math_atan2,_math_atan,_math_ceil,_math_cosh,_math_cos,_math_deg
+  ,_math_exp,_math_floor,_math_fmod,_math_frexp,_math_ldexp,_math_log10,_math_log,_math_max,_math_min,_math_modf,_math_pow,_math_rad,_math_random,_math_randomseed,_math_sinh,_math_sin,_math_sqrt,_math_tanh,_math_tan,_ll_loadlib,_ll_searchpath,_ll_seeall,_ll_module,_ll_require,_os_clock,_os_date,_os_difftime,_os_execute,_os_exit,_os_getenv
+  ,_os_remove,_os_rename,_os_setlocale,_os_time,_os_tmpname,_str_byte,_str_char,_str_dump,_str_find,_str_format,_gmatch,_str_gsub,_str_len,_str_lower,_str_match,_str_rep,_str_reverse,_str_sub,_str_upper,_tconcat,_maxn,_tinsert,_pack,_unpack,_tremove,_sort,_luaB_assert,_luaB_collectgarbage,_luaB_dofile,_luaB_error
+  ,_luaB_getmetatable,_luaB_ipairs,_luaB_loadfile,_luaB_load,_luaB_next,_luaB_pairs,_luaB_pcall,_luaB_print,_luaB_rawequal,_luaB_rawlen,_luaB_rawget,_luaB_rawset,_luaB_select,_luaB_setmetatable,_luaB_tonumber,_luaB_tostring,_luaB_type,_luaB_xpcall,_b_arshift,_b_and,_b_not,_b_or,_b_xor,_b_test,_b_extract,_b_lrot,_b_lshift,_b_replace,_b_rrot,_b_rshift
+  ,_luaB_cocreate,_luaB_coresume,_luaB_corunning,_luaB_costatus,_luaB_cowrap,_luaB_yield,_db_debug,_db_getuservalue,_db_gethook,_db_getinfo,_db_getlocal,_db_getregistry,_db_getmetatable,_db_getupvalue,_db_upvaluejoin,_db_upvalueid,_db_setuservalue,_db_sethook,_db_setlocal,_db_setmetatable,_db_setupvalue,_db_traceback,_pmain,_traceback,_panic,_luaopen_base,_luaopen_package,_luaopen_coroutine,_luaopen_table,_luaopen_io
+  ,_luaopen_os,_luaopen_string,_luaopen_bit32,_luaopen_math,_luaopen_debug,_io_noclose,_io_readline,_io_fclose,_io_pclose,_gctm,_searcher_preload,_searcher_Lua,_searcher_C,_searcher_Croot,_gmatch_aux,_dofilecont,_ipairsaux,_pcallcont,_luaB_auxwrap,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3
+  ,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3
+  ,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3
+  ,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3,b3];
+  var FUNCTION_TABLE_iiiii = [b4,_l_alloc,_writer,b4];
+  var FUNCTION_TABLE_iii = [b5,_lua_newstate];
+
+  return { _testSetjmp: _testSetjmp, _i64Subtract: _i64Subtract, _free: _free, _main: _main, _rand_r: _rand_r, _realloc: _realloc, _i64Add: _i64Add, _tolower: _tolower, _saveSetjmp: _saveSetjmp, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, _strlen: _strlen, _rand: _rand, _bitshift64Shl: _bitshift64Shl, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_iiii: dynCall_iiii, dynCall_vi: dynCall_vi, dynCall_vii: dynCall_vii, dynCall_ii: dynCall_ii, dynCall_iiiii: dynCall_iiiii, dynCall_iii: dynCall_iii };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_iiii": invoke_iiii, "invoke_vi": invoke_vi, "invoke_vii": invoke_vii, "invoke_ii": invoke_ii, "invoke_iiiii": invoke_iiiii, "invoke_iii": invoke_iii, "_isalnum": _isalnum, "_fabs": _fabs, "_frexp": _frexp, "_exp": _exp, "_fread": _fread, "__reallyNegative": __reallyNegative, "_longjmp": _longjmp, "__addDays": __addDays, "_fsync": _fsync, "_signal": _signal, "_rename": _rename, "_sbrk": _sbrk, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_sinh": _sinh, "_sysconf": _sysconf, "_close": _close, "_ferror": _ferror, "_clock": _clock, "_cos": _cos, "_tanh": _tanh, "_unlink": _unlink, "_write": _write, "__isLeapYear": __isLeapYear, "_ftell": _ftell, "_isupper": _isupper, "_gmtime_r": _gmtime_r, "_islower": _islower, "_tmpnam": _tmpnam, "_tmpfile": _tmpfile, "_send": _send, "_abort": _abort, "_setvbuf": _setvbuf, "_atan2": _atan2, "_setlocale": _setlocale, "_isgraph": _isgraph, "_modf": _modf, "_strerror_r": _strerror_r, "_fscanf": _fscanf, "___setErrNo": ___setErrNo, "_isalpha": _isalpha, "_srand": _srand, "_mktime": _mktime, "_putchar": _putchar, "_gmtime": _gmtime, "_localeconv": _localeconv, "_sprintf": _sprintf, "_localtime": _localtime, "_read": _read, "_fwrite": _fwrite, "_time": _time, "_fprintf": _fprintf, "_exit": _exit, "_freopen": _freopen, "_llvm_pow_f64": _llvm_pow_f64, "_fgetc": _fgetc, "_fmod": _fmod, "_lseek": _lseek, "_rmdir": _rmdir, "_asin": _asin, "_floor": _floor, "_pwrite": _pwrite, "_localtime_r": _localtime_r, "_tzset": _tzset, "_open": _open, "_remove": _remove, "_snprintf": _snprintf, "__scanString": __scanString, "_strftime": _strftime, "_fseek": _fseek, "_iscntrl": _iscntrl, "_isxdigit": _isxdigit, "_fclose": _fclose, "_log": _log, "_recv": _recv, "_tan": _tan, "_copysign": _copysign, "__getFloat": __getFloat, "_fputc": _fputc, "_ispunct": _ispunct, "_ceil": _ceil, "_isspace": _isspace, "_fopen": _fopen, "_sin": _sin, "_acos": _acos, "_cosh": _cosh, "___buildEnvironment": ___buildEnvironment, "_difftime": _difftime, "_ungetc": _ungetc, "_system": _system, "_fflush": _fflush, "_log10": _log10, "_fileno": _fileno, "__exit": __exit, "__arraySum": __arraySum, "_fgets": _fgets, "_atan": _atan, "_pread": _pread, "_mkport": _mkport, "_toupper": _toupper, "_feof": _feof, "___errno_location": ___errno_location, "_clearerr": _clearerr, "_getenv": _getenv, "_strerror": _strerror, "_emscripten_longjmp": _emscripten_longjmp, "__formatString": __formatString, "_fputs": _fputs, "_sqrt": _sqrt, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "cttz_i8": cttz_i8, "ctlz_i8": ctlz_i8, "___rand_seed": ___rand_seed, "NaN": NaN, "Infinity": Infinity, "_stderr": _stderr, "_stdin": _stdin, "_stdout": _stdout }, buffer);
+var _testSetjmp = Module["_testSetjmp"] = asm["_testSetjmp"];
+var _i64Subtract = Module["_i64Subtract"] = asm["_i64Subtract"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _rand_r = Module["_rand_r"] = asm["_rand_r"];
+var _realloc = Module["_realloc"] = asm["_realloc"];
+var _i64Add = Module["_i64Add"] = asm["_i64Add"];
+var _tolower = Module["_tolower"] = asm["_tolower"];
+var _saveSetjmp = Module["_saveSetjmp"] = asm["_saveSetjmp"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _rand = Module["_rand"] = asm["_rand"];
+var _bitshift64Shl = Module["_bitshift64Shl"] = asm["_bitshift64Shl"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var dynCall_iiii = Module["dynCall_iiii"] = asm["dynCall_iiii"];
+var dynCall_vi = Module["dynCall_vi"] = asm["dynCall_vi"];
+var dynCall_vii = Module["dynCall_vii"] = asm["dynCall_vii"];
+var dynCall_ii = Module["dynCall_ii"] = asm["dynCall_ii"];
+var dynCall_iiiii = Module["dynCall_iiiii"] = asm["dynCall_iiiii"];
+var dynCall_iii = Module["dynCall_iii"] = asm["dynCall_iii"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// TODO: strip out parts of this we do not need
+
+//======= begin closure i64 code =======
+
+// Copyright 2009 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Defines a Long class for representing a 64-bit two's-complement
+ * integer value, which faithfully simulates the behavior of a Java "long". This
+ * implementation is derived from LongLib in GWT.
+ *
+ */
+
+var i64Math = (function() { // Emscripten wrapper
+  var goog = { math: {} };
+
+
+  /**
+   * Constructs a 64-bit two's-complement integer, given its low and high 32-bit
+   * values as *signed* integers.  See the from* functions below for more
+   * convenient ways of constructing Longs.
+   *
+   * The internal representation of a long is the two given signed, 32-bit values.
+   * We use 32-bit pieces because these are the size of integers on which
+   * Javascript performs bit-operations.  For operations like addition and
+   * multiplication, we split each number into 16-bit pieces, which can easily be
+   * multiplied within Javascript's floating-point representation without overflow
+   * or change in sign.
+   *
+   * In the algorithms below, we frequently reduce the negative case to the
+   * positive case by negating the input(s) and then post-processing the result.
+   * Note that we must ALWAYS check specially whether those values are MIN_VALUE
+   * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
+   * a positive number, it overflows back into a negative).  Not handling this
+   * case would often result in infinite recursion.
+   *
+   * @param {number} low  The low (signed) 32 bits of the long.
+   * @param {number} high  The high (signed) 32 bits of the long.
+   * @constructor
+   */
+  goog.math.Long = function(low, high) {
+    /**
+     * @type {number}
+     * @private
+     */
+    this.low_ = low | 0;  // force into 32 signed bits.
+
+    /**
+     * @type {number}
+     * @private
+     */
+    this.high_ = high | 0;  // force into 32 signed bits.
+  };
+
+
+  // NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
+  // from* methods on which they depend.
+
+
+  /**
+   * A cache of the Long representations of small integer values.
+   * @type {!Object}
+   * @private
+   */
+  goog.math.Long.IntCache_ = {};
+
+
+  /**
+   * Returns a Long representing the given (32-bit) integer value.
+   * @param {number} value The 32-bit integer in question.
+   * @return {!goog.math.Long} The corresponding Long value.
+   */
+  goog.math.Long.fromInt = function(value) {
+    if (-128 <= value && value < 128) {
+      var cachedObj = goog.math.Long.IntCache_[value];
+      if (cachedObj) {
+        return cachedObj;
+      }
+    }
+
+    var obj = new goog.math.Long(value | 0, value < 0 ? -1 : 0);
+    if (-128 <= value && value < 128) {
+      goog.math.Long.IntCache_[value] = obj;
+    }
+    return obj;
+  };
+
+
+  /**
+   * Returns a Long representing the given value, provided that it is a finite
+   * number.  Otherwise, zero is returned.
+   * @param {number} value The number in question.
+   * @return {!goog.math.Long} The corresponding Long value.
+   */
+  goog.math.Long.fromNumber = function(value) {
+    if (isNaN(value) || !isFinite(value)) {
+      return goog.math.Long.ZERO;
+    } else if (value <= -goog.math.Long.TWO_PWR_63_DBL_) {
+      return goog.math.Long.MIN_VALUE;
+    } else if (value + 1 >= goog.math.Long.TWO_PWR_63_DBL_) {
+      return goog.math.Long.MAX_VALUE;
+    } else if (value < 0) {
+      return goog.math.Long.fromNumber(-value).negate();
+    } else {
+      return new goog.math.Long(
+          (value % goog.math.Long.TWO_PWR_32_DBL_) | 0,
+          (value / goog.math.Long.TWO_PWR_32_DBL_) | 0);
+    }
+  };
+
+
+  /**
+   * Returns a Long representing the 64-bit integer that comes by concatenating
+   * the given high and low bits.  Each is assumed to use 32 bits.
+   * @param {number} lowBits The low 32-bits.
+   * @param {number} highBits The high 32-bits.
+   * @return {!goog.math.Long} The corresponding Long value.
+   */
+  goog.math.Long.fromBits = function(lowBits, highBits) {
+    return new goog.math.Long(lowBits, highBits);
+  };
+
+
+  /**
+   * Returns a Long representation of the given string, written using the given
+   * radix.
+   * @param {string} str The textual representation of the Long.
+   * @param {number=} opt_radix The radix in which the text is written.
+   * @return {!goog.math.Long} The corresponding Long value.
+   */
+  goog.math.Long.fromString = function(str, opt_radix) {
+    if (str.length == 0) {
+      throw Error('number format error: empty string');
+    }
+
+    var radix = opt_radix || 10;
+    if (radix < 2 || 36 < radix) {
+      throw Error('radix out of range: ' + radix);
+    }
+
+    if (str.charAt(0) == '-') {
+      return goog.math.Long.fromString(str.substring(1), radix).negate();
+    } else if (str.indexOf('-') >= 0) {
+      throw Error('number format error: interior "-" character: ' + str);
+    }
+
+    // Do several (8) digits each time through the loop, so as to
+    // minimize the calls to the very expensive emulated div.
+    var radixToPower = goog.math.Long.fromNumber(Math.pow(radix, 8));
+
+    var result = goog.math.Long.ZERO;
+    for (var i = 0; i < str.length; i += 8) {
+      var size = Math.min(8, str.length - i);
+      var value = parseInt(str.substring(i, i + size), radix);
+      if (size < 8) {
+        var power = goog.math.Long.fromNumber(Math.pow(radix, size));
+        result = result.multiply(power).add(goog.math.Long.fromNumber(value));
+      } else {
+        result = result.multiply(radixToPower);
+        result = result.add(goog.math.Long.fromNumber(value));
+      }
+    }
+    return result;
+  };
+
+
+  // NOTE: the compiler should inline these constant values below and then remove
+  // these variables, so there should be no runtime penalty for these.
+
+
+  /**
+   * Number used repeated below in calculations.  This must appear before the
+   * first call to any from* function below.
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_16_DBL_ = 1 << 16;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_24_DBL_ = 1 << 24;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_32_DBL_ =
+      goog.math.Long.TWO_PWR_16_DBL_ * goog.math.Long.TWO_PWR_16_DBL_;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_31_DBL_ =
+      goog.math.Long.TWO_PWR_32_DBL_ / 2;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_48_DBL_ =
+      goog.math.Long.TWO_PWR_32_DBL_ * goog.math.Long.TWO_PWR_16_DBL_;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_64_DBL_ =
+      goog.math.Long.TWO_PWR_32_DBL_ * goog.math.Long.TWO_PWR_32_DBL_;
+
+
+  /**
+   * @type {number}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_63_DBL_ =
+      goog.math.Long.TWO_PWR_64_DBL_ / 2;
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.ZERO = goog.math.Long.fromInt(0);
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.ONE = goog.math.Long.fromInt(1);
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.NEG_ONE = goog.math.Long.fromInt(-1);
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.MAX_VALUE =
+      goog.math.Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
+
+
+  /** @type {!goog.math.Long} */
+  goog.math.Long.MIN_VALUE = goog.math.Long.fromBits(0, 0x80000000 | 0);
+
+
+  /**
+   * @type {!goog.math.Long}
+   * @private
+   */
+  goog.math.Long.TWO_PWR_24_ = goog.math.Long.fromInt(1 << 24);
+
+
+  /** @return {number} The value, assuming it is a 32-bit integer. */
+  goog.math.Long.prototype.toInt = function() {
+    return this.low_;
+  };
+
+
+  /** @return {number} The closest floating-point representation to this value. */
+  goog.math.Long.prototype.toNumber = function() {
+    return this.high_ * goog.math.Long.TWO_PWR_32_DBL_ +
+           this.getLowBitsUnsigned();
+  };
+
+
+  /**
+   * @param {number=} opt_radix The radix in which the text should be written.
+   * @return {string} The textual representation of this value.
+   */
+  goog.math.Long.prototype.toString = function(opt_radix) {
+    var radix = opt_radix || 10;
+    if (radix < 2 || 36 < radix) {
+      throw Error('radix out of range: ' + radix);
+    }
+
+    if (this.isZero()) {
+      return '0';
+    }
+
+    if (this.isNegative()) {
+      if (this.equals(goog.math.Long.MIN_VALUE)) {
+        // We need to change the Long value before it can be negated, so we remove
+        // the bottom-most digit in this base and then recurse to do the rest.
+        var radixLong = goog.math.Long.fromNumber(radix);
+        var div = this.div(radixLong);
+        var rem = div.multiply(radixLong).subtract(this);
+        return div.toString(radix) + rem.toInt().toString(radix);
+      } else {
+        return '-' + this.negate().toString(radix);
+      }
+    }
+
+    // Do several (6) digits each time through the loop, so as to
+    // minimize the calls to the very expensive emulated div.
+    var radixToPower = goog.math.Long.fromNumber(Math.pow(radix, 6));
+
+    var rem = this;
+    var result = '';
+    while (true) {
+      var remDiv = rem.div(radixToPower);
+      var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt();
+      var digits = intval.toString(radix);
+
+      rem = remDiv;
+      if (rem.isZero()) {
+        return digits + result;
+      } else {
+        while (digits.length < 6) {
+          digits = '0' + digits;
+        }
+        result = '' + digits + result;
+      }
+    }
+  };
+
+
+  /** @return {number} The high 32-bits as a signed value. */
+  goog.math.Long.prototype.getHighBits = function() {
+    return this.high_;
+  };
+
+
+  /** @return {number} The low 32-bits as a signed value. */
+  goog.math.Long.prototype.getLowBits = function() {
+    return this.low_;
+  };
+
+
+  /** @return {number} The low 32-bits as an unsigned value. */
+  goog.math.Long.prototype.getLowBitsUnsigned = function() {
+    return (this.low_ >= 0) ?
+        this.low_ : goog.math.Long.TWO_PWR_32_DBL_ + this.low_;
+  };
+
+
+  /**
+   * @return {number} Returns the number of bits needed to represent the absolute
+   *     value of this Long.
+   */
+  goog.math.Long.prototype.getNumBitsAbs = function() {
+    if (this.isNegative()) {
+      if (this.equals(goog.math.Long.MIN_VALUE)) {
+        return 64;
+      } else {
+        return this.negate().getNumBitsAbs();
+      }
+    } else {
+      var val = this.high_ != 0 ? this.high_ : this.low_;
+      for (var bit = 31; bit > 0; bit--) {
+        if ((val & (1 << bit)) != 0) {
+          break;
+        }
+      }
+      return this.high_ != 0 ? bit + 33 : bit + 1;
+    }
+  };
+
+
+  /** @return {boolean} Whether this value is zero. */
+  goog.math.Long.prototype.isZero = function() {
+    return this.high_ == 0 && this.low_ == 0;
+  };
+
+
+  /** @return {boolean} Whether this value is negative. */
+  goog.math.Long.prototype.isNegative = function() {
+    return this.high_ < 0;
+  };
+
+
+  /** @return {boolean} Whether this value is odd. */
+  goog.math.Long.prototype.isOdd = function() {
+    return (this.low_ & 1) == 1;
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long equals the other.
+   */
+  goog.math.Long.prototype.equals = function(other) {
+    return (this.high_ == other.high_) && (this.low_ == other.low_);
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long does not equal the other.
+   */
+  goog.math.Long.prototype.notEquals = function(other) {
+    return (this.high_ != other.high_) || (this.low_ != other.low_);
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long is less than the other.
+   */
+  goog.math.Long.prototype.lessThan = function(other) {
+    return this.compare(other) < 0;
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long is less than or equal to the other.
+   */
+  goog.math.Long.prototype.lessThanOrEqual = function(other) {
+    return this.compare(other) <= 0;
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long is greater than the other.
+   */
+  goog.math.Long.prototype.greaterThan = function(other) {
+    return this.compare(other) > 0;
+  };
+
+
+  /**
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {boolean} Whether this Long is greater than or equal to the other.
+   */
+  goog.math.Long.prototype.greaterThanOrEqual = function(other) {
+    return this.compare(other) >= 0;
+  };
+
+
+  /**
+   * Compares this Long with the given one.
+   * @param {goog.math.Long} other Long to compare against.
+   * @return {number} 0 if they are the same, 1 if the this is greater, and -1
+   *     if the given one is greater.
+   */
+  goog.math.Long.prototype.compare = function(other) {
+    if (this.equals(other)) {
+      return 0;
+    }
+
+    var thisNeg = this.isNegative();
+    var otherNeg = other.isNegative();
+    if (thisNeg && !otherNeg) {
+      return -1;
+    }
+    if (!thisNeg && otherNeg) {
+      return 1;
+    }
+
+    // at this point, the signs are the same, so subtraction will not overflow
+    if (this.subtract(other).isNegative()) {
+      return -1;
+    } else {
+      return 1;
+    }
+  };
+
+
+  /** @return {!goog.math.Long} The negation of this value. */
+  goog.math.Long.prototype.negate = function() {
+    if (this.equals(goog.math.Long.MIN_VALUE)) {
+      return goog.math.Long.MIN_VALUE;
+    } else {
+      return this.not().add(goog.math.Long.ONE);
+    }
+  };
+
+
+  /**
+   * Returns the sum of this and the given Long.
+   * @param {goog.math.Long} other Long to add to this one.
+   * @return {!goog.math.Long} The sum of this and the given Long.
+   */
+  goog.math.Long.prototype.add = function(other) {
+    // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
+
+    var a48 = this.high_ >>> 16;
+    var a32 = this.high_ & 0xFFFF;
+    var a16 = this.low_ >>> 16;
+    var a00 = this.low_ & 0xFFFF;
+
+    var b48 = other.high_ >>> 16;
+    var b32 = other.high_ & 0xFFFF;
+    var b16 = other.low_ >>> 16;
+    var b00 = other.low_ & 0xFFFF;
+
+    var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+    c00 += a00 + b00;
+    c16 += c00 >>> 16;
+    c00 &= 0xFFFF;
+    c16 += a16 + b16;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c32 += a32 + b32;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c48 += a48 + b48;
+    c48 &= 0xFFFF;
+    return goog.math.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
+  };
+
+
+  /**
+   * Returns the difference of this and the given Long.
+   * @param {goog.math.Long} other Long to subtract from this.
+   * @return {!goog.math.Long} The difference of this and the given Long.
+   */
+  goog.math.Long.prototype.subtract = function(other) {
+    return this.add(other.negate());
+  };
+
+
+  /**
+   * Returns the product of this and the given long.
+   * @param {goog.math.Long} other Long to multiply with this.
+   * @return {!goog.math.Long} The product of this and the other.
+   */
+  goog.math.Long.prototype.multiply = function(other) {
+    if (this.isZero()) {
+      return goog.math.Long.ZERO;
+    } else if (other.isZero()) {
+      return goog.math.Long.ZERO;
+    }
+
+    if (this.equals(goog.math.Long.MIN_VALUE)) {
+      return other.isOdd() ? goog.math.Long.MIN_VALUE : goog.math.Long.ZERO;
+    } else if (other.equals(goog.math.Long.MIN_VALUE)) {
+      return this.isOdd() ? goog.math.Long.MIN_VALUE : goog.math.Long.ZERO;
+    }
+
+    if (this.isNegative()) {
+      if (other.isNegative()) {
+        return this.negate().multiply(other.negate());
+      } else {
+        return this.negate().multiply(other).negate();
+      }
+    } else if (other.isNegative()) {
+      return this.multiply(other.negate()).negate();
+    }
+
+    // If both longs are small, use float multiplication
+    if (this.lessThan(goog.math.Long.TWO_PWR_24_) &&
+        other.lessThan(goog.math.Long.TWO_PWR_24_)) {
+      return goog.math.Long.fromNumber(this.toNumber() * other.toNumber());
+    }
+
+    // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
+    // We can skip products that would overflow.
+
+    var a48 = this.high_ >>> 16;
+    var a32 = this.high_ & 0xFFFF;
+    var a16 = this.low_ >>> 16;
+    var a00 = this.low_ & 0xFFFF;
+
+    var b48 = other.high_ >>> 16;
+    var b32 = other.high_ & 0xFFFF;
+    var b16 = other.low_ >>> 16;
+    var b00 = other.low_ & 0xFFFF;
+
+    var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+    c00 += a00 * b00;
+    c16 += c00 >>> 16;
+    c00 &= 0xFFFF;
+    c16 += a16 * b00;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c16 += a00 * b16;
+    c32 += c16 >>> 16;
+    c16 &= 0xFFFF;
+    c32 += a32 * b00;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c32 += a16 * b16;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c32 += a00 * b32;
+    c48 += c32 >>> 16;
+    c32 &= 0xFFFF;
+    c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
+    c48 &= 0xFFFF;
+    return goog.math.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
+  };
+
+
+  /**
+   * Returns this Long divided by the given one.
+   * @param {goog.math.Long} other Long by which to divide.
+   * @return {!goog.math.Long} This Long divided by the given one.
+   */
+  goog.math.Long.prototype.div = function(other) {
+    if (other.isZero()) {
+      throw Error('division by zero');
+    } else if (this.isZero()) {
+      return goog.math.Long.ZERO;
+    }
+
+    if (this.equals(goog.math.Long.MIN_VALUE)) {
+      if (other.equals(goog.math.Long.ONE) ||
+          other.equals(goog.math.Long.NEG_ONE)) {
+        return goog.math.Long.MIN_VALUE;  // recall that -MIN_VALUE == MIN_VALUE
+      } else if (other.equals(goog.math.Long.MIN_VALUE)) {
+        return goog.math.Long.ONE;
+      } else {
+        // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
+        var halfThis = this.shiftRight(1);
+        var approx = halfThis.div(other).shiftLeft(1);
+        if (approx.equals(goog.math.Long.ZERO)) {
+          return other.isNegative() ? goog.math.Long.ONE : goog.math.Long.NEG_ONE;
+        } else {
+          var rem = this.subtract(other.multiply(approx));
+          var result = approx.add(rem.div(other));
+          return result;
+        }
+      }
+    } else if (other.equals(goog.math.Long.MIN_VALUE)) {
+      return goog.math.Long.ZERO;
+    }
+
+    if (this.isNegative()) {
+      if (other.isNegative()) {
+        return this.negate().div(other.negate());
+      } else {
+        return this.negate().div(other).negate();
+      }
+    } else if (other.isNegative()) {
+      return this.div(other.negate()).negate();
+    }
+
+    // Repeat the following until the remainder is less than other:  find a
+    // floating-point that approximates remainder / other *from below*, add this
+    // into the result, and subtract it from the remainder.  It is critical that
+    // the approximate value is less than or equal to the real value so that the
+    // remainder never becomes negative.
+    var res = goog.math.Long.ZERO;
+    var rem = this;
+    while (rem.greaterThanOrEqual(other)) {
+      // Approximate the result of division. This may be a little greater or
+      // smaller than the actual value.
+      var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
+
+      // We will tweak the approximate result by changing it in the 48-th digit or
+      // the smallest non-fractional digit, whichever is larger.
+      var log2 = Math.ceil(Math.log(approx) / Math.LN2);
+      var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
+
+      // Decrease the approximation until it is smaller than the remainder.  Note
+      // that if it is too large, the product overflows and is negative.
+      var approxRes = goog.math.Long.fromNumber(approx);
+      var approxRem = approxRes.multiply(other);
+      while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
+        approx -= delta;
+        approxRes = goog.math.Long.fromNumber(approx);
+        approxRem = approxRes.multiply(other);
+      }
+
+      // We know the answer can't be zero... and actually, zero would cause
+      // infinite recursion since we would make no progress.
+      if (approxRes.isZero()) {
+        approxRes = goog.math.Long.ONE;
+      }
+
+      res = res.add(approxRes);
+      rem = rem.subtract(approxRem);
+    }
+    return res;
+  };
+
+
+  /**
+   * Returns this Long modulo the given one.
+   * @param {goog.math.Long} other Long by which to mod.
+   * @return {!goog.math.Long} This Long modulo the given one.
+   */
+  goog.math.Long.prototype.modulo = function(other) {
+    return this.subtract(this.div(other).multiply(other));
+  };
+
+
+  /** @return {!goog.math.Long} The bitwise-NOT of this value. */
+  goog.math.Long.prototype.not = function() {
+    return goog.math.Long.fromBits(~this.low_, ~this.high_);
+  };
+
+
+  /**
+   * Returns the bitwise-AND of this Long and the given one.
+   * @param {goog.math.Long} other The Long with which to AND.
+   * @return {!goog.math.Long} The bitwise-AND of this and the other.
+   */
+  goog.math.Long.prototype.and = function(other) {
+    return goog.math.Long.fromBits(this.low_ & other.low_,
+                                   this.high_ & other.high_);
+  };
+
+
+  /**
+   * Returns the bitwise-OR of this Long and the given one.
+   * @param {goog.math.Long} other The Long with which to OR.
+   * @return {!goog.math.Long} The bitwise-OR of this and the other.
+   */
+  goog.math.Long.prototype.or = function(other) {
+    return goog.math.Long.fromBits(this.low_ | other.low_,
+                                   this.high_ | other.high_);
+  };
+
+
+  /**
+   * Returns the bitwise-XOR of this Long and the given one.
+   * @param {goog.math.Long} other The Long with which to XOR.
+   * @return {!goog.math.Long} The bitwise-XOR of this and the other.
+   */
+  goog.math.Long.prototype.xor = function(other) {
+    return goog.math.Long.fromBits(this.low_ ^ other.low_,
+                                   this.high_ ^ other.high_);
+  };
+
+
+  /**
+   * Returns this Long with bits shifted to the left by the given amount.
+   * @param {number} numBits The number of bits by which to shift.
+   * @return {!goog.math.Long} This shifted to the left by the given amount.
+   */
+  goog.math.Long.prototype.shiftLeft = function(numBits) {
+    numBits &= 63;
+    if (numBits == 0) {
+      return this;
+    } else {
+      var low = this.low_;
+      if (numBits < 32) {
+        var high = this.high_;
+        return goog.math.Long.fromBits(
+            low << numBits,
+            (high << numBits) | (low >>> (32 - numBits)));
+      } else {
+        return goog.math.Long.fromBits(0, low << (numBits - 32));
+      }
+    }
+  };
+
+
+  /**
+   * Returns this Long with bits shifted to the right by the given amount.
+   * @param {number} numBits The number of bits by which to shift.
+   * @return {!goog.math.Long} This shifted to the right by the given amount.
+   */
+  goog.math.Long.prototype.shiftRight = function(numBits) {
+    numBits &= 63;
+    if (numBits == 0) {
+      return this;
+    } else {
+      var high = this.high_;
+      if (numBits < 32) {
+        var low = this.low_;
+        return goog.math.Long.fromBits(
+            (low >>> numBits) | (high << (32 - numBits)),
+            high >> numBits);
+      } else {
+        return goog.math.Long.fromBits(
+            high >> (numBits - 32),
+            high >= 0 ? 0 : -1);
+      }
+    }
+  };
+
+
+  /**
+   * Returns this Long with bits shifted to the right by the given amount, with
+   * the new top bits matching the current sign bit.
+   * @param {number} numBits The number of bits by which to shift.
+   * @return {!goog.math.Long} This shifted to the right by the given amount, with
+   *     zeros placed into the new leading bits.
+   */
+  goog.math.Long.prototype.shiftRightUnsigned = function(numBits) {
+    numBits &= 63;
+    if (numBits == 0) {
+      return this;
+    } else {
+      var high = this.high_;
+      if (numBits < 32) {
+        var low = this.low_;
+        return goog.math.Long.fromBits(
+            (low >>> numBits) | (high << (32 - numBits)),
+            high >>> numBits);
+      } else if (numBits == 32) {
+        return goog.math.Long.fromBits(high, 0);
+      } else {
+        return goog.math.Long.fromBits(high >>> (numBits - 32), 0);
+      }
+    }
+  };
+
+  //======= begin jsbn =======
+
+  var navigator = { appName: 'Modern Browser' }; // polyfill a little
+
+  // Copyright (c) 2005  Tom Wu
+  // All Rights Reserved.
+  // http://www-cs-students.stanford.edu/~tjw/jsbn/
+
+  /*
+   * Copyright (c) 2003-2005  Tom Wu
+   * All Rights Reserved.
+   *
+   * 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" AND WITHOUT WARRANTY OF ANY KIND,
+   * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+   * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+   *
+   * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+   * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+   * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+   * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+   * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+   *
+   * In addition, the following condition applies:
+   *
+   * All redistributions must retain an intact copy of this copyright notice
+   * and disclaimer.
+   */
+
+  // Basic JavaScript BN library - subset useful for RSA encryption.
+
+  // Bits per digit
+  var dbits;
+
+  // JavaScript engine analysis
+  var canary = 0xdeadbeefcafe;
+  var j_lm = ((canary&0xffffff)==0xefcafe);
+
+  // (public) Constructor
+  function BigInteger(a,b,c) {
+    if(a != null)
+      if("number" == typeof a) this.fromNumber(a,b,c);
+      else if(b == null && "string" != typeof a) this.fromString(a,256);
+      else this.fromString(a,b);
+  }
+
+  // return new, unset BigInteger
+  function nbi() { return new BigInteger(null); }
+
+  // am: Compute w_j += (x*this_i), propagate carries,
+  // c is initial carry, returns final carry.
+  // c < 3*dvalue, x < 2*dvalue, this_i < dvalue
+  // We need to select the fastest one that works in this environment.
+
+  // am1: use a single mult and divide to get the high bits,
+  // max digit bits should be 26 because
+  // max internal value = 2*dvalue^2-2*dvalue (< 2^53)
+  function am1(i,x,w,j,c,n) {
+    while(--n >= 0) {
+      var v = x*this[i++]+w[j]+c;
+      c = Math.floor(v/0x4000000);
+      w[j++] = v&0x3ffffff;
+    }
+    return c;
+  }
+  // am2 avoids a big mult-and-extract completely.
+  // Max digit bits should be <= 30 because we do bitwise ops
+  // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
+  function am2(i,x,w,j,c,n) {
+    var xl = x&0x7fff, xh = x>>15;
+    while(--n >= 0) {
+      var l = this[i]&0x7fff;
+      var h = this[i++]>>15;
+      var m = xh*l+h*xl;
+      l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
+      c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
+      w[j++] = l&0x3fffffff;
+    }
+    return c;
+  }
+  // Alternately, set max digit bits to 28 since some
+  // browsers slow down when dealing with 32-bit numbers.
+  function am3(i,x,w,j,c,n) {
+    var xl = x&0x3fff, xh = x>>14;
+    while(--n >= 0) {
+      var l = this[i]&0x3fff;
+      var h = this[i++]>>14;
+      var m = xh*l+h*xl;
+      l = xl*l+((m&0x3fff)<<14)+w[j]+c;
+      c = (l>>28)+(m>>14)+xh*h;
+      w[j++] = l&0xfffffff;
+    }
+    return c;
+  }
+  if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
+    BigInteger.prototype.am = am2;
+    dbits = 30;
+  }
+  else if(j_lm && (navigator.appName != "Netscape")) {
+    BigInteger.prototype.am = am1;
+    dbits = 26;
+  }
+  else { // Mozilla/Netscape seems to prefer am3
+    BigInteger.prototype.am = am3;
+    dbits = 28;
+  }
+
+  BigInteger.prototype.DB = dbits;
+  BigInteger.prototype.DM = ((1<<dbits)-1);
+  BigInteger.prototype.DV = (1<<dbits);
+
+  var BI_FP = 52;
+  BigInteger.prototype.FV = Math.pow(2,BI_FP);
+  BigInteger.prototype.F1 = BI_FP-dbits;
+  BigInteger.prototype.F2 = 2*dbits-BI_FP;
+
+  // Digit conversions
+  var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
+  var BI_RC = new Array();
+  var rr,vv;
+  rr = "0".charCodeAt(0);
+  for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
+  rr = "a".charCodeAt(0);
+  for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+  rr = "A".charCodeAt(0);
+  for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+
+  function int2char(n) { return BI_RM.charAt(n); }
+  function intAt(s,i) {
+    var c = BI_RC[s.charCodeAt(i)];
+    return (c==null)?-1:c;
+  }
+
+  // (protected) copy this to r
+  function bnpCopyTo(r) {
+    for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
+    r.t = this.t;
+    r.s = this.s;
+  }
+
+  // (protected) set from integer value x, -DV <= x < DV
+  function bnpFromInt(x) {
+    this.t = 1;
+    this.s = (x<0)?-1:0;
+    if(x > 0) this[0] = x;
+    else if(x < -1) this[0] = x+DV;
+    else this.t = 0;
+  }
+
+  // return bigint initialized to value
+  function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
+
+  // (protected) set from string and radix
+  function bnpFromString(s,b) {
+    var k;
+    if(b == 16) k = 4;
+    else if(b == 8) k = 3;
+    else if(b == 256) k = 8; // byte array
+    else if(b == 2) k = 1;
+    else if(b == 32) k = 5;
+    else if(b == 4) k = 2;
+    else { this.fromRadix(s,b); return; }
+    this.t = 0;
+    this.s = 0;
+    var i = s.length, mi = false, sh = 0;
+    while(--i >= 0) {
+      var x = (k==8)?s[i]&0xff:intAt(s,i);
+      if(x < 0) {
+        if(s.charAt(i) == "-") mi = true;
+        continue;
+      }
+      mi = false;
+      if(sh == 0)
+        this[this.t++] = x;
+      else if(sh+k > this.DB) {
+        this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
+        this[this.t++] = (x>>(this.DB-sh));
+      }
+      else
+        this[this.t-1] |= x<<sh;
+      sh += k;
+      if(sh >= this.DB) sh -= this.DB;
+    }
+    if(k == 8 && (s[0]&0x80) != 0) {
+      this.s = -1;
+      if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
+    }
+    this.clamp();
+    if(mi) BigInteger.ZERO.subTo(this,this);
+  }
+
+  // (protected) clamp off excess high words
+  function bnpClamp() {
+    var c = this.s&this.DM;
+    while(this.t > 0 && this[this.t-1] == c) --this.t;
+  }
+
+  // (public) return string representation in given radix
+  function bnToString(b) {
+    if(this.s < 0) return "-"+this.negate().toString(b);
+    var k;
+    if(b == 16) k = 4;
+    else if(b == 8) k = 3;
+    else if(b == 2) k = 1;
+    else if(b == 32) k = 5;
+    else if(b == 4) k = 2;
+    else return this.toRadix(b);
+    var km = (1<<k)-1, d, m = false, r = "", i = this.t;
+    var p = this.DB-(i*this.DB)%k;
+    if(i-- > 0) {
+      if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
+      while(i >= 0) {
+        if(p < k) {
+          d = (this[i]&((1<<p)-1))<<(k-p);
+          d |= this[--i]>>(p+=this.DB-k);
+        }
+        else {
+          d = (this[i]>>(p-=k))&km;
+          if(p <= 0) { p += this.DB; --i; }
+        }
+        if(d > 0) m = true;
+        if(m) r += int2char(d);
+      }
+    }
+    return m?r:"0";
+  }
+
+  // (public) -this
+  function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
+
+  // (public) |this|
+  function bnAbs() { return (this.s<0)?this.negate():this; }
+
+  // (public) return + if this > a, - if this < a, 0 if equal
+  function bnCompareTo(a) {
+    var r = this.s-a.s;
+    if(r != 0) return r;
+    var i = this.t;
+    r = i-a.t;
+    if(r != 0) return (this.s<0)?-r:r;
+    while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
+    return 0;
+  }
+
+  // returns bit length of the integer x
+  function nbits(x) {
+    var r = 1, t;
+    if((t=x>>>16) != 0) { x = t; r += 16; }
+    if((t=x>>8) != 0) { x = t; r += 8; }
+    if((t=x>>4) != 0) { x = t; r += 4; }
+    if((t=x>>2) != 0) { x = t; r += 2; }
+    if((t=x>>1) != 0) { x = t; r += 1; }
+    return r;
+  }
+
+  // (public) return the number of bits in "this"
+  function bnBitLength() {
+    if(this.t <= 0) return 0;
+    return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
+  }
+
+  // (protected) r = this << n*DB
+  function bnpDLShiftTo(n,r) {
+    var i;
+    for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
+    for(i = n-1; i >= 0; --i) r[i] = 0;
+    r.t = this.t+n;
+    r.s = this.s;
+  }
+
+  // (protected) r = this >> n*DB
+  function bnpDRShiftTo(n,r) {
+    for(var i = n; i < this.t; ++i) r[i-n] = this[i];
+    r.t = Math.max(this.t-n,0);
+    r.s = this.s;
+  }
+
+  // (protected) r = this << n
+  function bnpLShiftTo(n,r) {
+    var bs = n%this.DB;
+    var cbs = this.DB-bs;
+    var bm = (1<<cbs)-1;
+    var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
+    for(i = this.t-1; i >= 0; --i) {
+      r[i+ds+1] = (this[i]>>cbs)|c;
+      c = (this[i]&bm)<<bs;
+    }
+    for(i = ds-1; i >= 0; --i) r[i] = 0;
+    r[ds] = c;
+    r.t = this.t+ds+1;
+    r.s = this.s;
+    r.clamp();
+  }
+
+  // (protected) r = this >> n
+  function bnpRShiftTo(n,r) {
+    r.s = this.s;
+    var ds = Math.floor(n/this.DB);
+    if(ds >= this.t) { r.t = 0; return; }
+    var bs = n%this.DB;
+    var cbs = this.DB-bs;
+    var bm = (1<<bs)-1;
+    r[0] = this[ds]>>bs;
+    for(var i = ds+1; i < this.t; ++i) {
+      r[i-ds-1] |= (this[i]&bm)<<cbs;
+      r[i-ds] = this[i]>>bs;
+    }
+    if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
+    r.t = this.t-ds;
+    r.clamp();
+  }
+
+  // (protected) r = this - a
+  function bnpSubTo(a,r) {
+    var i = 0, c = 0, m = Math.min(a.t,this.t);
+    while(i < m) {
+      c += this[i]-a[i];
+      r[i++] = c&this.DM;
+      c >>= this.DB;
+    }
+    if(a.t < this.t) {
+      c -= a.s;
+      while(i < this.t) {
+        c += this[i];
+        r[i++] = c&this.DM;
+        c >>= this.DB;
+      }
+      c += this.s;
+    }
+    else {
+      c += this.s;
+      while(i < a.t) {
+        c -= a[i];
+        r[i++] = c&this.DM;
+        c >>= this.DB;
+      }
+      c -= a.s;
+    }
+    r.s = (c<0)?-1:0;
+    if(c < -1) r[i++] = this.DV+c;
+    else if(c > 0) r[i++] = c;
+    r.t = i;
+    r.clamp();
+  }
+
+  // (protected) r = this * a, r != this,a (HAC 14.12)
+  // "this" should be the larger one if appropriate.
+  function bnpMultiplyTo(a,r) {
+    var x = this.abs(), y = a.abs();
+    var i = x.t;
+    r.t = i+y.t;
+    while(--i >= 0) r[i] = 0;
+    for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
+    r.s = 0;
+    r.clamp();
+    if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
+  }
+
+  // (protected) r = this^2, r != this (HAC 14.16)
+  function bnpSquareTo(r) {
+    var x = this.abs();
+    var i = r.t = 2*x.t;
+    while(--i >= 0) r[i] = 0;
+    for(i = 0; i < x.t-1; ++i) {
+      var c = x.am(i,x[i],r,2*i,0,1);
+      if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
+        r[i+x.t] -= x.DV;
+        r[i+x.t+1] = 1;
+      }
+    }
+    if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
+    r.s = 0;
+    r.clamp();
+  }
+
+  // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
+  // r != q, this != m.  q or r may be null.
+  function bnpDivRemTo(m,q,r) {
+    var pm = m.abs();
+    if(pm.t <= 0) return;
+    var pt = this.abs();
+    if(pt.t < pm.t) {
+      if(q != null) q.fromInt(0);
+      if(r != null) this.copyTo(r);
+      return;
+    }
+    if(r == null) r = nbi();
+    var y = nbi(), ts = this.s, ms = m.s;
+    var nsh = this.DB-nbits(pm[pm.t-1]);  // normalize modulus
+    if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
+    else { pm.copyTo(y); pt.copyTo(r); }
+    var ys = y.t;
+    var y0 = y[ys-1];
+    if(y0 == 0) return;
+    var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
+    var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
+    var i = r.t, j = i-ys, t = (q==null)?nbi():q;
+    y.dlShiftTo(j,t);
+    if(r.compareTo(t) >= 0) {
+      r[r.t++] = 1;
+      r.subTo(t,r);
+    }
+    BigInteger.ONE.dlShiftTo(ys,t);
+    t.subTo(y,y);  // "negative" y so we can replace sub with am later
+    while(y.t < ys) y[y.t++] = 0;
+    while(--j >= 0) {
+      // Estimate quotient digit
+      var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
+      if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) {  // Try it out
+        y.dlShiftTo(j,t);
+        r.subTo(t,r);
+        while(r[i] < --qd) r.subTo(t,r);
+      }
+    }
+    if(q != null) {
+      r.drShiftTo(ys,q);
+      if(ts != ms) BigInteger.ZERO.subTo(q,q);
+    }
+    r.t = ys;
+    r.clamp();
+    if(nsh > 0) r.rShiftTo(nsh,r);  // Denormalize remainder
+    if(ts < 0) BigInteger.ZERO.subTo(r,r);
+  }
+
+  // (public) this mod a
+  function bnMod(a) {
+    var r = nbi();
+    this.abs().divRemTo(a,null,r);
+    if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
+    return r;
+  }
+
+  // Modular reduction using "classic" algorithm
+  function Classic(m) { this.m = m; }
+  function cConvert(x) {
+    if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
+    else return x;
+  }
+  function cRevert(x) { return x; }
+  function cReduce(x) { x.divRemTo(this.m,null,x); }
+  function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+  function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+  Classic.prototype.convert = cConvert;
+  Classic.prototype.revert = cRevert;
+  Classic.prototype.reduce = cReduce;
+  Classic.prototype.mulTo = cMulTo;
+  Classic.prototype.sqrTo = cSqrTo;
+
+  // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
+  // justification:
+  //         xy == 1 (mod m)
+  //         xy =  1+km
+  //   xy(2-xy) = (1+km)(1-km)
+  // x[y(2-xy)] = 1-k^2m^2
+  // x[y(2-xy)] == 1 (mod m^2)
+  // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+  // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+  // JS multiply "overflows" differently from C/C++, so care is needed here.
+  function bnpInvDigit() {
+    if(this.t < 1) return 0;
+    var x = this[0];
+    if((x&1) == 0) return 0;
+    var y = x&3;    // y == 1/x mod 2^2
+    y = (y*(2-(x&0xf)*y))&0xf;  // y == 1/x mod 2^4
+    y = (y*(2-(x&0xff)*y))&0xff;  // y == 1/x mod 2^8
+    y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff;  // y == 1/x mod 2^16
+    // last step - calculate inverse mod DV directly;
+    // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
+    y = (y*(2-x*y%this.DV))%this.DV;    // y == 1/x mod 2^dbits
+    // we really want the negative inverse, and -DV < y < DV
+    return (y>0)?this.DV-y:-y;
+  }
+
+  // Montgomery reduction
+  function Montgomery(m) {
+    this.m = m;
+    this.mp = m.invDigit();
+    this.mpl = this.mp&0x7fff;
+    this.mph = this.mp>>15;
+    this.um = (1<<(m.DB-15))-1;
+    this.mt2 = 2*m.t;
+  }
+
+  // xR mod m
+  function montConvert(x) {
+    var r = nbi();
+    x.abs().dlShiftTo(this.m.t,r);
+    r.divRemTo(this.m,null,r);
+    if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
+    return r;
+  }
+
+  // x/R mod m
+  function montRevert(x) {
+    var r = nbi();
+    x.copyTo(r);
+    this.reduce(r);
+    return r;
+  }
+
+  // x = x/R mod m (HAC 14.32)
+  function montReduce(x) {
+    while(x.t <= this.mt2)  // pad x so am has enough room later
+      x[x.t++] = 0;
+    for(var i = 0; i < this.m.t; ++i) {
+      // faster way of calculating u0 = x[i]*mp mod DV
+      var j = x[i]&0x7fff;
+      var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
+      // use am to combine the multiply-shift-add into one call
+      j = i+this.m.t;
+      x[j] += this.m.am(0,u0,x,i,0,this.m.t);
+      // propagate carry
+      while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
+    }
+    x.clamp();
+    x.drShiftTo(this.m.t,x);
+    if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
+  }
+
+  // r = "x^2/R mod m"; x != r
+  function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+  // r = "xy/R mod m"; x,y != r
+  function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+
+  Montgomery.prototype.convert = montConvert;
+  Montgomery.prototype.revert = montRevert;
+  Montgomery.prototype.reduce = montReduce;
+  Montgomery.prototype.mulTo = montMulTo;
+  Montgomery.prototype.sqrTo = montSqrTo;
+
+  // (protected) true iff this is even
+  function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
+
+  // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
+  function bnpExp(e,z) {
+    if(e > 0xffffffff || e < 1) return BigInteger.ONE;
+    var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
+    g.copyTo(r);
+    while(--i >= 0) {
+      z.sqrTo(r,r2);
+      if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
+      else { var t = r; r = r2; r2 = t; }
+    }
+    return z.revert(r);
+  }
+
+  // (public) this^e % m, 0 <= e < 2^32
+  function bnModPowInt(e,m) {
+    var z;
+    if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
+    return this.exp(e,z);
+  }
+
+  // protected
+  BigInteger.prototype.copyTo = bnpCopyTo;
+  BigInteger.prototype.fromInt = bnpFromInt;
+  BigInteger.prototype.fromString = bnpFromString;
+  BigInteger.prototype.clamp = bnpClamp;
+  BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
+  BigInteger.prototype.drShiftTo = bnpDRShiftTo;
+  BigInteger.prototype.lShiftTo = bnpLShiftTo;
+  BigInteger.prototype.rShiftTo = bnpRShiftTo;
+  BigInteger.prototype.subTo = bnpSubTo;
+  BigInteger.prototype.multiplyTo = bnpMultiplyTo;
+  BigInteger.prototype.squareTo = bnpSquareTo;
+  BigInteger.prototype.divRemTo = bnpDivRemTo;
+  BigInteger.prototype.invDigit = bnpInvDigit;
+  BigInteger.prototype.isEven = bnpIsEven;
+  BigInteger.prototype.exp = bnpExp;
+
+  // public
+  BigInteger.prototype.toString = bnToString;
+  BigInteger.prototype.negate = bnNegate;
+  BigInteger.prototype.abs = bnAbs;
+  BigInteger.prototype.compareTo = bnCompareTo;
+  BigInteger.prototype.bitLength = bnBitLength;
+  BigInteger.prototype.mod = bnMod;
+  BigInteger.prototype.modPowInt = bnModPowInt;
+
+  // "constants"
+  BigInteger.ZERO = nbv(0);
+  BigInteger.ONE = nbv(1);
+
+  // jsbn2 stuff
+
+  // (protected) convert from radix string
+  function bnpFromRadix(s,b) {
+    this.fromInt(0);
+    if(b == null) b = 10;
+    var cs = this.chunkSize(b);
+    var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
+    for(var i = 0; i < s.length; ++i) {
+      var x = intAt(s,i);
+      if(x < 0) {
+        if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
+        continue;
+      }
+      w = b*w+x;
+      if(++j >= cs) {
+        this.dMultiply(d);
+        this.dAddOffset(w,0);
+        j = 0;
+        w = 0;
+      }
+    }
+    if(j > 0) {
+      this.dMultiply(Math.pow(b,j));
+      this.dAddOffset(w,0);
+    }
+    if(mi) BigInteger.ZERO.subTo(this,this);
+  }
+
+  // (protected) return x s.t. r^x < DV
+  function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
+
+  // (public) 0 if this == 0, 1 if this > 0
+  function bnSigNum() {
+    if(this.s < 0) return -1;
+    else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
+    else return 1;
+  }
+
+  // (protected) this *= n, this >= 0, 1 < n < DV
+  function bnpDMultiply(n) {
+    this[this.t] = this.am(0,n-1,this,0,0,this.t);
+    ++this.t;
+    this.clamp();
+  }
+
+  // (protected) this += n << w words, this >= 0
+  function bnpDAddOffset(n,w) {
+    if(n == 0) return;
+    while(this.t <= w) this[this.t++] = 0;
+    this[w] += n;
+    while(this[w] >= this.DV) {
+      this[w] -= this.DV;
+      if(++w >= this.t) this[this.t++] = 0;
+      ++this[w];
+    }
+  }
+
+  // (protected) convert to radix string
+  function bnpToRadix(b) {
+    if(b == null) b = 10;
+    if(this.signum() == 0 || b < 2 || b > 36) return "0";
+    var cs = this.chunkSize(b);
+    var a = Math.pow(b,cs);
+    var d = nbv(a), y = nbi(), z = nbi(), r = "";
+    this.divRemTo(d,y,z);
+    while(y.signum() > 0) {
+      r = (a+z.intValue()).toString(b).substr(1) + r;
+      y.divRemTo(d,y,z);
+    }
+    return z.intValue().toString(b) + r;
+  }
+
+  // (public) return value as integer
+  function bnIntValue() {
+    if(this.s < 0) {
+      if(this.t == 1) return this[0]-this.DV;
+      else if(this.t == 0) return -1;
+    }
+    else if(this.t == 1) return this[0];
+    else if(this.t == 0) return 0;
+    // assumes 16 < DB < 32
+    return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
+  }
+
+  // (protected) r = this + a
+  function bnpAddTo(a,r) {
+    var i = 0, c = 0, m = Math.min(a.t,this.t);
+    while(i < m) {
+      c += this[i]+a[i];
+      r[i++] = c&this.DM;
+      c >>= this.DB;
+    }
+    if(a.t < this.t) {
+      c += a.s;
+      while(i < this.t) {
+        c += this[i];
+        r[i++] = c&this.DM;
+        c >>= this.DB;
+      }
+      c += this.s;
+    }
+    else {
+      c += this.s;
+      while(i < a.t) {
+        c += a[i];
+        r[i++] = c&this.DM;
+        c >>= this.DB;
+      }
+      c += a.s;
+    }
+    r.s = (c<0)?-1:0;
+    if(c > 0) r[i++] = c;
+    else if(c < -1) r[i++] = this.DV+c;
+    r.t = i;
+    r.clamp();
+  }
+
+  BigInteger.prototype.fromRadix = bnpFromRadix;
+  BigInteger.prototype.chunkSize = bnpChunkSize;
+  BigInteger.prototype.signum = bnSigNum;
+  BigInteger.prototype.dMultiply = bnpDMultiply;
+  BigInteger.prototype.dAddOffset = bnpDAddOffset;
+  BigInteger.prototype.toRadix = bnpToRadix;
+  BigInteger.prototype.intValue = bnIntValue;
+  BigInteger.prototype.addTo = bnpAddTo;
+
+  //======= end jsbn =======
+
+  // Emscripten wrapper
+  var Wrapper = {
+    abs: function(l, h) {
+      var x = new goog.math.Long(l, h);
+      var ret;
+      if (x.isNegative()) {
+        ret = x.negate();
+      } else {
+        ret = x;
+      }
+      HEAP32[tempDoublePtr>>2] = ret.low_;
+      HEAP32[tempDoublePtr+4>>2] = ret.high_;
+    },
+    ensureTemps: function() {
+      if (Wrapper.ensuredTemps) return;
+      Wrapper.ensuredTemps = true;
+      Wrapper.two32 = new BigInteger();
+      Wrapper.two32.fromString('4294967296', 10);
+      Wrapper.two64 = new BigInteger();
+      Wrapper.two64.fromString('18446744073709551616', 10);
+      Wrapper.temp1 = new BigInteger();
+      Wrapper.temp2 = new BigInteger();
+    },
+    lh2bignum: function(l, h) {
+      var a = new BigInteger();
+      a.fromString(h.toString(), 10);
+      var b = new BigInteger();
+      a.multiplyTo(Wrapper.two32, b);
+      var c = new BigInteger();
+      c.fromString(l.toString(), 10);
+      var d = new BigInteger();
+      c.addTo(b, d);
+      return d;
+    },
+    stringify: function(l, h, unsigned) {
+      var ret = new goog.math.Long(l, h).toString();
+      if (unsigned && ret[0] == '-') {
+        // unsign slowly using jsbn bignums
+        Wrapper.ensureTemps();
+        var bignum = new BigInteger();
+        bignum.fromString(ret, 10);
+        ret = new BigInteger();
+        Wrapper.two64.addTo(bignum, ret);
+        ret = ret.toString(10);
+      }
+      return ret;
+    },
+    fromString: function(str, base, min, max, unsigned) {
+      Wrapper.ensureTemps();
+      var bignum = new BigInteger();
+      bignum.fromString(str, base);
+      var bigmin = new BigInteger();
+      bigmin.fromString(min, 10);
+      var bigmax = new BigInteger();
+      bigmax.fromString(max, 10);
+      if (unsigned && bignum.compareTo(BigInteger.ZERO) < 0) {
+        var temp = new BigInteger();
+        bignum.addTo(Wrapper.two64, temp);
+        bignum = temp;
+      }
+      var error = false;
+      if (bignum.compareTo(bigmin) < 0) {
+        bignum = bigmin;
+        error = true;
+      } else if (bignum.compareTo(bigmax) > 0) {
+        bignum = bigmax;
+        error = true;
+      }
+      var ret = goog.math.Long.fromString(bignum.toString()); // min-max checks should have clamped this to a range goog.math.Long can handle well
+      HEAP32[tempDoublePtr>>2] = ret.low_;
+      HEAP32[tempDoublePtr+4>>2] = ret.high_;
+      if (error) throw 'range error';
+    }
+  };
+  return Wrapper;
+})();
+
+//======= end closure i64 code =======
+
+
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run(['binarytrees.lua'].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run(['binarytrees.lua'].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/memops.js b/test/mjsunit/asm/embenchen/memops.js
new file mode 100644
index 0000000..e8e607c
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/memops.js
@@ -0,0 +1,8087 @@
+var EXPECTED_OUTPUT = 'final: 840.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(531);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,10,0,0,0,0,0,0,102,105,110,97,108,58,32,37,100,46,10,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,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,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,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], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  Module["_memset"] = _memset;
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+  function _abort() {
+      Module['abort']();
+    }
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+    Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+    Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+    // just add the mouse delta to the current absolut mouse position
+    // FIXME: ideally this should be clamped against the canvas size and zero
+    Browser.mouseX += Browser.mouseMovementX;
+    Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _fflush=env._fflush;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _printf=env._printf;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var _abort=env._abort;
+  var ___setErrNo=env.___setErrNo;
+  var _fwrite=env._fwrite;
+  var _sbrk=env._sbrk;
+  var _time=env._time;
+  var _mkport=env._mkport;
+  var __reallyNegative=env.__reallyNegative;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _write=env._write;
+  var _fprintf=env._fprintf;
+  var _sysconf=env._sysconf;
+  var ___errno_location=env.___errno_location;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[10] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 80 + (i5 << 2) | 0;
+    i5 = 80 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[10] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[48 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 80 + (i7 << 2) | 0;
+     i7 = 80 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[10] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[48 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[60 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 80 + (i9 << 2) | 0;
+      i7 = HEAP32[10] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 80 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[10] = i7 | i8;
+       i28 = 80 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[48 >> 2] = i4;
+     HEAP32[60 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[44 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[344 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[56 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 344 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[48 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[60 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 80 + (i9 << 2) | 0;
+       i7 = HEAP32[10] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 80 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[10] = i7 | i8;
+        i25 = 80 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[48 >> 2] = i2;
+      HEAP32[60 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[44 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[344 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[344 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[48 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[56 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 344 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 80 + (i6 << 2) | 0;
+         i5 = HEAP32[10] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 80 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[10] = i5 | i4;
+          i21 = 80 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 344 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[44 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[44 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[56 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[48 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[60 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[60 >> 2] = i2 + i12;
+   HEAP32[48 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[48 >> 2] = 0;
+   HEAP32[60 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[52 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[52 >> 2] = i31;
+  i32 = HEAP32[64 >> 2] | 0;
+  HEAP32[64 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[128] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[520 >> 2] = i18;
+    HEAP32[516 >> 2] = i18;
+    HEAP32[524 >> 2] = -1;
+    HEAP32[528 >> 2] = -1;
+    HEAP32[532 >> 2] = 0;
+    HEAP32[484 >> 2] = 0;
+    HEAP32[128] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[520 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[480 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[472 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[484 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[64 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 488 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[52 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[516 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[472 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[480 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[520 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[484 >> 2] = HEAP32[484 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[472 >> 2] | 0) + i14 | 0;
+  HEAP32[472 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[476 >> 2] | 0) >>> 0) {
+   HEAP32[476 >> 2] = i15;
+  }
+  i15 = HEAP32[64 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 488 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[52 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[64 >> 2] = i15 + i3;
+     HEAP32[52 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[68 >> 2] = HEAP32[528 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+     HEAP32[56 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 488 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[64 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[60 >> 2] | 0)) {
+        i32 = (HEAP32[48 >> 2] | 0) + i10 | 0;
+        HEAP32[48 >> 2] = i32;
+        HEAP32[60 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 344 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 80 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[10] = HEAP32[10] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 80 + (i10 << 2) | 0;
+        i9 = HEAP32[10] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 80 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[10] = i9 | i5;
+         i3 = 80 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 344 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[44 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[44 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[56 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[52 >> 2] | 0) + i10 | 0;
+       HEAP32[52 >> 2] = i32;
+       HEAP32[64 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 488 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[64 >> 2] = i17 + i4;
+    HEAP32[52 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[68 >> 2] = HEAP32[528 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[488 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[492 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[496 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[500 >> 2];
+    HEAP32[488 >> 2] = i17;
+    HEAP32[492 >> 2] = i14;
+    HEAP32[500 >> 2] = 0;
+    HEAP32[496 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 80 + (i4 << 2) | 0;
+      i5 = HEAP32[10] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 80 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[10] = i5 | i3;
+       i7 = 80 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 344 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[44 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[44 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[56 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[56 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[56 >> 2] = i17;
+    }
+    HEAP32[488 >> 2] = i17;
+    HEAP32[492 >> 2] = i14;
+    HEAP32[500 >> 2] = 0;
+    HEAP32[76 >> 2] = HEAP32[128];
+    HEAP32[72 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 80 + (i32 << 2) | 0;
+     HEAP32[80 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[80 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[64 >> 2] = i17 + i2;
+    HEAP32[52 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[68 >> 2] = HEAP32[528 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[52 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[52 >> 2] = i31;
+   i32 = HEAP32[64 >> 2] | 0;
+   HEAP32[64 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[56 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[60 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[48 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 80 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[10] = HEAP32[10] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 344 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[64 >> 2] | 0)) {
+   i21 = (HEAP32[52 >> 2] | 0) + i11 | 0;
+   HEAP32[52 >> 2] = i21;
+   HEAP32[64 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[60 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[60 >> 2] = 0;
+   HEAP32[48 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[60 >> 2] | 0)) {
+   i21 = (HEAP32[48 >> 2] | 0) + i11 | 0;
+   HEAP32[48 >> 2] = i21;
+   HEAP32[60 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 344 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[44 >> 2] = HEAP32[44 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 80 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[10] = HEAP32[10] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[60 >> 2] | 0)) {
+   HEAP32[48 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 80 + (i7 << 2) | 0;
+  i8 = HEAP32[10] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 80 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[10] = i8 | i6;
+   i4 = 80 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 344 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[44 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L205 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L205;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[56 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[56 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[44 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[72 >> 2] | 0) + -1 | 0;
+ HEAP32[72 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 496 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[72 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 400;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 4e3;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 8e3;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 55;
+     break L1;
+    }
+   case 48:
+    {
+     i7 = 0;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i3 + -48;
+     _printf(8, i2 | 0) | 0;
+     i7 = -1;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 800;
+ }
+ i5 = _malloc(1048576) | 0;
+ i6 = 0;
+ i4 = 0;
+ do {
+  i7 = 0;
+  while (1) {
+   HEAP8[i5 + i7 | 0] = i7 + i6;
+   i7 = i7 + 1 | 0;
+   if ((i7 | 0) == 1048576) {
+    i7 = 0;
+    break;
+   }
+  }
+  do {
+   i6 = (HEAP8[i5 + i7 | 0] & 1) + i6 | 0;
+   i7 = i7 + 1 | 0;
+  } while ((i7 | 0) != 1048576);
+  i6 = (i6 | 0) % 1e3 | 0;
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) < (i3 | 0));
+ HEAP32[i2 >> 2] = i6;
+ _printf(24, i2 | 0) | 0;
+ i7 = 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_fflush": _fflush, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_printf": _printf, "_send": _send, "_pwrite": _pwrite, "_abort": _abort, "___setErrNo": ___setErrNo, "_fwrite": _fwrite, "_sbrk": _sbrk, "_time": _time, "_mkport": _mkport, "__reallyNegative": __reallyNegative, "__formatString": __formatString, "_fileno": _fileno, "_write": _write, "_fprintf": _fprintf, "_sysconf": _sysconf, "___errno_location": ___errno_location, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/primes.js b/test/mjsunit/asm/embenchen/primes.js
new file mode 100644
index 0000000..32f80b8
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/primes.js
@@ -0,0 +1,5984 @@
+var EXPECTED_OUTPUT = 'lastprime: 387677.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(35);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,108,97,115,116,112,114,105,109,101,58,32,37,100,46,10,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+  function _malloc(bytes) {
+      /* Over-allocate to make sure it is byte-aligned by 8.
+       * This will leak memory, but this is only the dummy
+       * implementation (replaced by dlmalloc normally) so
+       * not an issue.
+       */
+      var ptr = Runtime.dynamicAlloc(bytes + 8);
+      return (ptr+8) & 0xFFFFFFF8;
+    }
+  Module["_malloc"] = _malloc;
+
+
+  Module["_memset"] = _memset;
+
+  function _free() {
+  }
+  Module["_free"] = _free;
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+            Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+            Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+            // just add the mouse delta to the current absolut mouse position
+            // FIXME: ideally this should be clamped against the canvas size and zero
+            Browser.mouseX += Browser.mouseMovementX;
+            Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+          var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+          flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+          HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+
+
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  var _sqrtf=Math_sqrt;
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var _free=env._free;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _printf=env._printf;
+  var _send=env._send;
+  var _pwrite=env._pwrite;
+  var _sqrtf=env._sqrtf;
+  var __reallyNegative=env.__reallyNegative;
+  var _fwrite=env._fwrite;
+  var _malloc=env._malloc;
+  var _mkport=env._mkport;
+  var _fprintf=env._fprintf;
+  var ___setErrNo=env.___setErrNo;
+  var __formatString=env.__formatString;
+  var _fileno=env._fileno;
+  var _fflush=env._fflush;
+  var _write=env._write;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _main(i3, i5) {
+ i3 = i3 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i6 = 0, i7 = 0, d8 = 0.0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i3 | 0) > 1) {
+   i3 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i3 | 0) {
+   case 50:
+    {
+     i3 = 13e4;
+     break L1;
+    }
+   case 51:
+    {
+     i4 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i3 = 61e4;
+     break L1;
+    }
+   case 53:
+    {
+     i3 = 101e4;
+     break L1;
+    }
+   case 49:
+    {
+     i3 = 33e3;
+     break L1;
+    }
+   case 48:
+    {
+     i7 = 0;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i3 + -48;
+     _printf(8, i2 | 0) | 0;
+     i7 = -1;
+     STACKTOP = i1;
+     return i7 | 0;
+    }
+   }
+  } else {
+   i4 = 4;
+  }
+ } while (0);
+ if ((i4 | 0) == 4) {
+  i3 = 22e4;
+ }
+ i4 = 2;
+ i5 = 0;
+ while (1) {
+  d8 = +Math_sqrt(+(+(i4 | 0)));
+  L15 : do {
+   if (d8 > 2.0) {
+    i7 = 2;
+    while (1) {
+     i6 = i7 + 1 | 0;
+     if (((i4 | 0) % (i7 | 0) | 0 | 0) == 0) {
+      i6 = 0;
+      break L15;
+     }
+     if (+(i6 | 0) < d8) {
+      i7 = i6;
+     } else {
+      i6 = 1;
+      break;
+     }
+    }
+   } else {
+    i6 = 1;
+   }
+  } while (0);
+  i5 = i6 + i5 | 0;
+  if ((i5 | 0) >= (i3 | 0)) {
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ HEAP32[i2 >> 2] = i4;
+ _printf(24, i2 | 0) | 0;
+ i7 = 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function runPostSets() {}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+
+
+  return { _strlen: _strlen, _memcpy: _memcpy, _main: _main, _memset: _memset, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9 };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "_free": _free, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_printf": _printf, "_send": _send, "_pwrite": _pwrite, "_sqrtf": _sqrtf, "__reallyNegative": __reallyNegative, "_fwrite": _fwrite, "_malloc": _malloc, "_mkport": _mkport, "_fprintf": _fprintf, "___setErrNo": ___setErrNo, "__formatString": __formatString, "_fileno": _fileno, "_fflush": _fflush, "_write": _write, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/embenchen/zlib.js b/test/mjsunit/asm/embenchen/zlib.js
new file mode 100644
index 0000000..d90ee38
--- /dev/null
+++ b/test/mjsunit/asm/embenchen/zlib.js
@@ -0,0 +1,14752 @@
+var EXPECTED_OUTPUT = 'sizes: 100000,25906\nok.\n';
+var Module = {
+  arguments: [1],
+  print: function(x) {Module.printBuffer += x + '\n';},
+  preRun: [function() {Module.printBuffer = ''}],
+  postRun: [function() {
+    assertEquals(EXPECTED_OUTPUT, Module.printBuffer);
+  }],
+};
+// The Module object: Our interface to the outside world. We import
+// and export values on it, and do the work to get that through
+// closure compiler if necessary. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to do an eval in order to handle the closure compiler
+// case, where this code here is minified but Module was defined
+// elsewhere (e.g. case 4 above). We also need to check if Module
+// already exists (e.g. case 3 above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define   var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module;
+if (!Module) Module = (typeof Module !== 'undefined' ? Module : null) || {};
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+for (var key in Module) {
+  if (Module.hasOwnProperty(key)) {
+    moduleOverrides[key] = Module[key];
+  }
+}
+
+// The environment setup code below is customized to use Module.
+// *** Environment setup code ***
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (ENVIRONMENT_IS_NODE) {
+  // Expose functionality in the same simple way that the shells work
+  // Note that we pollute the global namespace here, otherwise we break in node
+  if (!Module['print']) Module['print'] = function print(x) {
+    process['stdout'].write(x + '\n');
+  };
+  if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+    process['stderr'].write(x + '\n');
+  };
+
+  var nodeFS = require('fs');
+  var nodePath = require('path');
+
+  Module['read'] = function read(filename, binary) {
+    filename = nodePath['normalize'](filename);
+    var ret = nodeFS['readFileSync'](filename);
+    // The path is absolute if the normalized version is the same as the resolved.
+    if (!ret && filename != nodePath['resolve'](filename)) {
+      filename = path.join(__dirname, '..', 'src', filename);
+      ret = nodeFS['readFileSync'](filename);
+    }
+    if (ret && !binary) ret = ret.toString();
+    return ret;
+  };
+
+  Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
+
+  Module['load'] = function load(f) {
+    globalEval(read(f));
+  };
+
+  Module['arguments'] = process['argv'].slice(2);
+
+  module['exports'] = Module;
+}
+else if (ENVIRONMENT_IS_SHELL) {
+  if (!Module['print']) Module['print'] = print;
+  if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
+
+  if (typeof read != 'undefined') {
+    Module['read'] = read;
+  } else {
+    Module['read'] = function read() { throw 'no read() available (jsc?)' };
+  }
+
+  Module['readBinary'] = function readBinary(f) {
+    return read(f, 'binary');
+  };
+
+  if (typeof scriptArgs != 'undefined') {
+    Module['arguments'] = scriptArgs;
+  } else if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  this['Module'] = Module;
+
+  eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
+}
+else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+  Module['read'] = function read(url) {
+    var xhr = new XMLHttpRequest();
+    xhr.open('GET', url, false);
+    xhr.send(null);
+    return xhr.responseText;
+  };
+
+  if (typeof arguments != 'undefined') {
+    Module['arguments'] = arguments;
+  }
+
+  if (typeof console !== 'undefined') {
+    if (!Module['print']) Module['print'] = function print(x) {
+      console.log(x);
+    };
+    if (!Module['printErr']) Module['printErr'] = function printErr(x) {
+      console.log(x);
+    };
+  } else {
+    // Probably a worker, and without console.log. We can do very little here...
+    var TRY_USE_DUMP = false;
+    if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+      dump(x);
+    }) : (function(x) {
+      // self.postMessage(x); // enable this if you want stdout to be sent as messages
+    }));
+  }
+
+  if (ENVIRONMENT_IS_WEB) {
+    window['Module'] = Module;
+  } else {
+    Module['load'] = importScripts;
+  }
+}
+else {
+  // Unreachable because SHELL is dependant on the others
+  throw 'Unknown runtime environment. Where are we?';
+}
+
+function globalEval(x) {
+  eval.call(null, x);
+}
+if (!Module['load'] == 'undefined' && Module['read']) {
+  Module['load'] = function load(f) {
+    globalEval(Module['read'](f));
+  };
+}
+if (!Module['print']) {
+  Module['print'] = function(){};
+}
+if (!Module['printErr']) {
+  Module['printErr'] = Module['print'];
+}
+if (!Module['arguments']) {
+  Module['arguments'] = [];
+}
+// *** Environment setup code ***
+
+// Closure helpers
+Module.print = Module['print'];
+Module.printErr = Module['printErr'];
+
+// Callbacks
+Module['preRun'] = [];
+Module['postRun'] = [];
+
+// Merge back in the overrides
+for (var key in moduleOverrides) {
+  if (moduleOverrides.hasOwnProperty(key)) {
+    Module[key] = moduleOverrides[key];
+  }
+}
+
+
+
+// === Auto-generated preamble library stuff ===
+
+//========================================
+// Runtime code shared with compiler
+//========================================
+
+var Runtime = {
+  stackSave: function () {
+    return STACKTOP;
+  },
+  stackRestore: function (stackTop) {
+    STACKTOP = stackTop;
+  },
+  forceAlign: function (target, quantum) {
+    quantum = quantum || 4;
+    if (quantum == 1) return target;
+    if (isNumber(target) && isNumber(quantum)) {
+      return Math.ceil(target/quantum)*quantum;
+    } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
+      return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
+    }
+    return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
+  },
+  isNumberType: function (type) {
+    return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
+  },
+  isPointerType: function isPointerType(type) {
+  return type[type.length-1] == '*';
+},
+  isStructType: function isStructType(type) {
+  if (isPointerType(type)) return false;
+  if (isArrayType(type)) return true;
+  if (/<?\{ ?[^}]* ?\}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
+  // See comment in isStructPointerType()
+  return type[0] == '%';
+},
+  INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
+  FLOAT_TYPES: {"float":0,"double":0},
+  or64: function (x, y) {
+    var l = (x | 0) | (y | 0);
+    var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  and64: function (x, y) {
+    var l = (x | 0) & (y | 0);
+    var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  xor64: function (x, y) {
+    var l = (x | 0) ^ (y | 0);
+    var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
+    return l + h;
+  },
+  getNativeTypeSize: function (type) {
+    switch (type) {
+      case 'i1': case 'i8': return 1;
+      case 'i16': return 2;
+      case 'i32': return 4;
+      case 'i64': return 8;
+      case 'float': return 4;
+      case 'double': return 8;
+      default: {
+        if (type[type.length-1] === '*') {
+          return Runtime.QUANTUM_SIZE; // A pointer
+        } else if (type[0] === 'i') {
+          var bits = parseInt(type.substr(1));
+          assert(bits % 8 === 0);
+          return bits/8;
+        } else {
+          return 0;
+        }
+      }
+    }
+  },
+  getNativeFieldSize: function (type) {
+    return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
+  },
+  dedup: function dedup(items, ident) {
+  var seen = {};
+  if (ident) {
+    return items.filter(function(item) {
+      if (seen[item[ident]]) return false;
+      seen[item[ident]] = true;
+      return true;
+    });
+  } else {
+    return items.filter(function(item) {
+      if (seen[item]) return false;
+      seen[item] = true;
+      return true;
+    });
+  }
+},
+  set: function set() {
+  var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
+  var ret = {};
+  for (var i = 0; i < args.length; i++) {
+    ret[args[i]] = 0;
+  }
+  return ret;
+},
+  STACK_ALIGN: 8,
+  getAlignSize: function (type, size, vararg) {
+    // we align i64s and doubles on 64-bit boundaries, unlike x86
+    if (!vararg && (type == 'i64' || type == 'double')) return 8;
+    if (!type) return Math.min(size, 8); // align structures internally to 64 bits
+    return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
+  },
+  calculateStructAlignment: function calculateStructAlignment(type) {
+    type.flatSize = 0;
+    type.alignSize = 0;
+    var diffs = [];
+    var prev = -1;
+    var index = 0;
+    type.flatIndexes = type.fields.map(function(field) {
+      index++;
+      var size, alignSize;
+      if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
+        size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
+        alignSize = Runtime.getAlignSize(field, size);
+      } else if (Runtime.isStructType(field)) {
+        if (field[1] === '0') {
+          // this is [0 x something]. When inside another structure like here, it must be at the end,
+          // and it adds no size
+          // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+          size = 0;
+          if (Types.types[field]) {
+            alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+          } else {
+            alignSize = type.alignSize || QUANTUM_SIZE;
+          }
+        } else {
+          size = Types.types[field].flatSize;
+          alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+        }
+      } else if (field[0] == 'b') {
+        // bN, large number field, like a [N x i8]
+        size = field.substr(1)|0;
+        alignSize = 1;
+      } else if (field[0] === '<') {
+        // vector type
+        size = alignSize = Types.types[field].flatSize; // fully aligned
+      } else if (field[0] === 'i') {
+        // illegal integer field, that could not be legalized because it is an internal structure field
+        // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+        size = alignSize = parseInt(field.substr(1))/8;
+        assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
+      } else {
+        assert(false, 'invalid type for calculateStructAlignment');
+      }
+      if (type.packed) alignSize = 1;
+      type.alignSize = Math.max(type.alignSize, alignSize);
+      var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
+      type.flatSize = curr + size;
+      if (prev >= 0) {
+        diffs.push(curr-prev);
+      }
+      prev = curr;
+      return curr;
+    });
+    if (type.name_ && type.name_[0] === '[') {
+      // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+      // allocating a potentially huge array for [999999 x i8] etc.
+      type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+    }
+    type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
+    if (diffs.length == 0) {
+      type.flatFactor = type.flatSize;
+    } else if (Runtime.dedup(diffs).length == 1) {
+      type.flatFactor = diffs[0];
+    }
+    type.needsFlattening = (type.flatFactor != 1);
+    return type.flatIndexes;
+  },
+  generateStructInfo: function (struct, typeName, offset) {
+    var type, alignment;
+    if (typeName) {
+      offset = offset || 0;
+      type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
+      if (!type) return null;
+      if (type.fields.length != struct.length) {
+        printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
+        return null;
+      }
+      alignment = type.flatIndexes;
+    } else {
+      var type = { fields: struct.map(function(item) { return item[0] }) };
+      alignment = Runtime.calculateStructAlignment(type);
+    }
+    var ret = {
+      __size__: type.flatSize
+    };
+    if (typeName) {
+      struct.forEach(function(item, i) {
+        if (typeof item === 'string') {
+          ret[item] = alignment[i] + offset;
+        } else {
+          // embedded struct
+          var key;
+          for (var k in item) key = k;
+          ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
+        }
+      });
+    } else {
+      struct.forEach(function(item, i) {
+        ret[item[1]] = alignment[i];
+      });
+    }
+    return ret;
+  },
+  dynCall: function (sig, ptr, args) {
+    if (args && args.length) {
+      if (!args.splice) args = Array.prototype.slice.call(args);
+      args.splice(0, 0, ptr);
+      return Module['dynCall_' + sig].apply(null, args);
+    } else {
+      return Module['dynCall_' + sig].call(null, ptr);
+    }
+  },
+  functionPointers: [],
+  addFunction: function (func) {
+    for (var i = 0; i < Runtime.functionPointers.length; i++) {
+      if (!Runtime.functionPointers[i]) {
+        Runtime.functionPointers[i] = func;
+        return 2*(1 + i);
+      }
+    }
+    throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
+  },
+  removeFunction: function (index) {
+    Runtime.functionPointers[(index-2)/2] = null;
+  },
+  getAsmConst: function (code, numArgs) {
+    // code is a constant string on the heap, so we can cache these
+    if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+    var func = Runtime.asmConstCache[code];
+    if (func) return func;
+    var args = [];
+    for (var i = 0; i < numArgs; i++) {
+      args.push(String.fromCharCode(36) + i); // $0, $1 etc
+    }
+    var source = Pointer_stringify(code);
+    if (source[0] === '"') {
+      // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+      if (source.indexOf('"', 1) === source.length-1) {
+        source = source.substr(1, source.length-2);
+      } else {
+        // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+        abort('invalid EM_ASM input |' + source + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+      }
+    }
+    try {
+      var evalled = eval('(function(' + args.join(',') + '){ ' + source + ' })'); // new Function does not allow upvars in node
+    } catch(e) {
+      Module.printErr('error in executing inline EM_ASM code: ' + e + ' on: \n\n' + source + '\n\nwith args |' + args + '| (make sure to use the right one out of EM_ASM, EM_ASM_ARGS, etc.)');
+      throw e;
+    }
+    return Runtime.asmConstCache[code] = evalled;
+  },
+  warnOnce: function (text) {
+    if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
+    if (!Runtime.warnOnce.shown[text]) {
+      Runtime.warnOnce.shown[text] = 1;
+      Module.printErr(text);
+    }
+  },
+  funcWrappers: {},
+  getFuncWrapper: function (func, sig) {
+    assert(sig);
+    if (!Runtime.funcWrappers[func]) {
+      Runtime.funcWrappers[func] = function dynCall_wrapper() {
+        return Runtime.dynCall(sig, func, arguments);
+      };
+    }
+    return Runtime.funcWrappers[func];
+  },
+  UTF8Processor: function () {
+    var buffer = [];
+    var needed = 0;
+    this.processCChar = function (code) {
+      code = code & 0xFF;
+
+      if (buffer.length == 0) {
+        if ((code & 0x80) == 0x00) {        // 0xxxxxxx
+          return String.fromCharCode(code);
+        }
+        buffer.push(code);
+        if ((code & 0xE0) == 0xC0) {        // 110xxxxx
+          needed = 1;
+        } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
+          needed = 2;
+        } else {                            // 11110xxx
+          needed = 3;
+        }
+        return '';
+      }
+
+      if (needed) {
+        buffer.push(code);
+        needed--;
+        if (needed > 0) return '';
+      }
+
+      var c1 = buffer[0];
+      var c2 = buffer[1];
+      var c3 = buffer[2];
+      var c4 = buffer[3];
+      var ret;
+      if (buffer.length == 2) {
+        ret = String.fromCharCode(((c1 & 0x1F) << 6)  | (c2 & 0x3F));
+      } else if (buffer.length == 3) {
+        ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)  | (c3 & 0x3F));
+      } else {
+        // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+        var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+                        ((c3 & 0x3F) << 6)  | (c4 & 0x3F);
+        ret = String.fromCharCode(
+          Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+          (codePoint - 0x10000) % 0x400 + 0xDC00);
+      }
+      buffer.length = 0;
+      return ret;
+    }
+    this.processJSString = function processJSString(string) {
+      /* TODO: use TextEncoder when present,
+        var encoder = new TextEncoder();
+        encoder['encoding'] = "utf-8";
+        var utf8Array = encoder['encode'](aMsg.data);
+      */
+      string = unescape(encodeURIComponent(string));
+      var ret = [];
+      for (var i = 0; i < string.length; i++) {
+        ret.push(string.charCodeAt(i));
+      }
+      return ret;
+    }
+  },
+  getCompilerSetting: function (name) {
+    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work';
+  },
+  stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8); return ret; },
+  staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
+  dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + size)|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
+  alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
+  makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },
+  GLOBAL_BASE: 8,
+  QUANTUM_SIZE: 4,
+  __dummy__: 0
+}
+
+
+Module['Runtime'] = Runtime;
+
+
+
+
+
+
+
+
+
+//========================================
+// Runtime essentials
+//========================================
+
+var __THREW__ = 0; // Used in checking for thrown exceptions.
+
+var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
+
+var undef = 0;
+// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
+// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
+var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
+var tempI64, tempI64b;
+var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
+
+function assert(condition, text) {
+  if (!condition) {
+    abort('Assertion failed: ' + text);
+  }
+}
+
+var globalScope = this;
+
+// C calling interface. A convenient way to call C functions (in C files, or
+// defined with extern "C").
+//
+// Note: LLVM optimizations can inline and remove functions, after which you will not be
+//       able to call them. Closure can also do so. To avoid that, add your function to
+//       the exports using something like
+//
+//         -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
+//
+// @param ident      The name of the C function (note that C++ functions will be name-mangled - use extern "C")
+// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
+//                   'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
+// @param argTypes   An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
+//                   except that 'array' is not possible (there is no way for us to know the length of the array)
+// @param args       An array of the arguments to the function, as native JS values (as in returnType)
+//                   Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
+// @return           The return value, as a native JS value (as in returnType)
+function ccall(ident, returnType, argTypes, args) {
+  return ccallFunc(getCFunc(ident), returnType, argTypes, args);
+}
+Module["ccall"] = ccall;
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+  try {
+    var func = Module['_' + ident]; // closure exported function
+    if (!func) func = eval('_' + ident); // explicit lookup
+  } catch(e) {
+  }
+  assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
+  return func;
+}
+
+// Internal function that does a C call using a function, not an identifier
+function ccallFunc(func, returnType, argTypes, args) {
+  var stack = 0;
+  function toC(value, type) {
+    if (type == 'string') {
+      if (value === null || value === undefined || value === 0) return 0; // null string
+      value = intArrayFromString(value);
+      type = 'array';
+    }
+    if (type == 'array') {
+      if (!stack) stack = Runtime.stackSave();
+      var ret = Runtime.stackAlloc(value.length);
+      writeArrayToMemory(value, ret);
+      return ret;
+    }
+    return value;
+  }
+  function fromC(value, type) {
+    if (type == 'string') {
+      return Pointer_stringify(value);
+    }
+    assert(type != 'array');
+    return value;
+  }
+  var i = 0;
+  var cArgs = args ? args.map(function(arg) {
+    return toC(arg, argTypes[i++]);
+  }) : [];
+  var ret = fromC(func.apply(null, cArgs), returnType);
+  if (stack) Runtime.stackRestore(stack);
+  return ret;
+}
+
+// Returns a native JS wrapper for a C function. This is similar to ccall, but
+// returns a function you can call repeatedly in a normal way. For example:
+//
+//   var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
+//   alert(my_function(5, 22));
+//   alert(my_function(99, 12));
+//
+function cwrap(ident, returnType, argTypes) {
+  var func = getCFunc(ident);
+  return function() {
+    return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
+  }
+}
+Module["cwrap"] = cwrap;
+
+// Sets a value in memory in a dynamic way at run-time. Uses the
+// type data. This is the same as makeSetValue, except that
+// makeSetValue is done at compile-time and generates the needed
+// code then, whereas this function picks the right code at
+// run-time.
+// Note that setValue and getValue only do *aligned* writes and reads!
+// Note that ccall uses JS types as for defining types, while setValue and
+// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
+function setValue(ptr, value, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': HEAP8[(ptr)]=value; break;
+      case 'i8': HEAP8[(ptr)]=value; break;
+      case 'i16': HEAP16[((ptr)>>1)]=value; break;
+      case 'i32': HEAP32[((ptr)>>2)]=value; break;
+      case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
+      case 'float': HEAPF32[((ptr)>>2)]=value; break;
+      case 'double': HEAPF64[((ptr)>>3)]=value; break;
+      default: abort('invalid type for setValue: ' + type);
+    }
+}
+Module['setValue'] = setValue;
+
+// Parallel to setValue.
+function getValue(ptr, type, noSafe) {
+  type = type || 'i8';
+  if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+    switch(type) {
+      case 'i1': return HEAP8[(ptr)];
+      case 'i8': return HEAP8[(ptr)];
+      case 'i16': return HEAP16[((ptr)>>1)];
+      case 'i32': return HEAP32[((ptr)>>2)];
+      case 'i64': return HEAP32[((ptr)>>2)];
+      case 'float': return HEAPF32[((ptr)>>2)];
+      case 'double': return HEAPF64[((ptr)>>3)];
+      default: abort('invalid type for setValue: ' + type);
+    }
+  return null;
+}
+Module['getValue'] = getValue;
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
+var ALLOC_NONE = 4; // Do not allocate
+Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
+Module['ALLOC_STACK'] = ALLOC_STACK;
+Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+//             is a little tricky (see docs right below). The reason is that it is optimized
+//             for multiple syntaxes to save space in generated code. So you should
+//             normally not use allocate(), and instead allocate memory using _malloc(),
+//             initialize it with setValue(), and so forth.
+// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
+//        in *bytes* (note that this is sometimes confusing: the next parameter does not
+//        affect this!)
+// @types: Either an array of types, one for each byte (or 0 if no type at that position),
+//         or a single type which is used for the entire block. This only matters if there
+//         is initial data - if @slab is a number, then this does not matter at all and is
+//         ignored.
+// @allocator: How to allocate memory, see ALLOC_*
+function allocate(slab, types, allocator, ptr) {
+  var zeroinit, size;
+  if (typeof slab === 'number') {
+    zeroinit = true;
+    size = slab;
+  } else {
+    zeroinit = false;
+    size = slab.length;
+  }
+
+  var singleType = typeof types === 'string' ? types : null;
+
+  var ret;
+  if (allocator == ALLOC_NONE) {
+    ret = ptr;
+  } else {
+    ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+  }
+
+  if (zeroinit) {
+    var ptr = ret, stop;
+    assert((ret & 3) == 0);
+    stop = ret + (size & ~3);
+    for (; ptr < stop; ptr += 4) {
+      HEAP32[((ptr)>>2)]=0;
+    }
+    stop = ret + size;
+    while (ptr < stop) {
+      HEAP8[((ptr++)|0)]=0;
+    }
+    return ret;
+  }
+
+  if (singleType === 'i8') {
+    if (slab.subarray || slab.slice) {
+      HEAPU8.set(slab, ret);
+    } else {
+      HEAPU8.set(new Uint8Array(slab), ret);
+    }
+    return ret;
+  }
+
+  var i = 0, type, typeSize, previousType;
+  while (i < size) {
+    var curr = slab[i];
+
+    if (typeof curr === 'function') {
+      curr = Runtime.getFunctionIndex(curr);
+    }
+
+    type = singleType || types[i];
+    if (type === 0) {
+      i++;
+      continue;
+    }
+
+    if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
+
+    setValue(ret+i, curr, type);
+
+    // no need to look up size unless type changes, so cache it
+    if (previousType !== type) {
+      typeSize = Runtime.getNativeTypeSize(type);
+      previousType = type;
+    }
+    i += typeSize;
+  }
+
+  return ret;
+}
+Module['allocate'] = allocate;
+
+function Pointer_stringify(ptr, /* optional */ length) {
+  // TODO: use TextDecoder
+  // Find the length, and check for UTF while doing so
+  var hasUtf = false;
+  var t;
+  var i = 0;
+  while (1) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    if (t >= 128) hasUtf = true;
+    else if (t == 0 && !length) break;
+    i++;
+    if (length && i == length) break;
+  }
+  if (!length) length = i;
+
+  var ret = '';
+
+  if (!hasUtf) {
+    var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
+    var curr;
+    while (length > 0) {
+      curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
+      ret = ret ? ret + curr : curr;
+      ptr += MAX_CHUNK;
+      length -= MAX_CHUNK;
+    }
+    return ret;
+  }
+
+  var utf8 = new Runtime.UTF8Processor();
+  for (i = 0; i < length; i++) {
+    t = HEAPU8[(((ptr)+(i))|0)];
+    ret += utf8.processCChar(t);
+  }
+  return ret;
+}
+Module['Pointer_stringify'] = Pointer_stringify;
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF16ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+    if (codeUnit == 0)
+      return str;
+    ++i;
+    // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+    str += String.fromCharCode(codeUnit);
+  }
+}
+Module['UTF16ToString'] = UTF16ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
+function stringToUTF16(str, outPtr) {
+  for(var i = 0; i < str.length; ++i) {
+    // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+    var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+    HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
+}
+Module['stringToUTF16'] = stringToUTF16;
+
+// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+function UTF32ToString(ptr) {
+  var i = 0;
+
+  var str = '';
+  while (1) {
+    var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+    if (utf32 == 0)
+      return str;
+    ++i;
+    // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+    if (utf32 >= 0x10000) {
+      var ch = utf32 - 0x10000;
+      str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+    } else {
+      str += String.fromCharCode(utf32);
+    }
+  }
+}
+Module['UTF32ToString'] = UTF32ToString;
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
+// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
+function stringToUTF32(str, outPtr) {
+  var iChar = 0;
+  for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
+    // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+    var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
+    if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+      var trailSurrogate = str.charCodeAt(++iCodeUnit);
+      codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+    }
+    HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
+    ++iChar;
+  }
+  // Null-terminate the pointer to the HEAP.
+  HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
+}
+Module['stringToUTF32'] = stringToUTF32;
+
+function demangle(func) {
+  var i = 3;
+  // params, etc.
+  var basicTypes = {
+    'v': 'void',
+    'b': 'bool',
+    'c': 'char',
+    's': 'short',
+    'i': 'int',
+    'l': 'long',
+    'f': 'float',
+    'd': 'double',
+    'w': 'wchar_t',
+    'a': 'signed char',
+    'h': 'unsigned char',
+    't': 'unsigned short',
+    'j': 'unsigned int',
+    'm': 'unsigned long',
+    'x': 'long long',
+    'y': 'unsigned long long',
+    'z': '...'
+  };
+  var subs = [];
+  var first = true;
+  function dump(x) {
+    //return;
+    if (x) Module.print(x);
+    Module.print(func);
+    var pre = '';
+    for (var a = 0; a < i; a++) pre += ' ';
+    Module.print (pre + '^');
+  }
+  function parseNested() {
+    i++;
+    if (func[i] === 'K') i++; // ignore const
+    var parts = [];
+    while (func[i] !== 'E') {
+      if (func[i] === 'S') { // substitution
+        i++;
+        var next = func.indexOf('_', i);
+        var num = func.substring(i, next) || 0;
+        parts.push(subs[num] || '?');
+        i = next+1;
+        continue;
+      }
+      if (func[i] === 'C') { // constructor
+        parts.push(parts[parts.length-1]);
+        i += 2;
+        continue;
+      }
+      var size = parseInt(func.substr(i));
+      var pre = size.toString().length;
+      if (!size || !pre) { i--; break; } // counter i++ below us
+      var curr = func.substr(i + pre, size);
+      parts.push(curr);
+      subs.push(curr);
+      i += pre + size;
+    }
+    i++; // skip E
+    return parts;
+  }
+  function parse(rawList, limit, allowVoid) { // main parser
+    limit = limit || Infinity;
+    var ret = '', list = [];
+    function flushList() {
+      return '(' + list.join(', ') + ')';
+    }
+    var name;
+    if (func[i] === 'N') {
+      // namespaced N-E
+      name = parseNested().join('::');
+      limit--;
+      if (limit === 0) return rawList ? [name] : name;
+    } else {
+      // not namespaced
+      if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
+      var size = parseInt(func.substr(i));
+      if (size) {
+        var pre = size.toString().length;
+        name = func.substr(i + pre, size);
+        i += pre + size;
+      }
+    }
+    first = false;
+    if (func[i] === 'I') {
+      i++;
+      var iList = parse(true);
+      var iRet = parse(true, 1, true);
+      ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
+    } else {
+      ret = name;
+    }
+    paramLoop: while (i < func.length && limit-- > 0) {
+      //dump('paramLoop');
+      var c = func[i++];
+      if (c in basicTypes) {
+        list.push(basicTypes[c]);
+      } else {
+        switch (c) {
+          case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+          case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
+          case 'L': { // literal
+            i++; // skip basic type
+            var end = func.indexOf('E', i);
+            var size = end - i;
+            list.push(func.substr(i, size));
+            i += size + 2; // size + 'EE'
+            break;
+          }
+          case 'A': { // array
+            var size = parseInt(func.substr(i));
+            i += size.toString().length;
+            if (func[i] !== '_') throw '?';
+            i++; // skip _
+            list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+            break;
+          }
+          case 'E': break paramLoop;
+          default: ret += '?' + c; break paramLoop;
+        }
+      }
+    }
+    if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
+    if (rawList) {
+      if (ret) {
+        list.push(ret + '?');
+      }
+      return list;
+    } else {
+      return ret + flushList();
+    }
+  }
+  try {
+    // Special-case the entry point, since its name differs from other name mangling.
+    if (func == 'Object._main' || func == '_main') {
+      return 'main()';
+    }
+    if (typeof func === 'number') func = Pointer_stringify(func);
+    if (func[0] !== '_') return func;
+    if (func[1] !== '_') return func; // C function
+    if (func[2] !== 'Z') return func;
+    switch (func[3]) {
+      case 'n': return 'operator new()';
+      case 'd': return 'operator delete()';
+    }
+    return parse();
+  } catch(e) {
+    return func;
+  }
+}
+
+function demangleAll(text) {
+  return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
+}
+
+function stackTrace() {
+  var stack = new Error().stack;
+  return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
+}
+
+// Memory management
+
+var PAGE_SIZE = 4096;
+function alignMemoryPage(x) {
+  return (x+4095)&-4096;
+}
+
+var HEAP;
+var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+
+var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
+var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
+var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
+
+function enlargeMemory() {
+  abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
+}
+
+var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
+var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 134217728;
+var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
+
+var totalMemory = 4096;
+while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
+  if (totalMemory < 16*1024*1024) {
+    totalMemory *= 2;
+  } else {
+    totalMemory += 16*1024*1024
+  }
+}
+if (totalMemory !== TOTAL_MEMORY) {
+  Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable');
+  TOTAL_MEMORY = totalMemory;
+}
+
+// Initialize the runtime's memory
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+       'JS engine does not provide full typed array support');
+
+var buffer = new ArrayBuffer(TOTAL_MEMORY);
+HEAP8 = new Int8Array(buffer);
+HEAP16 = new Int16Array(buffer);
+HEAP32 = new Int32Array(buffer);
+HEAPU8 = new Uint8Array(buffer);
+HEAPU16 = new Uint16Array(buffer);
+HEAPU32 = new Uint32Array(buffer);
+HEAPF32 = new Float32Array(buffer);
+HEAPF64 = new Float64Array(buffer);
+
+// Endianness check (note: assumes compiler arch was little-endian)
+HEAP32[0] = 255;
+assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
+
+Module['HEAP'] = HEAP;
+Module['HEAP8'] = HEAP8;
+Module['HEAP16'] = HEAP16;
+Module['HEAP32'] = HEAP32;
+Module['HEAPU8'] = HEAPU8;
+Module['HEAPU16'] = HEAPU16;
+Module['HEAPU32'] = HEAPU32;
+Module['HEAPF32'] = HEAPF32;
+Module['HEAPF64'] = HEAPF64;
+
+function callRuntimeCallbacks(callbacks) {
+  while(callbacks.length > 0) {
+    var callback = callbacks.shift();
+    if (typeof callback == 'function') {
+      callback();
+      continue;
+    }
+    var func = callback.func;
+    if (typeof func === 'number') {
+      if (callback.arg === undefined) {
+        Runtime.dynCall('v', func);
+      } else {
+        Runtime.dynCall('vi', func, [callback.arg]);
+      }
+    } else {
+      func(callback.arg === undefined ? null : callback.arg);
+    }
+  }
+}
+
+var __ATPRERUN__  = []; // functions called before the runtime is initialized
+var __ATINIT__    = []; // functions called during startup
+var __ATMAIN__    = []; // functions called when main() is to be run
+var __ATEXIT__    = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the runtime has exited
+
+var runtimeInitialized = false;
+
+function preRun() {
+  // compatibility - merge in anything from Module['preRun'] at this time
+  if (Module['preRun']) {
+    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+    while (Module['preRun'].length) {
+      addOnPreRun(Module['preRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function ensureInitRuntime() {
+  if (runtimeInitialized) return;
+  runtimeInitialized = true;
+  callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+  callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+  callRuntimeCallbacks(__ATEXIT__);
+}
+
+function postRun() {
+  // compatibility - merge in anything from Module['postRun'] at this time
+  if (Module['postRun']) {
+    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+    while (Module['postRun'].length) {
+      addOnPostRun(Module['postRun'].shift());
+    }
+  }
+  callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+  __ATPRERUN__.unshift(cb);
+}
+Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
+
+function addOnInit(cb) {
+  __ATINIT__.unshift(cb);
+}
+Module['addOnInit'] = Module.addOnInit = addOnInit;
+
+function addOnPreMain(cb) {
+  __ATMAIN__.unshift(cb);
+}
+Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
+
+function addOnExit(cb) {
+  __ATEXIT__.unshift(cb);
+}
+Module['addOnExit'] = Module.addOnExit = addOnExit;
+
+function addOnPostRun(cb) {
+  __ATPOSTRUN__.unshift(cb);
+}
+Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
+
+// Tools
+
+// This processes a JS string into a C-line array of numbers, 0-terminated.
+// For LLVM-originating strings, see parser.js:parseLLVMString function
+function intArrayFromString(stringy, dontAddNull, length /* optional */) {
+  var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
+  if (length) {
+    ret.length = length;
+  }
+  if (!dontAddNull) {
+    ret.push(0);
+  }
+  return ret;
+}
+Module['intArrayFromString'] = intArrayFromString;
+
+function intArrayToString(array) {
+  var ret = [];
+  for (var i = 0; i < array.length; i++) {
+    var chr = array[i];
+    if (chr > 0xFF) {
+      chr &= 0xFF;
+    }
+    ret.push(String.fromCharCode(chr));
+  }
+  return ret.join('');
+}
+Module['intArrayToString'] = intArrayToString;
+
+// Write a Javascript array to somewhere in the heap
+function writeStringToMemory(string, buffer, dontAddNull) {
+  var array = intArrayFromString(string, dontAddNull);
+  var i = 0;
+  while (i < array.length) {
+    var chr = array[i];
+    HEAP8[(((buffer)+(i))|0)]=chr;
+    i = i + 1;
+  }
+}
+Module['writeStringToMemory'] = writeStringToMemory;
+
+function writeArrayToMemory(array, buffer) {
+  for (var i = 0; i < array.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=array[i];
+  }
+}
+Module['writeArrayToMemory'] = writeArrayToMemory;
+
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+  for (var i = 0; i < str.length; i++) {
+    HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
+  }
+  if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
+}
+Module['writeAsciiToMemory'] = writeAsciiToMemory;
+
+function unSign(value, bits, ignore) {
+  if (value >= 0) {
+    return value;
+  }
+  return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
+                    : Math.pow(2, bits)         + value;
+}
+function reSign(value, bits, ignore) {
+  if (value <= 0) {
+    return value;
+  }
+  var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
+                        : Math.pow(2, bits-1);
+  if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
+                                                       // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
+                                                       // TODO: In i64 mode 1, resign the two parts separately and safely
+    value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
+  }
+  return value;
+}
+
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
+  var ah  = a >>> 16;
+  var al = a & 0xffff;
+  var bh  = b >>> 16;
+  var bl = b & 0xffff;
+  return (al*bl + ((ah*bl + al*bh) << 16))|0;
+};
+Math.imul = Math['imul'];
+
+
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_fround = Math.fround;
+var Math_min = Math.min;
+
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+
+function addRunDependency(id) {
+  runDependencies++;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+}
+Module['addRunDependency'] = addRunDependency;
+function removeRunDependency(id) {
+  runDependencies--;
+  if (Module['monitorRunDependencies']) {
+    Module['monitorRunDependencies'](runDependencies);
+  }
+  if (runDependencies == 0) {
+    if (runDependencyWatcher !== null) {
+      clearInterval(runDependencyWatcher);
+      runDependencyWatcher = null;
+    }
+    if (dependenciesFulfilled) {
+      var callback = dependenciesFulfilled;
+      dependenciesFulfilled = null;
+      callback(); // can add another dependenciesFulfilled
+    }
+  }
+}
+Module['removeRunDependency'] = removeRunDependency;
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+
+var memoryInitializer = null;
+
+// === Body ===
+
+
+
+
+
+STATIC_BASE = 8;
+
+STATICTOP = STATIC_BASE + Runtime.alignMemory(14963);
+/* global initializers */ __ATINIT__.push();
+
+
+/* memory initializer */ allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,115,105,122,101,115,58,32,37,100,44,37,100,10,0,0,0,100,101,99,111,109,112,114,101,115,115,101,100,83,105,122,101,32,61,61,32,115,105,122,101,0,0,0,0,0,0,0,0,47,116,109,112,47,101,109,115,99,114,105,112,116,101,110,95,116,101,109,112,47,122,108,105,98,46,99,0,0,0,0,0,100,111,105,116,0,0,0,0,115,116,114,99,109,112,40,98,117,102,102,101,114,44,32,98,117,102,102,101,114,51,41,32,61,61,32,48,0,0,0,0,101,114,114,111,114,58,32,37,100,92,110,0,0,0,0,0,111,107,46,0,0,0,0,0,49,46,50,46,53,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,4,0,8,0,4,0,2,0,0,0,4,0,5,0,16,0,8,0,2,0,0,0,4,0,6,0,32,0,32,0,2,0,0,0,4,0,4,0,16,0,16,0,3,0,0,0,8,0,16,0,32,0,32,0,3,0,0,0,8,0,16,0,128,0,128,0,3,0,0,0,8,0,32,0,128,0,0,1,3,0,0,0,32,0,128,0,2,1,0,4,3,0,0,0,32,0,2,1,2,1,0,16,3,0,0,0,0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,0,0,16,17,18,18,19,19,20,20,20,20,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,112,4,0,0,104,9,0,0,1,1,0,0,30,1,0,0,15,0,0,0,0,0,0,0,240,8,0,0,88,10,0,0,0,0,0,0,30,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,96,11,0,0,0,0,0,0,19,0,0,0,7,0,0,0,0,0,0,0,12,0,8,0,140,0,8,0,76,0,8,0,204,0,8,0,44,0,8,0,172,0,8,0,108,0,8,0,236,0,8,0,28,0,8,0,156,0,8,0,92,0,8,0,220,0,8,0,60,0,8,0,188,0,8,0,124,0,8,0,252,0,8,0,2,0,8,0,130,0,8,0,66,0,8,0,194,0,8,0,34,0,8,0,162,0,8,0,98,0,8,0,226,0,8,0,18,0,8,0,146,0,8,0,82,0,8,0,210,0,8,0,50,0,8,0,178,0,8,0,114,0,8,0,242,0,8,0,10,0,8,0,138,0,8,0,74,0,8,0,202,0,8,0,42,0,8,0,170,0,8,0,106,0,8,0,234,0,8,0,26,0,8,0,154,0,8,0,90,0,8,0,218,0,8,0,58,0,8,0,186,0,8,0,122,0,8,0,250,0,8,0,6,0,8,0,134,0,8,0,70,0,8,0,198,0,8,0,38,0,8,0,166,0,8,0,102,0,8,0,230,0,8,0,22,0,8,0,150,0,8,0,86,0,8,0,214,0,8,0,54,0,8,0,182,0,8,0,118,0,8,0,246,0,8,0,14,0,8,0,142,0,8,0,78,0,8,0,206,0,8,0,46,0,8,0,174,0,8,0,110,0,8,0,238,0,8,0,30,0,8,0,158,0,8,0,94,0,8,0,222,0,8,0,62,0,8,0,190,0,8,0,126,0,8,0,254,0,8,0,1,0,8,0,129,0,8,0,65,0,8,0,193,0,8,0,33,0,8,0,161,0,8,0,97,0,8,0,225,0,8,0,17,0,8,0,145,0,8,0,81,0,8,0,209,0,8,0,49,0,8,0,177,0,8,0,113,0,8,0,241,0,8,0,9,0,8,0,137,0,8,0,73,0,8,0,201,0,8,0,41,0,8,0,169,0,8,0,105,0,8,0,233,0,8,0,25,0,8,0,153,0,8,0,89,0,8,0,217,0,8,0,57,0,8,0,185,0,8,0,121,0,8,0,249,0,8,0,5,0,8,0,133,0,8,0,69,0,8,0,197,0,8,0,37,0,8,0,165,0,8,0,101,0,8,0,229,0,8,0,21,0,8,0,149,0,8,0,85,0,8,0,213,0,8,0,53,0,8,0,181,0,8,0,117,0,8,0,245,0,8,0,13,0,8,0,141,0,8,0,77,0,8,0,205,0,8,0,45,0,8,0,173,0,8,0,109,0,8,0,237,0,8,0,29,0,8,0,157,0,8,0,93,0,8,0,221,0,8,0,61,0,8,0,189,0,8,0,125,0,8,0,253,0,8,0,19,0,9,0,19,1,9,0,147,0,9,0,147,1,9,0,83,0,9,0,83,1,9,0,211,0,9,0,211,1,9,0,51,0,9,0,51,1,9,0,179,0,9,0,179,1,9,0,115,0,9,0,115,1,9,0,243,0,9,0,243,1,9,0,11,0,9,0,11,1,9,0,139,0,9,0,139,1,9,0,75,0,9,0,75,1,9,0,203,0,9,0,203,1,9,0,43,0,9,0,43,1,9,0,171,0,9,0,171,1,9,0,107,0,9,0,107,1,9,0,235,0,9,0,235,1,9,0,27,0,9,0,27,1,9,0,155,0,9,0,155,1,9,0,91,0,9,0,91,1,9,0,219,0,9,0,219,1,9,0,59,0,9,0,59,1,9,0,187,0,9,0,187,1,9,0,123,0,9,0,123,1,9,0,251,0,9,0,251,1,9,0,7,0,9,0,7,1,9,0,135,0,9,0,135,1,9,0,71,0,9,0,71,1,9,0,199,0,9,0,199,1,9,0,39,0,9,0,39,1,9,0,167,0,9,0,167,1,9,0,103,0,9,0,103,1,9,0,231,0,9,0,231,1,9,0,23,0,9,0,23,1,9,0,151,0,9,0,151,1,9,0,87,0,9,0,87,1,9,0,215,0,9,0,215,1,9,0,55,0,9,0,55,1,9,0,183,0,9,0,183,1,9,0,119,0,9,0,119,1,9,0,247,0,9,0,247,1,9,0,15,0,9,0,15,1,9,0,143,0,9,0,143,1,9,0,79,0,9,0,79,1,9,0,207,0,9,0,207,1,9,0,47,0,9,0,47,1,9,0,175,0,9,0,175,1,9,0,111,0,9,0,111,1,9,0,239,0,9,0,239,1,9,0,31,0,9,0,31,1,9,0,159,0,9,0,159,1,9,0,95,0,9,0,95,1,9,0,223,0,9,0,223,1,9,0,63,0,9,0,63,1,9,0,191,0,9,0,191,1,9,0,127,0,9,0,127,1,9,0,255,0,9,0,255,1,9,0,0,0,7,0,64,0,7,0,32,0,7,0,96,0,7,0,16,0,7,0,80,0,7,0,48,0,7,0,112,0,7,0,8,0,7,0,72,0,7,0,40,0,7,0,104,0,7,0,24,0,7,0,88,0,7,0,56,0,7,0,120,0,7,0,4,0,7,0,68,0,7,0,36,0,7,0,100,0,7,0,20,0,7,0,84,0,7,0,52,0,7,0,116,0,7,0,3,0,8,0,131,0,8,0,67,0,8,0,195,0,8,0,35,0,8,0,163,0,8,0,99,0,8,0,227,0,8,0,0,0,5,0,16,0,5,0,8,0,5,0,24,0,5,0,4,0,5,0,20,0,5,0,12,0,5,0,28,0,5,0,2,0,5,0,18,0,5,0,10,0,5,0,26,0,5,0,6,0,5,0,22,0,5,0,14,0,5,0,30,0,5,0,1,0,5,0,17,0,5,0,9,0,5,0,25,0,5,0,5,0,5,0,21,0,5,0,13,0,5,0,29,0,5,0,3,0,5,0,19,0,5,0,11,0,5,0,27,0,5,0,7,0,5,0,23,0,5,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,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0,3,0,0,0,3,0,0,0,4,0,0,0,4,0,0,0,4,0,0,0,4,0,0,0,5,0,0,0,5,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,0,0,0,7,0,0,0,8,0,0,0,10,0,0,0,12,0,0,0,14,0,0,0,16,0,0,0,20,0,0,0,24,0,0,0,28,0,0,0,32,0,0,0,40,0,0,0,48,0,0,0,56,0,0,0,64,0,0,0,80,0,0,0,96,0,0,0,112,0,0,0,128,0,0,0,160,0,0,0,192,0,0,0,224,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,1,0,0,0,1,0,0,0,2,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0,4,0,0,0,4,0,0,0,5,0,0,0,5,0,0,0,6,0,0,0,6,0,0,0,7,0,0,0,7,0,0,0,8,0,0,0,8,0,0,0,9,0,0,0,9,0,0,0,10,0,0,0,10,0,0,0,11,0,0,0,11,0,0,0,12,0,0,0,12,0,0,0,13,0,0,0,13,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,6,0,0,0,8,0,0,0,12,0,0,0,16,0,0,0,24,0,0,0,32,0,0,0,48,0,0,0,64,0,0,0,96,0,0,0,128,0,0,0,192,0,0,0,0,1,0,0,128,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,6,0,0,0,8,0,0,0,12,0,0,0,16,0,0,0,24,0,0,0,32,0,0,0,48,0,0,0,64,0,0,0,96,0,0,16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15,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,2,0,0,0,3,0,0,0,7,0,0,0,0,0,0,0,49,46,50,46,53,0,0,0,110,101,101,100,32,100,105,99,116,105,111,110,97,114,121,0,115,116,114,101,97,109,32,101,110,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,102,105,108,101,32,101,114,114,111,114,0,0,0,0,0,0,115,116,114,101,97,109,32,101,114,114,111,114,0,0,0,0,100,97,116,97,32,101,114,114,111,114,0,0,0,0,0,0,105,110,115,117,102,102,105,99,105,101,110,116,32,109,101,109,111,114,121,0,0,0,0,0,98,117,102,102,101,114,32,101,114,114,111,114,0,0,0,0,105,110,99,111,109,112,97,116,105,98,108,101,32,118,101,114,115,105,111,110,0,0,0,0,184,11,0,0,200,11,0,0,216,11,0,0,224,11,0,0,240,11,0,0,0,12,0,0,16,12,0,0,40,12,0,0,56,12,0,0,216,11,0,0,0,0,0,0,150,48,7,119,44,97,14,238,186,81,9,153,25,196,109,7,143,244,106,112,53,165,99,233,163,149,100,158,50,136,219,14,164,184,220,121,30,233,213,224,136,217,210,151,43,76,182,9,189,124,177,126,7,45,184,231,145,29,191,144,100,16,183,29,242,32,176,106,72,113,185,243,222,65,190,132,125,212,218,26,235,228,221,109,81,181,212,244,199,133,211,131,86,152,108,19,192,168,107,100,122,249,98,253,236,201,101,138,79,92,1,20,217,108,6,99,99,61,15,250,245,13,8,141,200,32,110,59,94,16,105,76,228,65,96,213,114,113,103,162,209,228,3,60,71,212,4,75,253,133,13,210,107,181,10,165,250,168,181,53,108,152,178,66,214,201,187,219,64,249,188,172,227,108,216,50,117,92,223,69,207,13,214,220,89,61,209,171,172,48,217,38,58,0,222,81,128,81,215,200,22,97,208,191,181,244,180,33,35,196,179,86,153,149,186,207,15,165,189,184,158,184,2,40,8,136,5,95,178,217,12,198,36,233,11,177,135,124,111,47,17,76,104,88,171,29,97,193,61,45,102,182,144,65,220,118,6,113,219,1,188,32,210,152,42,16,213,239,137,133,177,113,31,181,182,6,165,228,191,159,51,212,184,232,162,201,7,120,52,249,0,15,142,168,9,150,24,152,14,225,187,13,106,127,45,61,109,8,151,108,100,145,1,92,99,230,244,81,107,107,98,97,108,28,216,48,101,133,78,0,98,242,237,149,6,108,123,165,1,27,193,244,8,130,87,196,15,245,198,217,176,101,80,233,183,18,234,184,190,139,124,136,185,252,223,29,221,98,73,45,218,21,243,124,211,140,101,76,212,251,88,97,178,77,206,81,181,58,116,0,188,163,226,48,187,212,65,165,223,74,215,149,216,61,109,196,209,164,251,244,214,211,106,233,105,67,252,217,110,52,70,136,103,173,208,184,96,218,115,45,4,68,229,29,3,51,95,76,10,170,201,124,13,221,60,113,5,80,170,65,2,39,16,16,11,190,134,32,12,201,37,181,104,87,179,133,111,32,9,212,102,185,159,228,97,206,14,249,222,94,152,201,217,41,34,152,208,176,180,168,215,199,23,61,179,89,129,13,180,46,59,92,189,183,173,108,186,192,32,131,184,237,182,179,191,154,12,226,182,3,154,210,177,116,57,71,213,234,175,119,210,157,21,38,219,4,131,22,220,115,18,11,99,227,132,59,100,148,62,106,109,13,168,90,106,122,11,207,14,228,157,255,9,147,39,174,0,10,177,158,7,125,68,147,15,240,210,163,8,135,104,242,1,30,254,194,6,105,93,87,98,247,203,103,101,128,113,54,108,25,231,6,107,110,118,27,212,254,224,43,211,137,90,122,218,16,204,74,221,103,111,223,185,249,249,239,190,142,67,190,183,23,213,142,176,96,232,163,214,214,126,147,209,161,196,194,216,56,82,242,223,79,241,103,187,209,103,87,188,166,221,6,181,63,75,54,178,72,218,43,13,216,76,27,10,175,246,74,3,54,96,122,4,65,195,239,96,223,85,223,103,168,239,142,110,49,121,190,105,70,140,179,97,203,26,131,102,188,160,210,111,37,54,226,104,82,149,119,12,204,3,71,11,187,185,22,2,34,47,38,5,85,190,59,186,197,40,11,189,178,146,90,180,43,4,106,179,92,167,255,215,194,49,207,208,181,139,158,217,44,29,174,222,91,176,194,100,155,38,242,99,236,156,163,106,117,10,147,109,2,169,6,9,156,63,54,14,235,133,103,7,114,19,87,0,5,130,74,191,149,20,122,184,226,174,43,177,123,56,27,182,12,155,142,210,146,13,190,213,229,183,239,220,124,33,223,219,11,212,210,211,134,66,226,212,241,248,179,221,104,110,131,218,31,205,22,190,129,91,38,185,246,225,119,176,111,119,71,183,24,230,90,8,136,112,106,15,255,202,59,6,102,92,11,1,17,255,158,101,143,105,174,98,248,211,255,107,97,69,207,108,22,120,226,10,160,238,210,13,215,84,131,4,78,194,179,3,57,97,38,103,167,247,22,96,208,77,71,105,73,219,119,110,62,74,106,209,174,220,90,214,217,102,11,223,64,240,59,216,55,83,174,188,169,197,158,187,222,127,207,178,71,233,255,181,48,28,242,189,189,138,194,186,202,48,147,179,83,166,163,180,36,5,54,208,186,147,6,215,205,41,87,222,84,191,103,217,35,46,122,102,179,184,74,97,196,2,27,104,93,148,43,111,42,55,190,11,180,161,142,12,195,27,223,5,90,141,239,2,45,0,0,0,0,65,49,27,25,130,98,54,50,195,83,45,43,4,197,108,100,69,244,119,125,134,167,90,86,199,150,65,79,8,138,217,200,73,187,194,209,138,232,239,250,203,217,244,227,12,79,181,172,77,126,174,181,142,45,131,158,207,28,152,135,81,18,194,74,16,35,217,83,211,112,244,120,146,65,239,97,85,215,174,46,20,230,181,55,215,181,152,28,150,132,131,5,89,152,27,130,24,169,0,155,219,250,45,176,154,203,54,169,93,93,119,230,28,108,108,255,223,63,65,212,158,14,90,205,162,36,132,149,227,21,159,140,32,70,178,167,97,119,169,190,166,225,232,241,231,208,243,232,36,131,222,195,101,178,197,218,170,174,93,93,235,159,70,68,40,204,107,111,105,253,112,118,174,107,49,57,239,90,42,32,44,9,7,11,109,56,28,18,243,54,70,223,178,7,93,198,113,84,112,237,48,101,107,244,247,243,42,187,182,194,49,162,117,145,28,137,52,160,7,144,251,188,159,23,186,141,132,14,121,222,169,37,56,239,178,60,255,121,243,115,190,72,232,106,125,27,197,65,60,42,222,88,5,79,121,240,68,126,98,233,135,45,79,194,198,28,84,219,1,138,21,148,64,187,14,141,131,232,35,166,194,217,56,191,13,197,160,56,76,244,187,33,143,167,150,10,206,150,141,19,9,0,204,92,72,49,215,69,139,98,250,110,202,83,225,119,84,93,187,186,21,108,160,163,214,63,141,136,151,14,150,145,80,152,215,222,17,169,204,199,210,250,225,236,147,203,250,245,92,215,98,114,29,230,121,107,222,181,84,64,159,132,79,89,88,18,14,22,25,35,21,15,218,112,56,36,155,65,35,61,167,107,253,101,230,90,230,124,37,9,203,87,100,56,208,78,163,174,145,1,226,159,138,24,33,204,167,51,96,253,188,42,175,225,36,173,238,208,63,180,45,131,18,159,108,178,9,134,171,36,72,201,234,21,83,208,41,70,126,251,104,119,101,226,246,121,63,47,183,72,36,54,116,27,9,29,53,42,18,4,242,188,83,75,179,141,72,82,112,222,101,121,49,239,126,96,254,243,230,231,191,194,253,254,124,145,208,213,61,160,203,204,250,54,138,131,187,7,145,154,120,84,188,177,57,101,167,168,75,152,131,59,10,169,152,34,201,250,181,9,136,203,174,16,79,93,239,95,14,108,244,70,205,63,217,109,140,14,194,116,67,18,90,243,2,35,65,234,193,112,108,193,128,65,119,216,71,215,54,151,6,230,45,142,197,181,0,165,132,132,27,188,26,138,65,113,91,187,90,104,152,232,119,67,217,217,108,90,30,79,45,21,95,126,54,12,156,45,27,39,221,28,0,62,18,0,152,185,83,49,131,160,144,98,174,139,209,83,181,146,22,197,244,221,87,244,239,196,148,167,194,239,213,150,217,246,233,188,7,174,168,141,28,183,107,222,49,156,42,239,42,133,237,121,107,202,172,72,112,211,111,27,93,248,46,42,70,225,225,54,222,102,160,7,197,127,99,84,232,84,34,101,243,77,229,243,178,2,164,194,169,27,103,145,132,48,38,160,159,41,184,174,197,228,249,159,222,253,58,204,243,214,123,253,232,207,188,107,169,128,253,90,178,153,62,9,159,178,127,56,132,171,176,36,28,44,241,21,7,53,50,70,42,30,115,119,49,7,180,225,112,72,245,208,107,81,54,131,70,122,119,178,93,99,78,215,250,203,15,230,225,210,204,181,204,249,141,132,215,224,74,18,150,175,11,35,141,182,200,112,160,157,137,65,187,132,70,93,35,3,7,108,56,26,196,63,21,49,133,14,14,40,66,152,79,103,3,169,84,126,192,250,121,85,129,203,98,76,31,197,56,129,94,244,35,152,157,167,14,179,220,150,21,170,27,0,84,229,90,49,79,252,153,98,98,215,216,83,121,206,23,79,225,73,86,126,250,80,149,45,215,123,212,28,204,98,19,138,141,45,82,187,150,52,145,232,187,31,208,217,160,6,236,243,126,94,173,194,101,71,110,145,72,108,47,160,83,117,232,54,18,58,169,7,9,35,106,84,36,8,43,101,63,17,228,121,167,150,165,72,188,143,102,27,145,164,39,42,138,189,224,188,203,242,161,141,208,235,98,222,253,192,35,239,230,217,189,225,188,20,252,208,167,13,63,131,138,38,126,178,145,63,185,36,208,112,248,21,203,105,59,70,230,66,122,119,253,91,181,107,101,220,244,90,126,197,55,9,83,238,118,56,72,247,177,174,9,184,240,159,18,161,51,204,63,138,114,253,36,147,0,0,0,0,55,106,194,1,110,212,132,3,89,190,70,2,220,168,9,7,235,194,203,6,178,124,141,4,133,22,79,5,184,81,19,14,143,59,209,15,214,133,151,13,225,239,85,12,100,249,26,9,83,147,216,8,10,45,158,10,61,71,92,11,112,163,38,28,71,201,228,29,30,119,162,31,41,29,96,30,172,11,47,27,155,97,237,26,194,223,171,24,245,181,105,25,200,242,53,18,255,152,247,19,166,38,177,17,145,76,115,16,20,90,60,21,35,48,254,20,122,142,184,22,77,228,122,23,224,70,77,56,215,44,143,57,142,146,201,59,185,248,11,58,60,238,68,63,11,132,134,62,82,58,192,60,101,80,2,61,88,23,94,54,111,125,156,55,54,195,218,53,1,169,24,52,132,191,87,49,179,213,149,48,234,107,211,50,221,1,17,51,144,229,107,36,167,143,169,37,254,49,239,39,201,91,45,38,76,77,98,35,123,39,160,34,34,153,230,32,21,243,36,33,40,180,120,42,31,222,186,43,70,96,252,41,113,10,62,40,244,28,113,45,195,118,179,44,154,200,245,46,173,162,55,47,192,141,154,112,247,231,88,113,174,89,30,115,153,51,220,114,28,37,147,119,43,79,81,118,114,241,23,116,69,155,213,117,120,220,137,126,79,182,75,127,22,8,13,125,33,98,207,124,164,116,128,121,147,30,66,120,202,160,4,122,253,202,198,123,176,46,188,108,135,68,126,109,222,250,56,111,233,144,250,110,108,134,181,107,91,236,119,106,2,82,49,104,53,56,243,105,8,127,175,98,63,21,109,99,102,171,43,97,81,193,233,96,212,215,166,101,227,189,100,100,186,3,34,102,141,105,224,103,32,203,215,72,23,161,21,73,78,31,83,75,121,117,145,74,252,99,222,79,203,9,28,78,146,183,90,76,165,221,152,77,152,154,196,70,175,240,6,71,246,78,64,69,193,36,130,68,68,50,205,65,115,88,15,64,42,230,73,66,29,140,139,67,80,104,241,84,103,2,51,85,62,188,117,87,9,214,183,86,140,192,248,83,187,170,58,82,226,20,124,80,213,126,190,81,232,57,226,90,223,83,32,91,134,237,102,89,177,135,164,88,52,145,235,93,3,251,41,92,90,69,111,94,109,47,173,95,128,27,53,225,183,113,247,224,238,207,177,226,217,165,115,227,92,179,60,230,107,217,254,231,50,103,184,229,5,13,122,228,56,74,38,239,15,32,228,238,86,158,162,236,97,244,96,237,228,226,47,232,211,136,237,233,138,54,171,235,189,92,105,234,240,184,19,253,199,210,209,252,158,108,151,254,169,6,85,255,44,16,26,250,27,122,216,251,66,196,158,249,117,174,92,248,72,233,0,243,127,131,194,242,38,61,132,240,17,87,70,241,148,65,9,244,163,43,203,245,250,149,141,247,205,255,79,246,96,93,120,217,87,55,186,216,14,137,252,218,57,227,62,219,188,245,113,222,139,159,179,223,210,33,245,221,229,75,55,220,216,12,107,215,239,102,169,214,182,216,239,212,129,178,45,213,4,164,98,208,51,206,160,209,106,112,230,211,93,26,36,210,16,254,94,197,39,148,156,196,126,42,218,198,73,64,24,199,204,86,87,194,251,60,149,195,162,130,211,193,149,232,17,192,168,175,77,203,159,197,143,202,198,123,201,200,241,17,11,201,116,7,68,204,67,109,134,205,26,211,192,207,45,185,2,206,64,150,175,145,119,252,109,144,46,66,43,146,25,40,233,147,156,62,166,150,171,84,100,151,242,234,34,149,197,128,224,148,248,199,188,159,207,173,126,158,150,19,56,156,161,121,250,157,36,111,181,152,19,5,119,153,74,187,49,155,125,209,243,154,48,53,137,141,7,95,75,140,94,225,13,142,105,139,207,143,236,157,128,138,219,247,66,139,130,73,4,137,181,35,198,136,136,100,154,131,191,14,88,130,230,176,30,128,209,218,220,129,84,204,147,132,99,166,81,133,58,24,23,135,13,114,213,134,160,208,226,169,151,186,32,168,206,4,102,170,249,110,164,171,124,120,235,174,75,18,41,175,18,172,111,173,37,198,173,172,24,129,241,167,47,235,51,166,118,85,117,164,65,63,183,165,196,41,248,160,243,67,58,161,170,253,124,163,157,151,190,162,208,115,196,181,231,25,6,180,190,167,64,182,137,205,130,183,12,219,205,178,59,177,15,179,98,15,73,177,85,101,139,176,104,34,215,187,95,72,21,186,6,246,83,184,49,156,145,185,180,138,222,188,131,224,28,189,218,94,90,191,237,52,152,190,0,0,0,0,101,103,188,184,139,200,9,170,238,175,181,18,87,151,98,143,50,240,222,55,220,95,107,37,185,56,215,157,239,40,180,197,138,79,8,125,100,224,189,111,1,135,1,215,184,191,214,74,221,216,106,242,51,119,223,224,86,16,99,88,159,87,25,80,250,48,165,232,20,159,16,250,113,248,172,66,200,192,123,223,173,167,199,103,67,8,114,117,38,111,206,205,112,127,173,149,21,24,17,45,251,183,164,63,158,208,24,135,39,232,207,26,66,143,115,162,172,32,198,176,201,71,122,8,62,175,50,160,91,200,142,24,181,103,59,10,208,0,135,178,105,56,80,47,12,95,236,151,226,240,89,133,135,151,229,61,209,135,134,101,180,224,58,221,90,79,143,207,63,40,51,119,134,16,228,234,227,119,88,82,13,216,237,64,104,191,81,248,161,248,43,240,196,159,151,72,42,48,34,90,79,87,158,226,246,111,73,127,147,8,245,199,125,167,64,213,24,192,252,109,78,208,159,53,43,183,35,141,197,24,150,159,160,127,42,39,25,71,253,186,124,32,65,2,146,143,244,16,247,232,72,168,61,88,20,155,88,63,168,35,182,144,29,49,211,247,161,137,106,207,118,20,15,168,202,172,225,7,127,190,132,96,195,6,210,112,160,94,183,23,28,230,89,184,169,244,60,223,21,76,133,231,194,209,224,128,126,105,14,47,203,123,107,72,119,195,162,15,13,203,199,104,177,115,41,199,4,97,76,160,184,217,245,152,111,68,144,255,211,252,126,80,102,238,27,55,218,86,77,39,185,14,40,64,5,182,198,239,176,164,163,136,12,28,26,176,219,129,127,215,103,57,145,120,210,43,244,31,110,147,3,247,38,59,102,144,154,131,136,63,47,145,237,88,147,41,84,96,68,180,49,7,248,12,223,168,77,30,186,207,241,166,236,223,146,254,137,184,46,70,103,23,155,84,2,112,39,236,187,72,240,113,222,47,76,201,48,128,249,219,85,231,69,99,156,160,63,107,249,199,131,211,23,104,54,193,114,15,138,121,203,55,93,228,174,80,225,92,64,255,84,78,37,152,232,246,115,136,139,174,22,239,55,22,248,64,130,4,157,39,62,188,36,31,233,33,65,120,85,153,175,215,224,139,202,176,92,51,59,182,89,237,94,209,229,85,176,126,80,71,213,25,236,255,108,33,59,98,9,70,135,218,231,233,50,200,130,142,142,112,212,158,237,40,177,249,81,144,95,86,228,130,58,49,88,58,131,9,143,167,230,110,51,31,8,193,134,13,109,166,58,181,164,225,64,189,193,134,252,5,47,41,73,23,74,78,245,175,243,118,34,50,150,17,158,138,120,190,43,152,29,217,151,32,75,201,244,120,46,174,72,192,192,1,253,210,165,102,65,106,28,94,150,247,121,57,42,79,151,150,159,93,242,241,35,229,5,25,107,77,96,126,215,245,142,209,98,231,235,182,222,95,82,142,9,194,55,233,181,122,217,70,0,104,188,33,188,208,234,49,223,136,143,86,99,48,97,249,214,34,4,158,106,154,189,166,189,7,216,193,1,191,54,110,180,173,83,9,8,21,154,78,114,29,255,41,206,165,17,134,123,183,116,225,199,15,205,217,16,146,168,190,172,42,70,17,25,56,35,118,165,128,117,102,198,216,16,1,122,96,254,174,207,114,155,201,115,202,34,241,164,87,71,150,24,239,169,57,173,253,204,94,17,69,6,238,77,118,99,137,241,206,141,38,68,220,232,65,248,100,81,121,47,249,52,30,147,65,218,177,38,83,191,214,154,235,233,198,249,179,140,161,69,11,98,14,240,25,7,105,76,161,190,81,155,60,219,54,39,132,53,153,146,150,80,254,46,46,153,185,84,38,252,222,232,158,18,113,93,140,119,22,225,52,206,46,54,169,171,73,138,17,69,230,63,3,32,129,131,187,118,145,224,227,19,246,92,91,253,89,233,73,152,62,85,241,33,6,130,108,68,97,62,212,170,206,139,198,207,169,55,126,56,65,127,214,93,38,195,110,179,137,118,124,214,238,202,196,111,214,29,89,10,177,161,225,228,30,20,243,129,121,168,75,215,105,203,19,178,14,119,171,92,161,194,185,57,198,126,1,128,254,169,156,229,153,21,36,11,54,160,54,110,81,28,142,167,22,102,134,194,113,218,62,44,222,111,44,73,185,211,148,240,129,4,9,149,230,184,177,123,73,13,163,30,46,177,27,72,62,210,67,45,89,110,251,195,246,219,233,166,145,103,81,31,169,176,204,122,206,12,116,148,97,185,102,241,6,5,222,0,0,0,0,119,7,48,150,238,14,97,44,153,9,81,186,7,109,196,25,112,106,244,143,233,99,165,53,158,100,149,163,14,219,136,50,121,220,184,164,224,213,233,30,151,210,217,136,9,182,76,43,126,177,124,189,231,184,45,7,144,191,29,145,29,183,16,100,106,176,32,242,243,185,113,72,132,190,65,222,26,218,212,125,109,221,228,235,244,212,181,81,131,211,133,199,19,108,152,86,100,107,168,192,253,98,249,122,138,101,201,236,20,1,92,79,99,6,108,217,250,15,61,99,141,8,13,245,59,110,32,200,76,105,16,94,213,96,65,228,162,103,113,114,60,3,228,209,75,4,212,71,210,13,133,253,165,10,181,107,53,181,168,250,66,178,152,108,219,187,201,214,172,188,249,64,50,216,108,227,69,223,92,117,220,214,13,207,171,209,61,89,38,217,48,172,81,222,0,58,200,215,81,128,191,208,97,22,33,180,244,181,86,179,196,35,207,186,149,153,184,189,165,15,40,2,184,158,95,5,136,8,198,12,217,178,177,11,233,36,47,111,124,135,88,104,76,17,193,97,29,171,182,102,45,61,118,220,65,144,1,219,113,6,152,210,32,188,239,213,16,42,113,177,133,137,6,182,181,31,159,191,228,165,232,184,212,51,120,7,201,162,15,0,249,52,150,9,168,142,225,14,152,24,127,106,13,187,8,109,61,45,145,100,108,151,230,99,92,1,107,107,81,244,28,108,97,98,133,101,48,216,242,98,0,78,108,6,149,237,27,1,165,123,130,8,244,193,245,15,196,87,101,176,217,198,18,183,233,80,139,190,184,234,252,185,136,124,98,221,29,223,21,218,45,73,140,211,124,243,251,212,76,101,77,178,97,88,58,181,81,206,163,188,0,116,212,187,48,226,74,223,165,65,61,216,149,215,164,209,196,109,211,214,244,251,67,105,233,106,52,110,217,252,173,103,136,70,218,96,184,208,68,4,45,115,51,3,29,229,170,10,76,95,221,13,124,201,80,5,113,60,39,2,65,170,190,11,16,16,201,12,32,134,87,104,181,37,32,111,133,179,185,102,212,9,206,97,228,159,94,222,249,14,41,217,201,152,176,208,152,34,199,215,168,180,89,179,61,23,46,180,13,129,183,189,92,59,192,186,108,173,237,184,131,32,154,191,179,182,3,182,226,12,116,177,210,154,234,213,71,57,157,210,119,175,4,219,38,21,115,220,22,131,227,99,11,18,148,100,59,132,13,109,106,62,122,106,90,168,228,14,207,11,147,9,255,157,10,0,174,39,125,7,158,177,240,15,147,68,135,8,163,210,30,1,242,104,105,6,194,254,247,98,87,93,128,101,103,203,25,108,54,113,110,107,6,231,254,212,27,118,137,211,43,224,16,218,122,90,103,221,74,204,249,185,223,111,142,190,239,249,23,183,190,67,96,176,142,213,214,214,163,232,161,209,147,126,56,216,194,196,79,223,242,82,209,187,103,241,166,188,87,103,63,181,6,221,72,178,54,75,216,13,43,218,175,10,27,76,54,3,74,246,65,4,122,96,223,96,239,195,168,103,223,85,49,110,142,239,70,105,190,121,203,97,179,140,188,102,131,26,37,111,210,160,82,104,226,54,204,12,119,149,187,11,71,3,34,2,22,185,85,5,38,47,197,186,59,190,178,189,11,40,43,180,90,146,92,179,106,4,194,215,255,167,181,208,207,49,44,217,158,139,91,222,174,29,155,100,194,176,236,99,242,38,117,106,163,156,2,109,147,10,156,9,6,169,235,14,54,63,114,7,103,133,5,0,87,19,149,191,74,130,226,184,122,20,123,177,43,174,12,182,27,56,146,210,142,155,229,213,190,13,124,220,239,183,11,219,223,33,134,211,210,212,241,212,226,66,104,221,179,248,31,218,131,110,129,190,22,205,246,185,38,91,111,176,119,225,24,183,71,119,136,8,90,230,255,15,106,112,102,6,59,202,17,1,11,92,143,101,158,255,248,98,174,105,97,107,255,211,22,108,207,69,160,10,226,120,215,13,210,238,78,4,131,84,57,3,179,194,167,103,38,97,208,96,22,247,73,105,71,77,62,110,119,219,174,209,106,74,217,214,90,220,64,223,11,102,55,216,59,240,169,188,174,83,222,187,158,197,71,178,207,127,48,181,255,233,189,189,242,28,202,186,194,138,83,179,147,48,36,180,163,166,186,208,54,5,205,215,6,147,84,222,87,41,35,217,103,191,179,102,122,46,196,97,74,184,93,104,27,2,42,111,43,148,180,11,190,55,195,12,142,161,90,5,223,27,45,2,239,141,0,0,0,0,25,27,49,65,50,54,98,130,43,45,83,195,100,108,197,4,125,119,244,69,86,90,167,134,79,65,150,199,200,217,138,8,209,194,187,73,250,239,232,138,227,244,217,203,172,181,79,12,181,174,126,77,158,131,45,142,135,152,28,207,74,194,18,81,83,217,35,16,120,244,112,211,97,239,65,146,46,174,215,85,55,181,230,20,28,152,181,215,5,131,132,150,130,27,152,89,155,0,169,24,176,45,250,219,169,54,203,154,230,119,93,93,255,108,108,28,212,65,63,223,205,90,14,158,149,132,36,162,140,159,21,227,167,178,70,32,190,169,119,97,241,232,225,166,232,243,208,231,195,222,131,36,218,197,178,101,93,93,174,170,68,70,159,235,111,107,204,40,118,112,253,105,57,49,107,174,32,42,90,239,11,7,9,44,18,28,56,109,223,70,54,243,198,93,7,178,237,112,84,113,244,107,101,48,187,42,243,247,162,49,194,182,137,28,145,117,144,7,160,52,23,159,188,251,14,132,141,186,37,169,222,121,60,178,239,56,115,243,121,255,106,232,72,190,65,197,27,125,88,222,42,60,240,121,79,5,233,98,126,68,194,79,45,135,219,84,28,198,148,21,138,1,141,14,187,64,166,35,232,131,191,56,217,194,56,160,197,13,33,187,244,76,10,150,167,143,19,141,150,206,92,204,0,9,69,215,49,72,110,250,98,139,119,225,83,202,186,187,93,84,163,160,108,21,136,141,63,214,145,150,14,151,222,215,152,80,199,204,169,17,236,225,250,210,245,250,203,147,114,98,215,92,107,121,230,29,64,84,181,222,89,79,132,159,22,14,18,88,15,21,35,25,36,56,112,218,61,35,65,155,101,253,107,167,124,230,90,230,87,203,9,37,78,208,56,100,1,145,174,163,24,138,159,226,51,167,204,33,42,188,253,96,173,36,225,175,180,63,208,238,159,18,131,45,134,9,178,108,201,72,36,171,208,83,21,234,251,126,70,41,226,101,119,104,47,63,121,246,54,36,72,183,29,9,27,116,4,18,42,53,75,83,188,242,82,72,141,179,121,101,222,112,96,126,239,49,231,230,243,254,254,253,194,191,213,208,145,124,204,203,160,61,131,138,54,250,154,145,7,187,177,188,84,120,168,167,101,57,59,131,152,75,34,152,169,10,9,181,250,201,16,174,203,136,95,239,93,79,70,244,108,14,109,217,63,205,116,194,14,140,243,90,18,67,234,65,35,2,193,108,112,193,216,119,65,128,151,54,215,71,142,45,230,6,165,0,181,197,188,27,132,132,113,65,138,26,104,90,187,91,67,119,232,152,90,108,217,217,21,45,79,30,12,54,126,95,39,27,45,156,62,0,28,221,185,152,0,18,160,131,49,83,139,174,98,144,146,181,83,209,221,244,197,22,196,239,244,87,239,194,167,148,246,217,150,213,174,7,188,233,183,28,141,168,156,49,222,107,133,42,239,42,202,107,121,237,211,112,72,172,248,93,27,111,225,70,42,46,102,222,54,225,127,197,7,160,84,232,84,99,77,243,101,34,2,178,243,229,27,169,194,164,48,132,145,103,41,159,160,38,228,197,174,184,253,222,159,249,214,243,204,58,207,232,253,123,128,169,107,188,153,178,90,253,178,159,9,62,171,132,56,127,44,28,36,176,53,7,21,241,30,42,70,50,7,49,119,115,72,112,225,180,81,107,208,245,122,70,131,54,99,93,178,119,203,250,215,78,210,225,230,15,249,204,181,204,224,215,132,141,175,150,18,74,182,141,35,11,157,160,112,200,132,187,65,137,3,35,93,70,26,56,108,7,49,21,63,196,40,14,14,133,103,79,152,66,126,84,169,3,85,121,250,192,76,98,203,129,129,56,197,31,152,35,244,94,179,14,167,157,170,21,150,220,229,84,0,27,252,79,49,90,215,98,98,153,206,121,83,216,73,225,79,23,80,250,126,86,123,215,45,149,98,204,28,212,45,141,138,19,52,150,187,82,31,187,232,145,6,160,217,208,94,126,243,236,71,101,194,173,108,72,145,110,117,83,160,47,58,18,54,232,35,9,7,169,8,36,84,106,17,63,101,43,150,167,121,228,143,188,72,165,164,145,27,102,189,138,42,39,242,203,188,224,235,208,141,161,192,253,222,98,217,230,239,35,20,188,225,189,13,167,208,252,38,138,131,63,63,145,178,126,112,208,36,185,105,203,21,248,66,230,70,59,91,253,119,122,220,101,107,181,197,126,90,244,238,83,9,55,247,72,56,118,184,9,174,177,161,18,159,240,138,63,204,51,147,36,253,114,0,0,0,0,1,194,106,55,3,132,212,110,2,70,190,89,7,9,168,220,6,203,194,235,4,141,124,178,5,79,22,133,14,19,81,184,15,209,59,143,13,151,133,214,12,85,239,225,9,26,249,100,8,216,147,83,10,158,45,10,11,92,71,61,28,38,163,112,29,228,201,71,31,162,119,30,30,96,29,41,27,47,11,172,26,237,97,155,24,171,223,194,25,105,181,245,18,53,242,200,19,247,152,255,17,177,38,166,16,115,76,145,21,60,90,20,20,254,48,35,22,184,142,122,23,122,228,77,56,77,70,224,57,143,44,215,59,201,146,142,58,11,248,185,63,68,238,60,62,134,132,11,60,192,58,82,61,2,80,101,54,94,23,88,55,156,125,111,53,218,195,54,52,24,169,1,49,87,191,132,48,149,213,179,50,211,107,234,51,17,1,221,36,107,229,144,37,169,143,167,39,239,49,254,38,45,91,201,35,98,77,76,34,160,39,123,32,230,153,34,33,36,243,21,42,120,180,40,43,186,222,31,41,252,96,70,40,62,10,113,45,113,28,244,44,179,118,195,46,245,200,154,47,55,162,173,112,154,141,192,113,88,231,247,115,30,89,174,114,220,51,153,119,147,37,28,118,81,79,43,116,23,241,114,117,213,155,69,126,137,220,120,127,75,182,79,125,13,8,22,124,207,98,33,121,128,116,164,120,66,30,147,122,4,160,202,123,198,202,253,108,188,46,176,109,126,68,135,111,56,250,222,110,250,144,233,107,181,134,108,106,119,236,91,104,49,82,2,105,243,56,53,98,175,127,8,99,109,21,63,97,43,171,102,96,233,193,81,101,166,215,212,100,100,189,227,102,34,3,186,103,224,105,141,72,215,203,32,73,21,161,23,75,83,31,78,74,145,117,121,79,222,99,252,78,28,9,203,76,90,183,146,77,152,221,165,70,196,154,152,71,6,240,175,69,64,78,246,68,130,36,193,65,205,50,68,64,15,88,115,66,73,230,42,67,139,140,29,84,241,104,80,85,51,2,103,87,117,188,62,86,183,214,9,83,248,192,140,82,58,170,187,80,124,20,226,81,190,126,213,90,226,57,232,91,32,83,223,89,102,237,134,88,164,135,177,93,235,145,52,92,41,251,3,94,111,69,90,95,173,47,109,225,53,27,128,224,247,113,183,226,177,207,238,227,115,165,217,230,60,179,92,231,254,217,107,229,184,103,50,228,122,13,5,239,38,74,56,238,228,32,15,236,162,158,86,237,96,244,97,232,47,226,228,233,237,136,211,235,171,54,138,234,105,92,189,253,19,184,240,252,209,210,199,254,151,108,158,255,85,6,169,250,26,16,44,251,216,122,27,249,158,196,66,248,92,174,117,243,0,233,72,242,194,131,127,240,132,61,38,241,70,87,17,244,9,65,148,245,203,43,163,247,141,149,250,246,79,255,205,217,120,93,96,216,186,55,87,218,252,137,14,219,62,227,57,222,113,245,188,223,179,159,139,221,245,33,210,220,55,75,229,215,107,12,216,214,169,102,239,212,239,216,182,213,45,178,129,208,98,164,4,209,160,206,51,211,230,112,106,210,36,26,93,197,94,254,16,196,156,148,39,198,218,42,126,199,24,64,73,194,87,86,204,195,149,60,251,193,211,130,162,192,17,232,149,203,77,175,168,202,143,197,159,200,201,123,198,201,11,17,241,204,68,7,116,205,134,109,67,207,192,211,26,206,2,185,45,145,175,150,64,144,109,252,119,146,43,66,46,147,233,40,25,150,166,62,156,151,100,84,171,149,34,234,242,148,224,128,197,159,188,199,248,158,126,173,207,156,56,19,150,157,250,121,161,152,181,111,36,153,119,5,19,155,49,187,74,154,243,209,125,141,137,53,48,140,75,95,7,142,13,225,94,143,207,139,105,138,128,157,236,139,66,247,219,137,4,73,130,136,198,35,181,131,154,100,136,130,88,14,191,128,30,176,230,129,220,218,209,132,147,204,84,133,81,166,99,135,23,24,58,134,213,114,13,169,226,208,160,168,32,186,151,170,102,4,206,171,164,110,249], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
+/* memory initializer */ allocate([174,235,120,124,175,41,18,75,173,111,172,18,172,173,198,37,167,241,129,24,166,51,235,47,164,117,85,118,165,183,63,65,160,248,41,196,161,58,67,243,163,124,253,170,162,190,151,157,181,196,115,208,180,6,25,231,182,64,167,190,183,130,205,137,178,205,219,12,179,15,177,59,177,73,15,98,176,139,101,85,187,215,34,104,186,21,72,95,184,83,246,6,185,145,156,49,188,222,138,180,189,28,224,131,191,90,94,218,190,152,52,237,0,0,0,0,184,188,103,101,170,9,200,139,18,181,175,238,143,98,151,87,55,222,240,50,37,107,95,220,157,215,56,185,197,180,40,239,125,8,79,138,111,189,224,100,215,1,135,1,74,214,191,184,242,106,216,221,224,223,119,51,88,99,16,86,80,25,87,159,232,165,48,250,250,16,159,20,66,172,248,113,223,123,192,200,103,199,167,173,117,114,8,67,205,206,111,38,149,173,127,112,45,17,24,21,63,164,183,251,135,24,208,158,26,207,232,39,162,115,143,66,176,198,32,172,8,122,71,201,160,50,175,62,24,142,200,91,10,59,103,181,178,135,0,208,47,80,56,105,151,236,95,12,133,89,240,226,61,229,151,135,101,134,135,209,221,58,224,180,207,143,79,90,119,51,40,63,234,228,16,134,82,88,119,227,64,237,216,13,248,81,191,104,240,43,248,161,72,151,159,196,90,34,48,42,226,158,87,79,127,73,111,246,199,245,8,147,213,64,167,125,109,252,192,24,53,159,208,78,141,35,183,43,159,150,24,197,39,42,127,160,186,253,71,25,2,65,32,124,16,244,143,146,168,72,232,247,155,20,88,61,35,168,63,88,49,29,144,182,137,161,247,211,20,118,207,106,172,202,168,15,190,127,7,225,6,195,96,132,94,160,112,210,230,28,23,183,244,169,184,89,76,21,223,60,209,194,231,133,105,126,128,224,123,203,47,14,195,119,72,107,203,13,15,162,115,177,104,199,97,4,199,41,217,184,160,76,68,111,152,245,252,211,255,144,238,102,80,126,86,218,55,27,14,185,39,77,182,5,64,40,164,176,239,198,28,12,136,163,129,219,176,26,57,103,215,127,43,210,120,145,147,110,31,244,59,38,247,3,131,154,144,102,145,47,63,136,41,147,88,237,180,68,96,84,12,248,7,49,30,77,168,223,166,241,207,186,254,146,223,236,70,46,184,137,84,155,23,103,236,39,112,2,113,240,72,187,201,76,47,222,219,249,128,48,99,69,231,85,107,63,160,156,211,131,199,249,193,54,104,23,121,138,15,114,228,93,55,203,92,225,80,174,78,84,255,64,246,232,152,37,174,139,136,115,22,55,239,22,4,130,64,248,188,62,39,157,33,233,31,36,153,85,120,65,139,224,215,175,51,92,176,202,237,89,182,59,85,229,209,94,71,80,126,176,255,236,25,213,98,59,33,108,218,135,70,9,200,50,233,231,112,142,142,130,40,237,158,212,144,81,249,177,130,228,86,95,58,88,49,58,167,143,9,131,31,51,110,230,13,134,193,8,181,58,166,109,189,64,225,164,5,252,134,193,23,73,41,47,175,245,78,74,50,34,118,243,138,158,17,150,152,43,190,120,32,151,217,29,120,244,201,75,192,72,174,46,210,253,1,192,106,65,102,165,247,150,94,28,79,42,57,121,93,159,150,151,229,35,241,242,77,107,25,5,245,215,126,96,231,98,209,142,95,222,182,235,194,9,142,82,122,181,233,55,104,0,70,217,208,188,33,188,136,223,49,234,48,99,86,143,34,214,249,97,154,106,158,4,7,189,166,189,191,1,193,216,173,180,110,54,21,8,9,83,29,114,78,154,165,206,41,255,183,123,134,17,15,199,225,116,146,16,217,205,42,172,190,168,56,25,17,70,128,165,118,35,216,198,102,117,96,122,1,16,114,207,174,254,202,115,201,155,87,164,241,34,239,24,150,71,253,173,57,169,69,17,94,204,118,77,238,6,206,241,137,99,220,68,38,141,100,248,65,232,249,47,121,81,65,147,30,52,83,38,177,218,235,154,214,191,179,249,198,233,11,69,161,140,25,240,14,98,161,76,105,7,60,155,81,190,132,39,54,219,150,146,153,53,46,46,254,80,38,84,185,153,158,232,222,252,140,93,113,18,52,225,22,119,169,54,46,206,17,138,73,171,3,63,230,69,187,131,129,32,227,224,145,118,91,92,246,19,73,233,89,253,241,85,62,152,108,130,6,33,212,62,97,68,198,139,206,170,126,55,169,207,214,127,65,56,110,195,38,93,124,118,137,179,196,202,238,214,89,29,214,111,225,161,177,10,243,20,30,228,75,168,121,129,19,203,105,215,171,119,14,178,185,194,161,92,1,126,198,57,156,169,254,128,36,21,153,229,54,160,54,11,142,28,81,110,134,102,22,167,62,218,113,194,44,111,222,44,148,211,185,73,9,4,129,240,177,184,230,149,163,13,73,123,27,177,46,30,67,210,62,72,251,110,89,45,233,219,246,195,81,103,145,166,204,176,169,31,116,12,206,122,102,185,97,148,222,5,6,241,16,0,17,0,18,0,0,0,8,0,7,0,9,0,6,0,10,0,5,0,11,0,4,0,12,0,3,0,13,0,2,0,14,0,1,0,15,0,0,0,105,110,99,111,114,114,101,99,116,32,104,101,97,100,101,114,32,99,104,101,99,107,0,0,117,110,107,110,111,119,110,32,99,111,109,112,114,101,115,115,105,111,110,32,109,101,116,104,111,100,0,0,0,0,0,0,105,110,118,97,108,105,100,32,119,105,110,100,111,119,32,115,105,122,101,0,0,0,0,0,117,110,107,110,111,119,110,32,104,101,97,100,101,114,32,102,108,97,103,115,32,115,101,116,0,0,0,0,0,0,0,0,104,101,97,100,101,114,32,99,114,99,32,109,105,115,109,97,116,99,104,0,0,0,0,0,105,110,118,97,108,105,100,32,98,108,111,99,107,32,116,121,112,101,0,0,0,0,0,0,105,110,118,97,108,105,100,32,115,116,111,114,101,100,32,98,108,111,99,107,32,108,101,110,103,116,104,115,0,0,0,0,116,111,111,32,109,97,110,121,32,108,101,110,103,116,104,32,111,114,32,100,105,115,116,97,110,99,101,32,115,121,109,98,111,108,115,0,0,0,0,0,105,110,118,97,108,105,100,32,99,111,100,101,32,108,101,110,103,116,104,115,32,115,101,116,0,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,98,105,116,32,108,101,110,103,116,104,32,114,101,112,101,97,116,0,0,0,0,0,0,0,105,110,118,97,108,105,100,32,99,111,100,101,32,45,45,32,109,105,115,115,105,110,103,32,101,110,100,45,111,102,45,98,108,111,99,107,0,0,0,0,105,110,118,97,108,105,100,32,108,105,116,101,114,97,108,47,108,101,110,103,116,104,115,32,115,101,116,0,0,0,0,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,115,32,115,101,116,0,0,0,105,110,118,97,108,105,100,32,108,105,116,101,114,97,108,47,108,101,110,103,116,104,32,99,111,100,101,0,0,0,0,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,32,99,111,100,101,0,0,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,32,116,111,111,32,102,97,114,32,98,97,99,107,0,0,0,105,110,99,111,114,114,101,99,116,32,100,97,116,97,32,99,104,101,99,107,0,0,0,0,105,110,99,111,114,114,101,99,116,32,108,101,110,103,116,104,32,99,104,101,99,107,0,0,96,7,0,0,0,8,80,0,0,8,16,0,20,8,115,0,18,7,31,0,0,8,112,0,0,8,48,0,0,9,192,0,16,7,10,0,0,8,96,0,0,8,32,0,0,9,160,0,0,8,0,0,0,8,128,0,0,8,64,0,0,9,224,0,16,7,6,0,0,8,88,0,0,8,24,0,0,9,144,0,19,7,59,0,0,8,120,0,0,8,56,0,0,9,208,0,17,7,17,0,0,8,104,0,0,8,40,0,0,9,176,0,0,8,8,0,0,8,136,0,0,8,72,0,0,9,240,0,16,7,4,0,0,8,84,0,0,8,20,0,21,8,227,0,19,7,43,0,0,8,116,0,0,8,52,0,0,9,200,0,17,7,13,0,0,8,100,0,0,8,36,0,0,9,168,0,0,8,4,0,0,8,132,0,0,8,68,0,0,9,232,0,16,7,8,0,0,8,92,0,0,8,28,0,0,9,152,0,20,7,83,0,0,8,124,0,0,8,60,0,0,9,216,0,18,7,23,0,0,8,108,0,0,8,44,0,0,9,184,0,0,8,12,0,0,8,140,0,0,8,76,0,0,9,248,0,16,7,3,0,0,8,82,0,0,8,18,0,21,8,163,0,19,7,35,0,0,8,114,0,0,8,50,0,0,9,196,0,17,7,11,0,0,8,98,0,0,8,34,0,0,9,164,0,0,8,2,0,0,8,130,0,0,8,66,0,0,9,228,0,16,7,7,0,0,8,90,0,0,8,26,0,0,9,148,0,20,7,67,0,0,8,122,0,0,8,58,0,0,9,212,0,18,7,19,0,0,8,106,0,0,8,42,0,0,9,180,0,0,8,10,0,0,8,138,0,0,8,74,0,0,9,244,0,16,7,5,0,0,8,86,0,0,8,22,0,64,8,0,0,19,7,51,0,0,8,118,0,0,8,54,0,0,9,204,0,17,7,15,0,0,8,102,0,0,8,38,0,0,9,172,0,0,8,6,0,0,8,134,0,0,8,70,0,0,9,236,0,16,7,9,0,0,8,94,0,0,8,30,0,0,9,156,0,20,7,99,0,0,8,126,0,0,8,62,0,0,9,220,0,18,7,27,0,0,8,110,0,0,8,46,0,0,9,188,0,0,8,14,0,0,8,142,0,0,8,78,0,0,9,252,0,96,7,0,0,0,8,81,0,0,8,17,0,21,8,131,0,18,7,31,0,0,8,113,0,0,8,49,0,0,9,194,0,16,7,10,0,0,8,97,0,0,8,33,0,0,9,162,0,0,8,1,0,0,8,129,0,0,8,65,0,0,9,226,0,16,7,6,0,0,8,89,0,0,8,25,0,0,9,146,0,19,7,59,0,0,8,121,0,0,8,57,0,0,9,210,0,17,7,17,0,0,8,105,0,0,8,41,0,0,9,178,0,0,8,9,0,0,8,137,0,0,8,73,0,0,9,242,0,16,7,4,0,0,8,85,0,0,8,21,0,16,8,2,1,19,7,43,0,0,8,117,0,0,8,53,0,0,9,202,0,17,7,13,0,0,8,101,0,0,8,37,0,0,9,170,0,0,8,5,0,0,8,133,0,0,8,69,0,0,9,234,0,16,7,8,0,0,8,93,0,0,8,29,0,0,9,154,0,20,7,83,0,0,8,125,0,0,8,61,0,0,9,218,0,18,7,23,0,0,8,109,0,0,8,45,0,0,9,186,0,0,8,13,0,0,8,141,0,0,8,77,0,0,9,250,0,16,7,3,0,0,8,83,0,0,8,19,0,21,8,195,0,19,7,35,0,0,8,115,0,0,8,51,0,0,9,198,0,17,7,11,0,0,8,99,0,0,8,35,0,0,9,166,0,0,8,3,0,0,8,131,0,0,8,67,0,0,9,230,0,16,7,7,0,0,8,91,0,0,8,27,0,0,9,150,0,20,7,67,0,0,8,123,0,0,8,59,0,0,9,214,0,18,7,19,0,0,8,107,0,0,8,43,0,0,9,182,0,0,8,11,0,0,8,139,0,0,8,75,0,0,9,246,0,16,7,5,0,0,8,87,0,0,8,23,0,64,8,0,0,19,7,51,0,0,8,119,0,0,8,55,0,0,9,206,0,17,7,15,0,0,8,103,0,0,8,39,0,0,9,174,0,0,8,7,0,0,8,135,0,0,8,71,0,0,9,238,0,16,7,9,0,0,8,95,0,0,8,31,0,0,9,158,0,20,7,99,0,0,8,127,0,0,8,63,0,0,9,222,0,18,7,27,0,0,8,111,0,0,8,47,0,0,9,190,0,0,8,15,0,0,8,143,0,0,8,79,0,0,9,254,0,96,7,0,0,0,8,80,0,0,8,16,0,20,8,115,0,18,7,31,0,0,8,112,0,0,8,48,0,0,9,193,0,16,7,10,0,0,8,96,0,0,8,32,0,0,9,161,0,0,8,0,0,0,8,128,0,0,8,64,0,0,9,225,0,16,7,6,0,0,8,88,0,0,8,24,0,0,9,145,0,19,7,59,0,0,8,120,0,0,8,56,0,0,9,209,0,17,7,17,0,0,8,104,0,0,8,40,0,0,9,177,0,0,8,8,0,0,8,136,0,0,8,72,0,0,9,241,0,16,7,4,0,0,8,84,0,0,8,20,0,21,8,227,0,19,7,43,0,0,8,116,0,0,8,52,0,0,9,201,0,17,7,13,0,0,8,100,0,0,8,36,0,0,9,169,0,0,8,4,0,0,8,132,0,0,8,68,0,0,9,233,0,16,7,8,0,0,8,92,0,0,8,28,0,0,9,153,0,20,7,83,0,0,8,124,0,0,8,60,0,0,9,217,0,18,7,23,0,0,8,108,0,0,8,44,0,0,9,185,0,0,8,12,0,0,8,140,0,0,8,76,0,0,9,249,0,16,7,3,0,0,8,82,0,0,8,18,0,21,8,163,0,19,7,35,0,0,8,114,0,0,8,50,0,0,9,197,0,17,7,11,0,0,8,98,0,0,8,34,0,0,9,165,0,0,8,2,0,0,8,130,0,0,8,66,0,0,9,229,0,16,7,7,0,0,8,90,0,0,8,26,0,0,9,149,0,20,7,67,0,0,8,122,0,0,8,58,0,0,9,213,0,18,7,19,0,0,8,106,0,0,8,42,0,0,9,181,0,0,8,10,0,0,8,138,0,0,8,74,0,0,9,245,0,16,7,5,0,0,8,86,0,0,8,22,0,64,8,0,0,19,7,51,0,0,8,118,0,0,8,54,0,0,9,205,0,17,7,15,0,0,8,102,0,0,8,38,0,0,9,173,0,0,8,6,0,0,8,134,0,0,8,70,0,0,9,237,0,16,7,9,0,0,8,94,0,0,8,30,0,0,9,157,0,20,7,99,0,0,8,126,0,0,8,62,0,0,9,221,0,18,7,27,0,0,8,110,0,0,8,46,0,0,9,189,0,0,8,14,0,0,8,142,0,0,8,78,0,0,9,253,0,96,7,0,0,0,8,81,0,0,8,17,0,21,8,131,0,18,7,31,0,0,8,113,0,0,8,49,0,0,9,195,0,16,7,10,0,0,8,97,0,0,8,33,0,0,9,163,0,0,8,1,0,0,8,129,0,0,8,65,0,0,9,227,0,16,7,6,0,0,8,89,0,0,8,25,0,0,9,147,0,19,7,59,0,0,8,121,0,0,8,57,0,0,9,211,0,17,7,17,0,0,8,105,0,0,8,41,0,0,9,179,0,0,8,9,0,0,8,137,0,0,8,73,0,0,9,243,0,16,7,4,0,0,8,85,0,0,8,21,0,16,8,2,1,19,7,43,0,0,8,117,0,0,8,53,0,0,9,203,0,17,7,13,0,0,8,101,0,0,8,37,0,0,9,171,0,0,8,5,0,0,8,133,0,0,8,69,0,0,9,235,0,16,7,8,0,0,8,93,0,0,8,29,0,0,9,155,0,20,7,83,0,0,8,125,0,0,8,61,0,0,9,219,0,18,7,23,0,0,8,109,0,0,8,45,0,0,9,187,0,0,8,13,0,0,8,141,0,0,8,77,0,0,9,251,0,16,7,3,0,0,8,83,0,0,8,19,0,21,8,195,0,19,7,35,0,0,8,115,0,0,8,51,0,0,9,199,0,17,7,11,0,0,8,99,0,0,8,35,0,0,9,167,0,0,8,3,0,0,8,131,0,0,8,67,0,0,9,231,0,16,7,7,0,0,8,91,0,0,8,27,0,0,9,151,0,20,7,67,0,0,8,123,0,0,8,59,0,0,9,215,0,18,7,19,0,0,8,107,0,0,8,43,0,0,9,183,0,0,8,11,0,0,8,139,0,0,8,75,0,0,9,247,0,16,7,5,0,0,8,87,0,0,8,23,0,64,8,0,0,19,7,51,0,0,8,119,0,0,8,55,0,0,9,207,0,17,7,15,0,0,8,103,0,0,8,39,0,0,9,175,0,0,8,7,0,0,8,135,0,0,8,71,0,0,9,239,0,16,7,9,0,0,8,95,0,0,8,31,0,0,9,159,0,20,7,99,0,0,8,127,0,0,8,63,0,0,9,223,0,18,7,27,0,0,8,111,0,0,8,47,0,0,9,191,0,0,8,15,0,0,8,143,0,0,8,79,0,0,9,255,0,16,5,1,0,23,5,1,1,19,5,17,0,27,5,1,16,17,5,5,0,25,5,1,4,21,5,65,0,29,5,1,64,16,5,3,0,24,5,1,2,20,5,33,0,28,5,1,32,18,5,9,0,26,5,1,8,22,5,129,0,64,5,0,0,16,5,2,0,23,5,129,1,19,5,25,0,27,5,1,24,17,5,7,0,25,5,1,6,21,5,97,0,29,5,1,96,16,5,4,0,24,5,1,3,20,5,49,0,28,5,1,48,18,5,13,0,26,5,1,12,22,5,193,0,64,5,0,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,13,0,15,0,17,0,19,0,23,0,27,0,31,0,35,0,43,0,51,0,59,0,67,0,83,0,99,0,115,0,131,0,163,0,195,0,227,0,2,1,0,0,0,0,0,0,16,0,16,0,16,0,16,0,16,0,16,0,16,0,16,0,17,0,17,0,17,0,17,0,18,0,18,0,18,0,18,0,19,0,19,0,19,0,19,0,20,0,20,0,20,0,20,0,21,0,21,0,21,0,21,0,16,0,73,0,195,0,0,0,1,0,2,0,3,0,4,0,5,0,7,0,9,0,13,0,17,0,25,0,33,0,49,0,65,0,97,0,129,0,193,0,1,1,129,1,1,2,1,3,1,4,1,6,1,8,1,12,1,16,1,24,1,32,1,48,1,64,1,96,0,0,0,0,16,0,16,0,16,0,16,0,17,0,17,0,18,0,18,0,19,0,19,0,20,0,20,0,21,0,21,0,22,0,22,0,23,0,23,0,24,0,24,0,25,0,25,0,26,0,26,0,27,0,27,0,28,0,28,0,29,0,29,0,64,0,64,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,32,116,111,111,32,102,97,114,32,98,97,99,107,0,0,0,105,110,118,97,108,105,100,32,100,105,115,116,97,110,99,101,32,99,111,100,101,0,0,0,105,110,118,97,108,105,100,32,108,105,116,101,114,97,108,47,108,101,110,103,116,104,32,99,111,100,101,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,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,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,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], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE+10240);
+
+
+
+
+var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
+
+assert(tempDoublePtr % 8 == 0);
+
+function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+}
+
+function copyTempDouble(ptr) {
+
+  HEAP8[tempDoublePtr] = HEAP8[ptr];
+
+  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
+
+  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
+
+  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
+
+  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
+
+  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
+
+  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
+
+  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
+
+}
+
+
+
+
+
+
+  var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};
+
+  var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
+
+
+  var ___errno_state=0;function ___setErrNo(value) {
+      // For convenient setting and returning of errno.
+      HEAP32[((___errno_state)>>2)]=value;
+      return value;
+    }
+
+  var PATH={splitPath:function (filename) {
+        var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+        return splitPathRe.exec(filename).slice(1);
+      },normalizeArray:function (parts, allowAboveRoot) {
+        // if the path tries to go above the root, `up` ends up > 0
+        var up = 0;
+        for (var i = parts.length - 1; i >= 0; i--) {
+          var last = parts[i];
+          if (last === '.') {
+            parts.splice(i, 1);
+          } else if (last === '..') {
+            parts.splice(i, 1);
+            up++;
+          } else if (up) {
+            parts.splice(i, 1);
+            up--;
+          }
+        }
+        // if the path is allowed to go above the root, restore leading ..s
+        if (allowAboveRoot) {
+          for (; up--; up) {
+            parts.unshift('..');
+          }
+        }
+        return parts;
+      },normalize:function (path) {
+        var isAbsolute = path.charAt(0) === '/',
+            trailingSlash = path.substr(-1) === '/';
+        // Normalize the path
+        path = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), !isAbsolute).join('/');
+        if (!path && !isAbsolute) {
+          path = '.';
+        }
+        if (path && trailingSlash) {
+          path += '/';
+        }
+        return (isAbsolute ? '/' : '') + path;
+      },dirname:function (path) {
+        var result = PATH.splitPath(path),
+            root = result[0],
+            dir = result[1];
+        if (!root && !dir) {
+          // No dirname whatsoever
+          return '.';
+        }
+        if (dir) {
+          // It has a dirname, strip trailing slash
+          dir = dir.substr(0, dir.length - 1);
+        }
+        return root + dir;
+      },basename:function (path) {
+        // EMSCRIPTEN return '/'' for '/', not an empty string
+        if (path === '/') return '/';
+        var lastSlash = path.lastIndexOf('/');
+        if (lastSlash === -1) return path;
+        return path.substr(lastSlash+1);
+      },extname:function (path) {
+        return PATH.splitPath(path)[3];
+      },join:function () {
+        var paths = Array.prototype.slice.call(arguments, 0);
+        return PATH.normalize(paths.join('/'));
+      },join2:function (l, r) {
+        return PATH.normalize(l + '/' + r);
+      },resolve:function () {
+        var resolvedPath = '',
+          resolvedAbsolute = false;
+        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+          var path = (i >= 0) ? arguments[i] : FS.cwd();
+          // Skip empty and invalid entries
+          if (typeof path !== 'string') {
+            throw new TypeError('Arguments to path.resolve must be strings');
+          } else if (!path) {
+            continue;
+          }
+          resolvedPath = path + '/' + resolvedPath;
+          resolvedAbsolute = path.charAt(0) === '/';
+        }
+        // At this point the path should be resolved to a full absolute path, but
+        // handle relative paths to be safe (might happen when process.cwd() fails)
+        resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
+          return !!p;
+        }), !resolvedAbsolute).join('/');
+        return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+      },relative:function (from, to) {
+        from = PATH.resolve(from).substr(1);
+        to = PATH.resolve(to).substr(1);
+        function trim(arr) {
+          var start = 0;
+          for (; start < arr.length; start++) {
+            if (arr[start] !== '') break;
+          }
+          var end = arr.length - 1;
+          for (; end >= 0; end--) {
+            if (arr[end] !== '') break;
+          }
+          if (start > end) return [];
+          return arr.slice(start, end - start + 1);
+        }
+        var fromParts = trim(from.split('/'));
+        var toParts = trim(to.split('/'));
+        var length = Math.min(fromParts.length, toParts.length);
+        var samePartsLength = length;
+        for (var i = 0; i < length; i++) {
+          if (fromParts[i] !== toParts[i]) {
+            samePartsLength = i;
+            break;
+          }
+        }
+        var outputParts = [];
+        for (var i = samePartsLength; i < fromParts.length; i++) {
+          outputParts.push('..');
+        }
+        outputParts = outputParts.concat(toParts.slice(samePartsLength));
+        return outputParts.join('/');
+      }};
+
+  var TTY={ttys:[],init:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
+        //   // device, it always assumes it's a TTY device. because of this, we're forcing
+        //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
+        //   // with text files until FS.init can be refactored.
+        //   process['stdin']['setEncoding']('utf8');
+        // }
+      },shutdown:function () {
+        // https://github.com/kripken/emscripten/pull/1555
+        // if (ENVIRONMENT_IS_NODE) {
+        //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+        //   // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+        //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+        //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+        //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+        //   process['stdin']['pause']();
+        // }
+      },register:function (dev, ops) {
+        TTY.ttys[dev] = { input: [], output: [], ops: ops };
+        FS.registerDevice(dev, TTY.stream_ops);
+      },stream_ops:{open:function (stream) {
+          var tty = TTY.ttys[stream.node.rdev];
+          if (!tty) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          stream.tty = tty;
+          stream.seekable = false;
+        },close:function (stream) {
+          // flush any pending line data
+          if (stream.tty.output.length) {
+            stream.tty.ops.put_char(stream.tty, 10);
+          }
+        },read:function (stream, buffer, offset, length, pos /* ignored */) {
+          if (!stream.tty || !stream.tty.ops.get_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          var bytesRead = 0;
+          for (var i = 0; i < length; i++) {
+            var result;
+            try {
+              result = stream.tty.ops.get_char(stream.tty);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            if (result === undefined && bytesRead === 0) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+            if (result === null || result === undefined) break;
+            bytesRead++;
+            buffer[offset+i] = result;
+          }
+          if (bytesRead) {
+            stream.node.timestamp = Date.now();
+          }
+          return bytesRead;
+        },write:function (stream, buffer, offset, length, pos) {
+          if (!stream.tty || !stream.tty.ops.put_char) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
+          }
+          for (var i = 0; i < length; i++) {
+            try {
+              stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+          }
+          if (length) {
+            stream.node.timestamp = Date.now();
+          }
+          return i;
+        }},default_tty_ops:{get_char:function (tty) {
+          if (!tty.input.length) {
+            var result = null;
+            if (ENVIRONMENT_IS_NODE) {
+              result = process['stdin']['read']();
+              if (!result) {
+                if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+                  return null;  // EOF
+                }
+                return undefined;  // no data available
+              }
+            } else if (typeof window != 'undefined' &&
+              typeof window.prompt == 'function') {
+              // Browser.
+              result = window.prompt('Input: ');  // returns null on cancel
+              if (result !== null) {
+                result += '\n';
+              }
+            } else if (typeof readline == 'function') {
+              // Command line.
+              result = readline();
+              if (result !== null) {
+                result += '\n';
+              }
+            }
+            if (!result) {
+              return null;
+            }
+            tty.input = intArrayFromString(result, true);
+          }
+          return tty.input.shift();
+        },put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['print'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }},default_tty1_ops:{put_char:function (tty, val) {
+          if (val === null || val === 10) {
+            Module['printErr'](tty.output.join(''));
+            tty.output = [];
+          } else {
+            tty.output.push(TTY.utf8.processCChar(val));
+          }
+        }}};
+
+  var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
+        return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
+          // no supported
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (!MEMFS.ops_table) {
+          MEMFS.ops_table = {
+            dir: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                lookup: MEMFS.node_ops.lookup,
+                mknod: MEMFS.node_ops.mknod,
+                rename: MEMFS.node_ops.rename,
+                unlink: MEMFS.node_ops.unlink,
+                rmdir: MEMFS.node_ops.rmdir,
+                readdir: MEMFS.node_ops.readdir,
+                symlink: MEMFS.node_ops.symlink
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek
+              }
+            },
+            file: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: {
+                llseek: MEMFS.stream_ops.llseek,
+                read: MEMFS.stream_ops.read,
+                write: MEMFS.stream_ops.write,
+                allocate: MEMFS.stream_ops.allocate,
+                mmap: MEMFS.stream_ops.mmap
+              }
+            },
+            link: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr,
+                readlink: MEMFS.node_ops.readlink
+              },
+              stream: {}
+            },
+            chrdev: {
+              node: {
+                getattr: MEMFS.node_ops.getattr,
+                setattr: MEMFS.node_ops.setattr
+              },
+              stream: FS.chrdev_stream_ops
+            },
+          };
+        }
+        var node = FS.createNode(parent, name, mode, dev);
+        if (FS.isDir(node.mode)) {
+          node.node_ops = MEMFS.ops_table.dir.node;
+          node.stream_ops = MEMFS.ops_table.dir.stream;
+          node.contents = {};
+        } else if (FS.isFile(node.mode)) {
+          node.node_ops = MEMFS.ops_table.file.node;
+          node.stream_ops = MEMFS.ops_table.file.stream;
+          node.contents = [];
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        } else if (FS.isLink(node.mode)) {
+          node.node_ops = MEMFS.ops_table.link.node;
+          node.stream_ops = MEMFS.ops_table.link.stream;
+        } else if (FS.isChrdev(node.mode)) {
+          node.node_ops = MEMFS.ops_table.chrdev.node;
+          node.stream_ops = MEMFS.ops_table.chrdev.stream;
+        }
+        node.timestamp = Date.now();
+        // add the new node to the parent
+        if (parent) {
+          parent.contents[name] = node;
+        }
+        return node;
+      },ensureFlexible:function (node) {
+        if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+          var contents = node.contents;
+          node.contents = Array.prototype.slice.call(contents);
+          node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+        }
+      },node_ops:{getattr:function (node) {
+          var attr = {};
+          // device numbers reuse inode numbers.
+          attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
+          attr.ino = node.id;
+          attr.mode = node.mode;
+          attr.nlink = 1;
+          attr.uid = 0;
+          attr.gid = 0;
+          attr.rdev = node.rdev;
+          if (FS.isDir(node.mode)) {
+            attr.size = 4096;
+          } else if (FS.isFile(node.mode)) {
+            attr.size = node.contents.length;
+          } else if (FS.isLink(node.mode)) {
+            attr.size = node.link.length;
+          } else {
+            attr.size = 0;
+          }
+          attr.atime = new Date(node.timestamp);
+          attr.mtime = new Date(node.timestamp);
+          attr.ctime = new Date(node.timestamp);
+          // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
+          //       but this is not required by the standard.
+          attr.blksize = 4096;
+          attr.blocks = Math.ceil(attr.size / attr.blksize);
+          return attr;
+        },setattr:function (node, attr) {
+          if (attr.mode !== undefined) {
+            node.mode = attr.mode;
+          }
+          if (attr.timestamp !== undefined) {
+            node.timestamp = attr.timestamp;
+          }
+          if (attr.size !== undefined) {
+            MEMFS.ensureFlexible(node);
+            var contents = node.contents;
+            if (attr.size < contents.length) contents.length = attr.size;
+            else while (attr.size > contents.length) contents.push(0);
+          }
+        },lookup:function (parent, name) {
+          throw FS.genericErrors[ERRNO_CODES.ENOENT];
+        },mknod:function (parent, name, mode, dev) {
+          return MEMFS.createNode(parent, name, mode, dev);
+        },rename:function (old_node, new_dir, new_name) {
+          // if we're overwriting a directory at new_name, make sure it's empty.
+          if (FS.isDir(old_node.mode)) {
+            var new_node;
+            try {
+              new_node = FS.lookupNode(new_dir, new_name);
+            } catch (e) {
+            }
+            if (new_node) {
+              for (var i in new_node.contents) {
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+              }
+            }
+          }
+          // do the internal rewiring
+          delete old_node.parent.contents[old_node.name];
+          old_node.name = new_name;
+          new_dir.contents[new_name] = old_node;
+          old_node.parent = new_dir;
+        },unlink:function (parent, name) {
+          delete parent.contents[name];
+        },rmdir:function (parent, name) {
+          var node = FS.lookupNode(parent, name);
+          for (var i in node.contents) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+          }
+          delete parent.contents[name];
+        },readdir:function (node) {
+          var entries = ['.', '..']
+          for (var key in node.contents) {
+            if (!node.contents.hasOwnProperty(key)) {
+              continue;
+            }
+            entries.push(key);
+          }
+          return entries;
+        },symlink:function (parent, newname, oldpath) {
+          var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
+          node.link = oldpath;
+          return node;
+        },readlink:function (node) {
+          if (!FS.isLink(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          return node.link;
+        }},stream_ops:{read:function (stream, buffer, offset, length, position) {
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (size > 8 && contents.subarray) { // non-trivial, and typed array
+            buffer.set(contents.subarray(position, position + size), offset);
+          } else
+          {
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          }
+          return size;
+        },write:function (stream, buffer, offset, length, position, canOwn) {
+          var node = stream.node;
+          node.timestamp = Date.now();
+          var contents = node.contents;
+          if (length && contents.length === 0 && position === 0 && buffer.subarray) {
+            // just replace it with the new data
+            if (canOwn && offset === 0) {
+              node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
+              node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
+            } else {
+              node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
+              node.contentMode = MEMFS.CONTENT_FIXED;
+            }
+            return length;
+          }
+          MEMFS.ensureFlexible(node);
+          var contents = node.contents;
+          while (contents.length < position) contents.push(0);
+          for (var i = 0; i < length; i++) {
+            contents[position + i] = buffer[offset + i];
+          }
+          return length;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              position += stream.node.contents.length;
+            }
+          }
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          stream.ungotten = [];
+          stream.position = position;
+          return position;
+        },allocate:function (stream, offset, length) {
+          MEMFS.ensureFlexible(stream.node);
+          var contents = stream.node.contents;
+          var limit = offset + length;
+          while (limit > contents.length) contents.push(0);
+        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+          if (!FS.isFile(stream.node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+          }
+          var ptr;
+          var allocated;
+          var contents = stream.node.contents;
+          // Only make a new copy when MAP_PRIVATE is specified.
+          if ( !(flags & 2) &&
+                (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
+            // We can't emulate MAP_SHARED when the file is not backed by the buffer
+            // we're mapping to (e.g. the HEAP buffer).
+            allocated = false;
+            ptr = contents.byteOffset;
+          } else {
+            // Try to avoid unnecessary slices.
+            if (position > 0 || position + length < contents.length) {
+              if (contents.subarray) {
+                contents = contents.subarray(position, position + length);
+              } else {
+                contents = Array.prototype.slice.call(contents, position, position + length);
+              }
+            }
+            allocated = true;
+            ptr = _malloc(length);
+            if (!ptr) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
+            }
+            buffer.set(contents, ptr);
+          }
+          return { ptr: ptr, allocated: allocated };
+        }}};
+
+  var IDBFS={dbs:{},indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
+        // reuse all of the core MEMFS functionality
+        return MEMFS.mount.apply(null, arguments);
+      },syncfs:function (mount, populate, callback) {
+        IDBFS.getLocalSet(mount, function(err, local) {
+          if (err) return callback(err);
+
+          IDBFS.getRemoteSet(mount, function(err, remote) {
+            if (err) return callback(err);
+
+            var src = populate ? remote : local;
+            var dst = populate ? local : remote;
+
+            IDBFS.reconcile(src, dst, callback);
+          });
+        });
+      },getDB:function (name, callback) {
+        // check the cache first
+        var db = IDBFS.dbs[name];
+        if (db) {
+          return callback(null, db);
+        }
+
+        var req;
+        try {
+          req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+        } catch (e) {
+          return callback(e);
+        }
+        req.onupgradeneeded = function(e) {
+          var db = e.target.result;
+          var transaction = e.target.transaction;
+
+          var fileStore;
+
+          if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
+            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          } else {
+            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
+          }
+
+          fileStore.createIndex('timestamp', 'timestamp', { unique: false });
+        };
+        req.onsuccess = function() {
+          db = req.result;
+
+          // add to the cache
+          IDBFS.dbs[name] = db;
+          callback(null, db);
+        };
+        req.onerror = function() {
+          callback(this.error);
+        };
+      },getLocalSet:function (mount, callback) {
+        var entries = {};
+
+        function isRealDir(p) {
+          return p !== '.' && p !== '..';
+        };
+        function toAbsolute(root) {
+          return function(p) {
+            return PATH.join2(root, p);
+          }
+        };
+
+        var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
+
+        while (check.length) {
+          var path = check.pop();
+          var stat;
+
+          try {
+            stat = FS.stat(path);
+          } catch (e) {
+            return callback(e);
+          }
+
+          if (FS.isDir(stat.mode)) {
+            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
+          }
+
+          entries[path] = { timestamp: stat.mtime };
+        }
+
+        return callback(null, { type: 'local', entries: entries });
+      },getRemoteSet:function (mount, callback) {
+        var entries = {};
+
+        IDBFS.getDB(mount.mountpoint, function(err, db) {
+          if (err) return callback(err);
+
+          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+          transaction.onerror = function() { callback(this.error); };
+
+          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+          var index = store.index('timestamp');
+
+          index.openKeyCursor().onsuccess = function(event) {
+            var cursor = event.target.result;
+
+            if (!cursor) {
+              return callback(null, { type: 'remote', db: db, entries: entries });
+            }
+
+            entries[cursor.primaryKey] = { timestamp: cursor.key };
+
+            cursor.continue();
+          };
+        });
+      },loadLocalEntry:function (path, callback) {
+        var stat, node;
+
+        try {
+          var lookup = FS.lookupPath(path);
+          node = lookup.node;
+          stat = FS.stat(path);
+        } catch (e) {
+          return callback(e);
+        }
+
+        if (FS.isDir(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode });
+        } else if (FS.isFile(stat.mode)) {
+          return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
+        } else {
+          return callback(new Error('node type not supported'));
+        }
+      },storeLocalEntry:function (path, entry, callback) {
+        try {
+          if (FS.isDir(entry.mode)) {
+            FS.mkdir(path, entry.mode);
+          } else if (FS.isFile(entry.mode)) {
+            FS.writeFile(path, entry.contents, { encoding: 'binary', canOwn: true });
+          } else {
+            return callback(new Error('node type not supported'));
+          }
+
+          FS.utime(path, entry.timestamp, entry.timestamp);
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },removeLocalEntry:function (path, callback) {
+        try {
+          var lookup = FS.lookupPath(path);
+          var stat = FS.stat(path);
+
+          if (FS.isDir(stat.mode)) {
+            FS.rmdir(path);
+          } else if (FS.isFile(stat.mode)) {
+            FS.unlink(path);
+          }
+        } catch (e) {
+          return callback(e);
+        }
+
+        callback(null);
+      },loadRemoteEntry:function (store, path, callback) {
+        var req = store.get(path);
+        req.onsuccess = function(event) { callback(null, event.target.result); };
+        req.onerror = function() { callback(this.error); };
+      },storeRemoteEntry:function (store, path, entry, callback) {
+        var req = store.put(entry, path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },removeRemoteEntry:function (store, path, callback) {
+        var req = store.delete(path);
+        req.onsuccess = function() { callback(null); };
+        req.onerror = function() { callback(this.error); };
+      },reconcile:function (src, dst, callback) {
+        var total = 0;
+
+        var create = [];
+        Object.keys(src.entries).forEach(function (key) {
+          var e = src.entries[key];
+          var e2 = dst.entries[key];
+          if (!e2 || e.timestamp > e2.timestamp) {
+            create.push(key);
+            total++;
+          }
+        });
+
+        var remove = [];
+        Object.keys(dst.entries).forEach(function (key) {
+          var e = dst.entries[key];
+          var e2 = src.entries[key];
+          if (!e2) {
+            remove.push(key);
+            total++;
+          }
+        });
+
+        if (!total) {
+          return callback(null);
+        }
+
+        var errored = false;
+        var completed = 0;
+        var db = src.type === 'remote' ? src.db : dst.db;
+        var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= total) {
+            return callback(null);
+          }
+        };
+
+        transaction.onerror = function() { done(this.error); };
+
+        // sort paths in ascending order so directory entries are created
+        // before the files inside them
+        create.sort().forEach(function (path) {
+          if (dst.type === 'local') {
+            IDBFS.loadRemoteEntry(store, path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeLocalEntry(path, entry, done);
+            });
+          } else {
+            IDBFS.loadLocalEntry(path, function (err, entry) {
+              if (err) return done(err);
+              IDBFS.storeRemoteEntry(store, path, entry, done);
+            });
+          }
+        });
+
+        // sort paths in descending order so files are deleted before their
+        // parent directories
+        remove.sort().reverse().forEach(function(path) {
+          if (dst.type === 'local') {
+            IDBFS.removeLocalEntry(path, done);
+          } else {
+            IDBFS.removeRemoteEntry(store, path, done);
+          }
+        });
+      }};
+
+  var NODEFS={isWindows:false,staticInit:function () {
+        NODEFS.isWindows = !!process.platform.match(/^win/);
+      },mount:function (mount) {
+        assert(ENVIRONMENT_IS_NODE);
+        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+      },createNode:function (parent, name, mode, dev) {
+        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node = FS.createNode(parent, name, mode);
+        node.node_ops = NODEFS.node_ops;
+        node.stream_ops = NODEFS.stream_ops;
+        return node;
+      },getMode:function (path) {
+        var stat;
+        try {
+          stat = fs.lstatSync(path);
+          if (NODEFS.isWindows) {
+            // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
+            // propagate write bits to execute bits.
+            stat.mode = stat.mode | ((stat.mode & 146) >> 1);
+          }
+        } catch (e) {
+          if (!e.code) throw e;
+          throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+        }
+        return stat.mode;
+      },realPath:function (node) {
+        var parts = [];
+        while (node.parent !== node) {
+          parts.push(node.name);
+          node = node.parent;
+        }
+        parts.push(node.mount.opts.root);
+        parts.reverse();
+        return PATH.join.apply(null, parts);
+      },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
+        if (flags in NODEFS.flagsToPermissionStringMap) {
+          return NODEFS.flagsToPermissionStringMap[flags];
+        } else {
+          return flags;
+        }
+      },node_ops:{getattr:function (node) {
+          var path = NODEFS.realPath(node);
+          var stat;
+          try {
+            stat = fs.lstatSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
+          // See http://support.microsoft.com/kb/140365
+          if (NODEFS.isWindows && !stat.blksize) {
+            stat.blksize = 4096;
+          }
+          if (NODEFS.isWindows && !stat.blocks) {
+            stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
+          }
+          return {
+            dev: stat.dev,
+            ino: stat.ino,
+            mode: stat.mode,
+            nlink: stat.nlink,
+            uid: stat.uid,
+            gid: stat.gid,
+            rdev: stat.rdev,
+            size: stat.size,
+            atime: stat.atime,
+            mtime: stat.mtime,
+            ctime: stat.ctime,
+            blksize: stat.blksize,
+            blocks: stat.blocks
+          };
+        },setattr:function (node, attr) {
+          var path = NODEFS.realPath(node);
+          try {
+            if (attr.mode !== undefined) {
+              fs.chmodSync(path, attr.mode);
+              // update the common node structure mode as well
+              node.mode = attr.mode;
+            }
+            if (attr.timestamp !== undefined) {
+              var date = new Date(attr.timestamp);
+              fs.utimesSync(path, date, date);
+            }
+            if (attr.size !== undefined) {
+              fs.truncateSync(path, attr.size);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },lookup:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          var mode = NODEFS.getMode(path);
+          return NODEFS.createNode(parent, name, mode);
+        },mknod:function (parent, name, mode, dev) {
+          var node = NODEFS.createNode(parent, name, mode, dev);
+          // create the backing node for this in the fs root as well
+          var path = NODEFS.realPath(node);
+          try {
+            if (FS.isDir(node.mode)) {
+              fs.mkdirSync(path, node.mode);
+            } else {
+              fs.writeFileSync(path, '', { mode: node.mode });
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return node;
+        },rename:function (oldNode, newDir, newName) {
+          var oldPath = NODEFS.realPath(oldNode);
+          var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
+          try {
+            fs.renameSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },unlink:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.unlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },rmdir:function (parent, name) {
+          var path = PATH.join2(NODEFS.realPath(parent), name);
+          try {
+            fs.rmdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readdir:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readdirSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },symlink:function (parent, newName, oldPath) {
+          var newPath = PATH.join2(NODEFS.realPath(parent), newName);
+          try {
+            fs.symlinkSync(oldPath, newPath);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },readlink:function (node) {
+          var path = NODEFS.realPath(node);
+          try {
+            return fs.readlinkSync(path);
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        }},stream_ops:{open:function (stream) {
+          var path = NODEFS.realPath(stream.node);
+          try {
+            if (FS.isFile(stream.node.mode)) {
+              stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },close:function (stream) {
+          try {
+            if (FS.isFile(stream.node.mode) && stream.nfd) {
+              fs.closeSync(stream.nfd);
+            }
+          } catch (e) {
+            if (!e.code) throw e;
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+        },read:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(length);
+          var res;
+          try {
+            res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          if (res > 0) {
+            for (var i = 0; i < res; i++) {
+              buffer[offset + i] = nbuffer[i];
+            }
+          }
+          return res;
+        },write:function (stream, buffer, offset, length, position) {
+          // FIXME this is terrible.
+          var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+          var res;
+          try {
+            res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+          }
+          return res;
+        },llseek:function (stream, offset, whence) {
+          var position = offset;
+          if (whence === 1) {  // SEEK_CUR.
+            position += stream.position;
+          } else if (whence === 2) {  // SEEK_END.
+            if (FS.isFile(stream.node.mode)) {
+              try {
+                var stat = fs.fstatSync(stream.nfd);
+                position += stat.size;
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+              }
+            }
+          }
+
+          if (position < 0) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+
+          stream.position = position;
+          return position;
+        }}};
+
+  var _stdin=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stdout=allocate(1, "i32*", ALLOC_STATIC);
+
+  var _stderr=allocate(1, "i32*", ALLOC_STATIC);
+
+  function _fflush(stream) {
+      // int fflush(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
+      // we don't currently perform any user-space buffering of data
+    }var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
+        if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
+        return ___setErrNo(e.errno);
+      },lookupPath:function (path, opts) {
+        path = PATH.resolve(FS.cwd(), path);
+        opts = opts || {};
+
+        var defaults = {
+          follow_mount: true,
+          recurse_count: 0
+        };
+        for (var key in defaults) {
+          if (opts[key] === undefined) {
+            opts[key] = defaults[key];
+          }
+        }
+
+        if (opts.recurse_count > 8) {  // max recursive lookup of 8
+          throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+        }
+
+        // split the path
+        var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+          return !!p;
+        }), false);
+
+        // start at the root
+        var current = FS.root;
+        var current_path = '/';
+
+        for (var i = 0; i < parts.length; i++) {
+          var islast = (i === parts.length-1);
+          if (islast && opts.parent) {
+            // stop resolving
+            break;
+          }
+
+          current = FS.lookupNode(current, parts[i]);
+          current_path = PATH.join2(current_path, parts[i]);
+
+          // jump to the mount's root node if this is a mountpoint
+          if (FS.isMountpoint(current)) {
+            if (!islast || (islast && opts.follow_mount)) {
+              current = current.mounted.root;
+            }
+          }
+
+          // by default, lookupPath will not follow a symlink if it is the final path component.
+          // setting opts.follow = true will override this behavior.
+          if (!islast || opts.follow) {
+            var count = 0;
+            while (FS.isLink(current.mode)) {
+              var link = FS.readlink(current_path);
+              current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+              var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+              current = lookup.node;
+
+              if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+                throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+              }
+            }
+          }
+        }
+
+        return { path: current_path, node: current };
+      },getPath:function (node) {
+        var path;
+        while (true) {
+          if (FS.isRoot(node)) {
+            var mount = node.mount.mountpoint;
+            if (!path) return mount;
+            return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
+          }
+          path = path ? node.name + '/' + path : node.name;
+          node = node.parent;
+        }
+      },hashName:function (parentid, name) {
+        var hash = 0;
+
+
+        for (var i = 0; i < name.length; i++) {
+          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
+        }
+        return ((parentid + hash) >>> 0) % FS.nameTable.length;
+      },hashAddNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        node.name_next = FS.nameTable[hash];
+        FS.nameTable[hash] = node;
+      },hashRemoveNode:function (node) {
+        var hash = FS.hashName(node.parent.id, node.name);
+        if (FS.nameTable[hash] === node) {
+          FS.nameTable[hash] = node.name_next;
+        } else {
+          var current = FS.nameTable[hash];
+          while (current) {
+            if (current.name_next === node) {
+              current.name_next = node.name_next;
+              break;
+            }
+            current = current.name_next;
+          }
+        }
+      },lookupNode:function (parent, name) {
+        var err = FS.mayLookup(parent);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        var hash = FS.hashName(parent.id, name);
+        for (var node = FS.nameTable[hash]; node; node = node.name_next) {
+          var nodeName = node.name;
+          if (node.parent.id === parent.id && nodeName === name) {
+            return node;
+          }
+        }
+        // if we failed to find it in the cache, call into the VFS
+        return FS.lookup(parent, name);
+      },createNode:function (parent, name, mode, rdev) {
+        if (!FS.FSNode) {
+          FS.FSNode = function(parent, name, mode, rdev) {
+            if (!parent) {
+              parent = this;  // root node sets parent to itself
+            }
+            this.parent = parent;
+            this.mount = parent.mount;
+            this.mounted = null;
+            this.id = FS.nextInode++;
+            this.name = name;
+            this.mode = mode;
+            this.node_ops = {};
+            this.stream_ops = {};
+            this.rdev = rdev;
+          };
+
+          FS.FSNode.prototype = {};
+
+          // compatibility
+          var readMode = 292 | 73;
+          var writeMode = 146;
+
+          // NOTE we must use Object.defineProperties instead of individual calls to
+          // Object.defineProperty in order to make closure compiler happy
+          Object.defineProperties(FS.FSNode.prototype, {
+            read: {
+              get: function() { return (this.mode & readMode) === readMode; },
+              set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
+            },
+            write: {
+              get: function() { return (this.mode & writeMode) === writeMode; },
+              set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
+            },
+            isFolder: {
+              get: function() { return FS.isDir(this.mode); },
+            },
+            isDevice: {
+              get: function() { return FS.isChrdev(this.mode); },
+            },
+          });
+        }
+
+        var node = new FS.FSNode(parent, name, mode, rdev);
+
+        FS.hashAddNode(node);
+
+        return node;
+      },destroyNode:function (node) {
+        FS.hashRemoveNode(node);
+      },isRoot:function (node) {
+        return node === node.parent;
+      },isMountpoint:function (node) {
+        return !!node.mounted;
+      },isFile:function (mode) {
+        return (mode & 61440) === 32768;
+      },isDir:function (mode) {
+        return (mode & 61440) === 16384;
+      },isLink:function (mode) {
+        return (mode & 61440) === 40960;
+      },isChrdev:function (mode) {
+        return (mode & 61440) === 8192;
+      },isBlkdev:function (mode) {
+        return (mode & 61440) === 24576;
+      },isFIFO:function (mode) {
+        return (mode & 61440) === 4096;
+      },isSocket:function (mode) {
+        return (mode & 49152) === 49152;
+      },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
+        var flags = FS.flagModes[str];
+        if (typeof flags === 'undefined') {
+          throw new Error('Unknown file open mode: ' + str);
+        }
+        return flags;
+      },flagsToPermissionString:function (flag) {
+        var accmode = flag & 2097155;
+        var perms = ['r', 'w', 'rw'][accmode];
+        if ((flag & 512)) {
+          perms += 'w';
+        }
+        return perms;
+      },nodePermissions:function (node, perms) {
+        if (FS.ignorePermissions) {
+          return 0;
+        }
+        // return 0 if any user, group or owner bits are set.
+        if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
+          return ERRNO_CODES.EACCES;
+        } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
+          return ERRNO_CODES.EACCES;
+        }
+        return 0;
+      },mayLookup:function (dir) {
+        return FS.nodePermissions(dir, 'x');
+      },mayCreate:function (dir, name) {
+        try {
+          var node = FS.lookupNode(dir, name);
+          return ERRNO_CODES.EEXIST;
+        } catch (e) {
+        }
+        return FS.nodePermissions(dir, 'wx');
+      },mayDelete:function (dir, name, isdir) {
+        var node;
+        try {
+          node = FS.lookupNode(dir, name);
+        } catch (e) {
+          return e.errno;
+        }
+        var err = FS.nodePermissions(dir, 'wx');
+        if (err) {
+          return err;
+        }
+        if (isdir) {
+          if (!FS.isDir(node.mode)) {
+            return ERRNO_CODES.ENOTDIR;
+          }
+          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
+            return ERRNO_CODES.EBUSY;
+          }
+        } else {
+          if (FS.isDir(node.mode)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return 0;
+      },mayOpen:function (node, flags) {
+        if (!node) {
+          return ERRNO_CODES.ENOENT;
+        }
+        if (FS.isLink(node.mode)) {
+          return ERRNO_CODES.ELOOP;
+        } else if (FS.isDir(node.mode)) {
+          if ((flags & 2097155) !== 0 ||  // opening for write
+              (flags & 512)) {
+            return ERRNO_CODES.EISDIR;
+          }
+        }
+        return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
+      },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
+        fd_start = fd_start || 0;
+        fd_end = fd_end || FS.MAX_OPEN_FDS;
+        for (var fd = fd_start; fd <= fd_end; fd++) {
+          if (!FS.streams[fd]) {
+            return fd;
+          }
+        }
+        throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
+      },getStream:function (fd) {
+        return FS.streams[fd];
+      },createStream:function (stream, fd_start, fd_end) {
+        if (!FS.FSStream) {
+          FS.FSStream = function(){};
+          FS.FSStream.prototype = {};
+          // compatibility
+          Object.defineProperties(FS.FSStream.prototype, {
+            object: {
+              get: function() { return this.node; },
+              set: function(val) { this.node = val; }
+            },
+            isRead: {
+              get: function() { return (this.flags & 2097155) !== 1; }
+            },
+            isWrite: {
+              get: function() { return (this.flags & 2097155) !== 0; }
+            },
+            isAppend: {
+              get: function() { return (this.flags & 1024); }
+            }
+          });
+        }
+        if (0) {
+          // reuse the object
+          stream.__proto__ = FS.FSStream.prototype;
+        } else {
+          var newStream = new FS.FSStream();
+          for (var p in stream) {
+            newStream[p] = stream[p];
+          }
+          stream = newStream;
+        }
+        var fd = FS.nextfd(fd_start, fd_end);
+        stream.fd = fd;
+        FS.streams[fd] = stream;
+        return stream;
+      },closeStream:function (fd) {
+        FS.streams[fd] = null;
+      },getStreamFromPtr:function (ptr) {
+        return FS.streams[ptr - 1];
+      },getPtrForStream:function (stream) {
+        return stream ? stream.fd + 1 : 0;
+      },chrdev_stream_ops:{open:function (stream) {
+          var device = FS.getDevice(stream.node.rdev);
+          // override node's stream ops with the device's
+          stream.stream_ops = device.stream_ops;
+          // forward the open call
+          if (stream.stream_ops.open) {
+            stream.stream_ops.open(stream);
+          }
+        },llseek:function () {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }},major:function (dev) {
+        return ((dev) >> 8);
+      },minor:function (dev) {
+        return ((dev) & 0xff);
+      },makedev:function (ma, mi) {
+        return ((ma) << 8 | (mi));
+      },registerDevice:function (dev, ops) {
+        FS.devices[dev] = { stream_ops: ops };
+      },getDevice:function (dev) {
+        return FS.devices[dev];
+      },getMounts:function (mount) {
+        var mounts = [];
+        var check = [mount];
+
+        while (check.length) {
+          var m = check.pop();
+
+          mounts.push(m);
+
+          check.push.apply(check, m.mounts);
+        }
+
+        return mounts;
+      },syncfs:function (populate, callback) {
+        if (typeof(populate) === 'function') {
+          callback = populate;
+          populate = false;
+        }
+
+        var mounts = FS.getMounts(FS.root.mount);
+        var completed = 0;
+
+        function done(err) {
+          if (err) {
+            if (!done.errored) {
+              done.errored = true;
+              return callback(err);
+            }
+            return;
+          }
+          if (++completed >= mounts.length) {
+            callback(null);
+          }
+        };
+
+        // sync all mounts
+        mounts.forEach(function (mount) {
+          if (!mount.type.syncfs) {
+            return done(null);
+          }
+          mount.type.syncfs(mount, populate, done);
+        });
+      },mount:function (type, opts, mountpoint) {
+        var root = mountpoint === '/';
+        var pseudo = !mountpoint;
+        var node;
+
+        if (root && FS.root) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        } else if (!root && !pseudo) {
+          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+          mountpoint = lookup.path;  // use the absolute path
+          node = lookup.node;
+
+          if (FS.isMountpoint(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+          }
+
+          if (!FS.isDir(node.mode)) {
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+          }
+        }
+
+        var mount = {
+          type: type,
+          opts: opts,
+          mountpoint: mountpoint,
+          mounts: []
+        };
+
+        // create a root node for the fs
+        var mountRoot = type.mount(mount);
+        mountRoot.mount = mount;
+        mount.root = mountRoot;
+
+        if (root) {
+          FS.root = mountRoot;
+        } else if (node) {
+          // set as a mountpoint
+          node.mounted = mount;
+
+          // add the new mount to the current mount's children
+          if (node.mount) {
+            node.mount.mounts.push(mount);
+          }
+        }
+
+        return mountRoot;
+      },unmount:function (mountpoint) {
+        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
+
+        if (!FS.isMountpoint(lookup.node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+
+        // destroy the nodes for this mount, and all its child mounts
+        var node = lookup.node;
+        var mount = node.mounted;
+        var mounts = FS.getMounts(mount);
+
+        Object.keys(FS.nameTable).forEach(function (hash) {
+          var current = FS.nameTable[hash];
+
+          while (current) {
+            var next = current.name_next;
+
+            if (mounts.indexOf(current.mount) !== -1) {
+              FS.destroyNode(current);
+            }
+
+            current = next;
+          }
+        });
+
+        // no longer a mountpoint
+        node.mounted = null;
+
+        // remove this mount from the child mounts
+        var idx = node.mount.mounts.indexOf(mount);
+        assert(idx !== -1);
+        node.mount.mounts.splice(idx, 1);
+      },lookup:function (parent, name) {
+        return parent.node_ops.lookup(parent, name);
+      },mknod:function (path, mode, dev) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var err = FS.mayCreate(parent, name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.mknod) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.mknod(parent, name, mode, dev);
+      },create:function (path, mode) {
+        mode = mode !== undefined ? mode : 438 /* 0666 */;
+        mode &= 4095;
+        mode |= 32768;
+        return FS.mknod(path, mode, 0);
+      },mkdir:function (path, mode) {
+        mode = mode !== undefined ? mode : 511 /* 0777 */;
+        mode &= 511 | 512;
+        mode |= 16384;
+        return FS.mknod(path, mode, 0);
+      },mkdev:function (path, mode, dev) {
+        if (typeof(dev) === 'undefined') {
+          dev = mode;
+          mode = 438 /* 0666 */;
+        }
+        mode |= 8192;
+        return FS.mknod(path, mode, dev);
+      },symlink:function (oldpath, newpath) {
+        var lookup = FS.lookupPath(newpath, { parent: true });
+        var parent = lookup.node;
+        var newname = PATH.basename(newpath);
+        var err = FS.mayCreate(parent, newname);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.symlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return parent.node_ops.symlink(parent, newname, oldpath);
+      },rename:function (old_path, new_path) {
+        var old_dirname = PATH.dirname(old_path);
+        var new_dirname = PATH.dirname(new_path);
+        var old_name = PATH.basename(old_path);
+        var new_name = PATH.basename(new_path);
+        // parents must exist
+        var lookup, old_dir, new_dir;
+        try {
+          lookup = FS.lookupPath(old_path, { parent: true });
+          old_dir = lookup.node;
+          lookup = FS.lookupPath(new_path, { parent: true });
+          new_dir = lookup.node;
+        } catch (e) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // need to be part of the same mount
+        if (old_dir.mount !== new_dir.mount) {
+          throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
+        }
+        // source must exist
+        var old_node = FS.lookupNode(old_dir, old_name);
+        // old path should not be an ancestor of the new path
+        var relative = PATH.relative(old_path, new_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        // new path should not be an ancestor of the old path
+        relative = PATH.relative(new_path, old_dirname);
+        if (relative.charAt(0) !== '.') {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
+        }
+        // see if the new path already exists
+        var new_node;
+        try {
+          new_node = FS.lookupNode(new_dir, new_name);
+        } catch (e) {
+          // not fatal
+        }
+        // early out if nothing needs to change
+        if (old_node === new_node) {
+          return;
+        }
+        // we'll need to delete the old entry
+        var isdir = FS.isDir(old_node.mode);
+        var err = FS.mayDelete(old_dir, old_name, isdir);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // need delete permissions if we'll be overwriting.
+        // need create permissions if new doesn't already exist.
+        err = new_node ?
+          FS.mayDelete(new_dir, new_name, isdir) :
+          FS.mayCreate(new_dir, new_name);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!old_dir.node_ops.rename) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        // if we are going to change the parent, check write permissions
+        if (new_dir !== old_dir) {
+          err = FS.nodePermissions(old_dir, 'w');
+          if (err) {
+            throw new FS.ErrnoError(err);
+          }
+        }
+        // remove the node from the lookup hash
+        FS.hashRemoveNode(old_node);
+        // do the underlying fs rename
+        try {
+          old_dir.node_ops.rename(old_node, new_dir, new_name);
+        } catch (e) {
+          throw e;
+        } finally {
+          // add the node back to the hash (in case node_ops.rename
+          // changed its name)
+          FS.hashAddNode(old_node);
+        }
+      },rmdir:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, true);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.rmdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.rmdir(parent, name);
+        FS.destroyNode(node);
+      },readdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        if (!node.node_ops.readdir) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        return node.node_ops.readdir(node);
+      },unlink:function (path) {
+        var lookup = FS.lookupPath(path, { parent: true });
+        var parent = lookup.node;
+        var name = PATH.basename(path);
+        var node = FS.lookupNode(parent, name);
+        var err = FS.mayDelete(parent, name, false);
+        if (err) {
+          // POSIX says unlink should set EPERM, not EISDIR
+          if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
+          throw new FS.ErrnoError(err);
+        }
+        if (!parent.node_ops.unlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isMountpoint(node)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
+        }
+        parent.node_ops.unlink(parent, name);
+        FS.destroyNode(node);
+      },readlink:function (path) {
+        var lookup = FS.lookupPath(path);
+        var link = lookup.node;
+        if (!link.node_ops.readlink) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        return link.node_ops.readlink(link);
+      },stat:function (path, dontFollow) {
+        var lookup = FS.lookupPath(path, { follow: !dontFollow });
+        var node = lookup.node;
+        if (!node.node_ops.getattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        return node.node_ops.getattr(node);
+      },lstat:function (path) {
+        return FS.stat(path, true);
+      },chmod:function (path, mode, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          mode: (mode & 4095) | (node.mode & ~4095),
+          timestamp: Date.now()
+        });
+      },lchmod:function (path, mode) {
+        FS.chmod(path, mode, true);
+      },fchmod:function (fd, mode) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chmod(stream.node, mode);
+      },chown:function (path, uid, gid, dontFollow) {
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: !dontFollow });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        node.node_ops.setattr(node, {
+          timestamp: Date.now()
+          // we ignore the uid / gid for now
+        });
+      },lchown:function (path, uid, gid) {
+        FS.chown(path, uid, gid, true);
+      },fchown:function (fd, uid, gid) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        FS.chown(stream.node, uid, gid);
+      },truncate:function (path, len) {
+        if (len < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var node;
+        if (typeof path === 'string') {
+          var lookup = FS.lookupPath(path, { follow: true });
+          node = lookup.node;
+        } else {
+          node = path;
+        }
+        if (!node.node_ops.setattr) {
+          throw new FS.ErrnoError(ERRNO_CODES.EPERM);
+        }
+        if (FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!FS.isFile(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var err = FS.nodePermissions(node, 'w');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        node.node_ops.setattr(node, {
+          size: len,
+          timestamp: Date.now()
+        });
+      },ftruncate:function (fd, len) {
+        var stream = FS.getStream(fd);
+        if (!stream) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        FS.truncate(stream.node, len);
+      },utime:function (path, atime, mtime) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        var node = lookup.node;
+        node.node_ops.setattr(node, {
+          timestamp: Math.max(atime, mtime)
+        });
+      },open:function (path, flags, mode, fd_start, fd_end) {
+        flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
+        mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
+        if ((flags & 64)) {
+          mode = (mode & 4095) | 32768;
+        } else {
+          mode = 0;
+        }
+        var node;
+        if (typeof path === 'object') {
+          node = path;
+        } else {
+          path = PATH.normalize(path);
+          try {
+            var lookup = FS.lookupPath(path, {
+              follow: !(flags & 131072)
+            });
+            node = lookup.node;
+          } catch (e) {
+            // ignore
+          }
+        }
+        // perhaps we need to create the node
+        if ((flags & 64)) {
+          if (node) {
+            // if O_CREAT and O_EXCL are set, error out if the node already exists
+            if ((flags & 128)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
+            }
+          } else {
+            // node doesn't exist, try to create it
+            node = FS.mknod(path, mode, 0);
+          }
+        }
+        if (!node) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
+        }
+        // can't truncate a device
+        if (FS.isChrdev(node.mode)) {
+          flags &= ~512;
+        }
+        // check permissions
+        var err = FS.mayOpen(node, flags);
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        // do truncation if necessary
+        if ((flags & 512)) {
+          FS.truncate(node, 0);
+        }
+        // we've already handled these, don't pass down to the underlying vfs
+        flags &= ~(128 | 512);
+
+        // register the stream with the filesystem
+        var stream = FS.createStream({
+          node: node,
+          path: FS.getPath(node),  // we want the absolute path to the node
+          flags: flags,
+          seekable: true,
+          position: 0,
+          stream_ops: node.stream_ops,
+          // used by the file family libc calls (fopen, fwrite, ferror, etc.)
+          ungotten: [],
+          error: false
+        }, fd_start, fd_end);
+        // call the new stream's open function
+        if (stream.stream_ops.open) {
+          stream.stream_ops.open(stream);
+        }
+        if (Module['logReadFiles'] && !(flags & 1)) {
+          if (!FS.readFiles) FS.readFiles = {};
+          if (!(path in FS.readFiles)) {
+            FS.readFiles[path] = 1;
+            Module['printErr']('read file: ' + path);
+          }
+        }
+        return stream;
+      },close:function (stream) {
+        try {
+          if (stream.stream_ops.close) {
+            stream.stream_ops.close(stream);
+          }
+        } catch (e) {
+          throw e;
+        } finally {
+          FS.closeStream(stream.fd);
+        }
+      },llseek:function (stream, offset, whence) {
+        if (!stream.seekable || !stream.stream_ops.llseek) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        return stream.stream_ops.llseek(stream, offset, whence);
+      },read:function (stream, buffer, offset, length, position) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.read) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
+        if (!seeking) stream.position += bytesRead;
+        return bytesRead;
+      },write:function (stream, buffer, offset, length, position, canOwn) {
+        if (length < 0 || position < 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (FS.isDir(stream.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
+        }
+        if (!stream.stream_ops.write) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        var seeking = true;
+        if (typeof position === 'undefined') {
+          position = stream.position;
+          seeking = false;
+        } else if (!stream.seekable) {
+          throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
+        }
+        if (stream.flags & 1024) {
+          // seek to the end before writing in append mode
+          FS.llseek(stream, 0, 2);
+        }
+        var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
+        if (!seeking) stream.position += bytesWritten;
+        return bytesWritten;
+      },allocate:function (stream, offset, length) {
+        if (offset < 0 || length <= 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+        }
+        if ((stream.flags & 2097155) === 0) {
+          throw new FS.ErrnoError(ERRNO_CODES.EBADF);
+        }
+        if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        if (!stream.stream_ops.allocate) {
+          throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+        }
+        stream.stream_ops.allocate(stream, offset, length);
+      },mmap:function (stream, buffer, offset, length, position, prot, flags) {
+        // TODO if PROT is PROT_WRITE, make sure we have write access
+        if ((stream.flags & 2097155) === 1) {
+          throw new FS.ErrnoError(ERRNO_CODES.EACCES);
+        }
+        if (!stream.stream_ops.mmap) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
+        }
+        return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
+      },ioctl:function (stream, cmd, arg) {
+        if (!stream.stream_ops.ioctl) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
+        }
+        return stream.stream_ops.ioctl(stream, cmd, arg);
+      },readFile:function (path, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'r';
+        opts.encoding = opts.encoding || 'binary';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var ret;
+        var stream = FS.open(path, opts.flags);
+        var stat = FS.stat(path);
+        var length = stat.size;
+        var buf = new Uint8Array(length);
+        FS.read(stream, buf, 0, length, 0);
+        if (opts.encoding === 'utf8') {
+          ret = '';
+          var utf8 = new Runtime.UTF8Processor();
+          for (var i = 0; i < length; i++) {
+            ret += utf8.processCChar(buf[i]);
+          }
+        } else if (opts.encoding === 'binary') {
+          ret = buf;
+        }
+        FS.close(stream);
+        return ret;
+      },writeFile:function (path, data, opts) {
+        opts = opts || {};
+        opts.flags = opts.flags || 'w';
+        opts.encoding = opts.encoding || 'utf8';
+        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
+          throw new Error('Invalid encoding type "' + opts.encoding + '"');
+        }
+        var stream = FS.open(path, opts.flags, opts.mode);
+        if (opts.encoding === 'utf8') {
+          var utf8 = new Runtime.UTF8Processor();
+          var buf = new Uint8Array(utf8.processJSString(data));
+          FS.write(stream, buf, 0, buf.length, 0, opts.canOwn);
+        } else if (opts.encoding === 'binary') {
+          FS.write(stream, data, 0, data.length, 0, opts.canOwn);
+        }
+        FS.close(stream);
+      },cwd:function () {
+        return FS.currentPath;
+      },chdir:function (path) {
+        var lookup = FS.lookupPath(path, { follow: true });
+        if (!FS.isDir(lookup.node.mode)) {
+          throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+        }
+        var err = FS.nodePermissions(lookup.node, 'x');
+        if (err) {
+          throw new FS.ErrnoError(err);
+        }
+        FS.currentPath = lookup.path;
+      },createDefaultDirectories:function () {
+        FS.mkdir('/tmp');
+      },createDefaultDevices:function () {
+        // create /dev
+        FS.mkdir('/dev');
+        // setup /dev/null
+        FS.registerDevice(FS.makedev(1, 3), {
+          read: function() { return 0; },
+          write: function() { return 0; }
+        });
+        FS.mkdev('/dev/null', FS.makedev(1, 3));
+        // setup /dev/tty and /dev/tty1
+        // stderr needs to print output using Module['printErr']
+        // so we register a second tty just for it.
+        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
+        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
+        FS.mkdev('/dev/tty', FS.makedev(5, 0));
+        FS.mkdev('/dev/tty1', FS.makedev(6, 0));
+        // we're not going to emulate the actual shm device,
+        // just create the tmp dirs that reside in it commonly
+        FS.mkdir('/dev/shm');
+        FS.mkdir('/dev/shm/tmp');
+      },createStandardStreams:function () {
+        // TODO deprecate the old functionality of a single
+        // input / output callback and that utilizes FS.createDevice
+        // and instead require a unique set of stream ops
+
+        // by default, we symlink the standard streams to the
+        // default tty devices. however, if the standard streams
+        // have been overwritten we create a unique device for
+        // them instead.
+        if (Module['stdin']) {
+          FS.createDevice('/dev', 'stdin', Module['stdin']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdin');
+        }
+        if (Module['stdout']) {
+          FS.createDevice('/dev', 'stdout', null, Module['stdout']);
+        } else {
+          FS.symlink('/dev/tty', '/dev/stdout');
+        }
+        if (Module['stderr']) {
+          FS.createDevice('/dev', 'stderr', null, Module['stderr']);
+        } else {
+          FS.symlink('/dev/tty1', '/dev/stderr');
+        }
+
+        // open default streams for the stdin, stdout and stderr devices
+        var stdin = FS.open('/dev/stdin', 'r');
+        HEAP32[((_stdin)>>2)]=FS.getPtrForStream(stdin);
+        assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
+
+        var stdout = FS.open('/dev/stdout', 'w');
+        HEAP32[((_stdout)>>2)]=FS.getPtrForStream(stdout);
+        assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
+
+        var stderr = FS.open('/dev/stderr', 'w');
+        HEAP32[((_stderr)>>2)]=FS.getPtrForStream(stderr);
+        assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
+      },ensureErrnoError:function () {
+        if (FS.ErrnoError) return;
+        FS.ErrnoError = function ErrnoError(errno) {
+          this.errno = errno;
+          for (var key in ERRNO_CODES) {
+            if (ERRNO_CODES[key] === errno) {
+              this.code = key;
+              break;
+            }
+          }
+          this.message = ERRNO_MESSAGES[errno];
+        };
+        FS.ErrnoError.prototype = new Error();
+        FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+        // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
+        [ERRNO_CODES.ENOENT].forEach(function(code) {
+          FS.genericErrors[code] = new FS.ErrnoError(code);
+          FS.genericErrors[code].stack = '<generic error, no stack>';
+        });
+      },staticInit:function () {
+        FS.ensureErrnoError();
+
+        FS.nameTable = new Array(4096);
+
+        FS.mount(MEMFS, {}, '/');
+
+        FS.createDefaultDirectories();
+        FS.createDefaultDevices();
+      },init:function (input, output, error) {
+        assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+        FS.init.initialized = true;
+
+        FS.ensureErrnoError();
+
+        // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
+        Module['stdin'] = input || Module['stdin'];
+        Module['stdout'] = output || Module['stdout'];
+        Module['stderr'] = error || Module['stderr'];
+
+        FS.createStandardStreams();
+      },quit:function () {
+        FS.init.initialized = false;
+        for (var i = 0; i < FS.streams.length; i++) {
+          var stream = FS.streams[i];
+          if (!stream) {
+            continue;
+          }
+          FS.close(stream);
+        }
+      },getMode:function (canRead, canWrite) {
+        var mode = 0;
+        if (canRead) mode |= 292 | 73;
+        if (canWrite) mode |= 146;
+        return mode;
+      },joinPath:function (parts, forceRelative) {
+        var path = PATH.join.apply(null, parts);
+        if (forceRelative && path[0] == '/') path = path.substr(1);
+        return path;
+      },absolutePath:function (relative, base) {
+        return PATH.resolve(base, relative);
+      },standardizePath:function (path) {
+        return PATH.normalize(path);
+      },findObject:function (path, dontResolveLastLink) {
+        var ret = FS.analyzePath(path, dontResolveLastLink);
+        if (ret.exists) {
+          return ret.object;
+        } else {
+          ___setErrNo(ret.error);
+          return null;
+        }
+      },analyzePath:function (path, dontResolveLastLink) {
+        // operate from within the context of the symlink's target
+        try {
+          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          path = lookup.path;
+        } catch (e) {
+        }
+        var ret = {
+          isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
+          parentExists: false, parentPath: null, parentObject: null
+        };
+        try {
+          var lookup = FS.lookupPath(path, { parent: true });
+          ret.parentExists = true;
+          ret.parentPath = lookup.path;
+          ret.parentObject = lookup.node;
+          ret.name = PATH.basename(path);
+          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
+          ret.exists = true;
+          ret.path = lookup.path;
+          ret.object = lookup.node;
+          ret.name = lookup.node.name;
+          ret.isRoot = lookup.path === '/';
+        } catch (e) {
+          ret.error = e.errno;
+        };
+        return ret;
+      },createFolder:function (parent, name, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.mkdir(path, mode);
+      },createPath:function (parent, path, canRead, canWrite) {
+        parent = typeof parent === 'string' ? parent : FS.getPath(parent);
+        var parts = path.split('/').reverse();
+        while (parts.length) {
+          var part = parts.pop();
+          if (!part) continue;
+          var current = PATH.join2(parent, part);
+          try {
+            FS.mkdir(current);
+          } catch (e) {
+            // ignore EEXIST
+          }
+          parent = current;
+        }
+        return current;
+      },createFile:function (parent, name, properties, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(canRead, canWrite);
+        return FS.create(path, mode);
+      },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
+        var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
+        var mode = FS.getMode(canRead, canWrite);
+        var node = FS.create(path, mode);
+        if (data) {
+          if (typeof data === 'string') {
+            var arr = new Array(data.length);
+            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
+            data = arr;
+          }
+          // make sure we can write to the file
+          FS.chmod(node, mode | 146);
+          var stream = FS.open(node, 'w');
+          FS.write(stream, data, 0, data.length, 0, canOwn);
+          FS.close(stream);
+          FS.chmod(node, mode);
+        }
+        return node;
+      },createDevice:function (parent, name, input, output) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        var mode = FS.getMode(!!input, !!output);
+        if (!FS.createDevice.major) FS.createDevice.major = 64;
+        var dev = FS.makedev(FS.createDevice.major++, 0);
+        // Create a fake device that a set of stream ops to emulate
+        // the old behavior.
+        FS.registerDevice(dev, {
+          open: function(stream) {
+            stream.seekable = false;
+          },
+          close: function(stream) {
+            // flush any pending line data
+            if (output && output.buffer && output.buffer.length) {
+              output(10);
+            }
+          },
+          read: function(stream, buffer, offset, length, pos /* ignored */) {
+            var bytesRead = 0;
+            for (var i = 0; i < length; i++) {
+              var result;
+              try {
+                result = input();
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+              if (result === undefined && bytesRead === 0) {
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+              if (result === null || result === undefined) break;
+              bytesRead++;
+              buffer[offset+i] = result;
+            }
+            if (bytesRead) {
+              stream.node.timestamp = Date.now();
+            }
+            return bytesRead;
+          },
+          write: function(stream, buffer, offset, length, pos) {
+            for (var i = 0; i < length; i++) {
+              try {
+                output(buffer[offset+i]);
+              } catch (e) {
+                throw new FS.ErrnoError(ERRNO_CODES.EIO);
+              }
+            }
+            if (length) {
+              stream.node.timestamp = Date.now();
+            }
+            return i;
+          }
+        });
+        return FS.mkdev(path, mode, dev);
+      },createLink:function (parent, name, target, canRead, canWrite) {
+        var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+        return FS.symlink(target, path);
+      },forceLoadFile:function (obj) {
+        if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
+        var success = true;
+        if (typeof XMLHttpRequest !== 'undefined') {
+          throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
+        } else if (Module['read']) {
+          // Command-line.
+          try {
+            // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
+            //          read() will try to parse UTF8.
+            obj.contents = intArrayFromString(Module['read'](obj.url), true);
+          } catch (e) {
+            success = false;
+          }
+        } else {
+          throw new Error('Cannot load without read() or XMLHttpRequest.');
+        }
+        if (!success) ___setErrNo(ERRNO_CODES.EIO);
+        return success;
+      },createLazyFile:function (parent, name, url, canRead, canWrite) {
+        // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+        function LazyUint8Array() {
+          this.lengthKnown = false;
+          this.chunks = []; // Loaded chunks. Index is the chunk number
+        }
+        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+          if (idx > this.length-1 || idx < 0) {
+            return undefined;
+          }
+          var chunkOffset = idx % this.chunkSize;
+          var chunkNum = Math.floor(idx / this.chunkSize);
+          return this.getter(chunkNum)[chunkOffset];
+        }
+        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+          this.getter = getter;
+        }
+        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+            // Find length
+            var xhr = new XMLHttpRequest();
+            xhr.open('HEAD', url, false);
+            xhr.send(null);
+            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+            var datalength = Number(xhr.getResponseHeader("Content-length"));
+            var header;
+            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+            var chunkSize = 1024*1024; // Chunk size in bytes
+
+            if (!hasByteServing) chunkSize = datalength;
+
+            // Function to get a range from the remote URL.
+            var doXHR = (function(from, to) {
+              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+              var xhr = new XMLHttpRequest();
+              xhr.open('GET', url, false);
+              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+              // Some hints to the browser that we want binary data.
+              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+              if (xhr.overrideMimeType) {
+                xhr.overrideMimeType('text/plain; charset=x-user-defined');
+              }
+
+              xhr.send(null);
+              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+              if (xhr.response !== undefined) {
+                return new Uint8Array(xhr.response || []);
+              } else {
+                return intArrayFromString(xhr.responseText || '', true);
+              }
+            });
+            var lazyArray = this;
+            lazyArray.setDataGetter(function(chunkNum) {
+              var start = chunkNum * chunkSize;
+              var end = (chunkNum+1) * chunkSize - 1; // including this byte
+              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+                lazyArray.chunks[chunkNum] = doXHR(start, end);
+              }
+              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+              return lazyArray.chunks[chunkNum];
+            });
+
+            this._length = datalength;
+            this._chunkSize = chunkSize;
+            this.lengthKnown = true;
+        }
+        if (typeof XMLHttpRequest !== 'undefined') {
+          if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
+          var lazyArray = new LazyUint8Array();
+          Object.defineProperty(lazyArray, "length", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._length;
+              }
+          });
+          Object.defineProperty(lazyArray, "chunkSize", {
+              get: function() {
+                  if(!this.lengthKnown) {
+                      this.cacheLength();
+                  }
+                  return this._chunkSize;
+              }
+          });
+
+          var properties = { isDevice: false, contents: lazyArray };
+        } else {
+          var properties = { isDevice: false, url: url };
+        }
+
+        var node = FS.createFile(parent, name, properties, canRead, canWrite);
+        // This is a total hack, but I want to get this lazy file code out of the
+        // core of MEMFS. If we want to keep this lazy file concept I feel it should
+        // be its own thin LAZYFS proxying calls to MEMFS.
+        if (properties.contents) {
+          node.contents = properties.contents;
+        } else if (properties.url) {
+          node.contents = null;
+          node.url = properties.url;
+        }
+        // override each stream op with one that tries to force load the lazy file first
+        var stream_ops = {};
+        var keys = Object.keys(node.stream_ops);
+        keys.forEach(function(key) {
+          var fn = node.stream_ops[key];
+          stream_ops[key] = function forceLoadLazyFile() {
+            if (!FS.forceLoadFile(node)) {
+              throw new FS.ErrnoError(ERRNO_CODES.EIO);
+            }
+            return fn.apply(null, arguments);
+          };
+        });
+        // use a custom read function
+        stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
+          if (!FS.forceLoadFile(node)) {
+            throw new FS.ErrnoError(ERRNO_CODES.EIO);
+          }
+          var contents = stream.node.contents;
+          if (position >= contents.length)
+            return 0;
+          var size = Math.min(contents.length - position, length);
+          assert(size >= 0);
+          if (contents.slice) { // normal array
+            for (var i = 0; i < size; i++) {
+              buffer[offset + i] = contents[position + i];
+            }
+          } else {
+            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
+              buffer[offset + i] = contents.get(position + i);
+            }
+          }
+          return size;
+        };
+        node.stream_ops = stream_ops;
+        return node;
+      },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
+        Browser.init();
+        // TODO we should allow people to just pass in a complete filename instead
+        // of parent and name being that we just join them anyways
+        var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
+        function processData(byteArray) {
+          function finish(byteArray) {
+            if (!dontCreateFile) {
+              FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
+            }
+            if (onload) onload();
+            removeRunDependency('cp ' + fullname);
+          }
+          var handled = false;
+          Module['preloadPlugins'].forEach(function(plugin) {
+            if (handled) return;
+            if (plugin['canHandle'](fullname)) {
+              plugin['handle'](byteArray, fullname, finish, function() {
+                if (onerror) onerror();
+                removeRunDependency('cp ' + fullname);
+              });
+              handled = true;
+            }
+          });
+          if (!handled) finish(byteArray);
+        }
+        addRunDependency('cp ' + fullname);
+        if (typeof url == 'string') {
+          Browser.asyncLoad(url, function(byteArray) {
+            processData(byteArray);
+          }, onerror);
+        } else {
+          processData(url);
+        }
+      },indexedDB:function () {
+        return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+      },DB_NAME:function () {
+        return 'EM_FS_' + window.location.pathname;
+      },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
+          console.log('creating db');
+          var db = openRequest.result;
+          db.createObjectStore(FS.DB_STORE_NAME);
+        };
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
+            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      },loadFilesFromDB:function (paths, onload, onerror) {
+        onload = onload || function(){};
+        onerror = onerror || function(){};
+        var indexedDB = FS.indexedDB();
+        try {
+          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+        } catch (e) {
+          return onerror(e);
+        }
+        openRequest.onupgradeneeded = onerror; // no database to load from
+        openRequest.onsuccess = function openRequest_onsuccess() {
+          var db = openRequest.result;
+          try {
+            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+          } catch(e) {
+            onerror(e);
+            return;
+          }
+          var files = transaction.objectStore(FS.DB_STORE_NAME);
+          var ok = 0, fail = 0, total = paths.length;
+          function finish() {
+            if (fail == 0) onload(); else onerror();
+          }
+          paths.forEach(function(path) {
+            var getRequest = files.get(path);
+            getRequest.onsuccess = function getRequest_onsuccess() {
+              if (FS.analyzePath(path).exists) {
+                FS.unlink(path);
+              }
+              FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+              ok++;
+              if (ok + fail == total) finish();
+            };
+            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
+          });
+          transaction.onerror = onerror;
+        };
+        openRequest.onerror = onerror;
+      }};
+
+
+
+
+  function _mkport() { throw 'TODO' }var SOCKFS={mount:function (mount) {
+        return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
+      },createSocket:function (family, type, protocol) {
+        var streaming = type == 1;
+        if (protocol) {
+          assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
+        }
+
+        // create our internal socket structure
+        var sock = {
+          family: family,
+          type: type,
+          protocol: protocol,
+          server: null,
+          peers: {},
+          pending: [],
+          recv_queue: [],
+          sock_ops: SOCKFS.websocket_sock_ops
+        };
+
+        // create the filesystem node to store the socket structure
+        var name = SOCKFS.nextname();
+        var node = FS.createNode(SOCKFS.root, name, 49152, 0);
+        node.sock = sock;
+
+        // and the wrapping stream that enables library functions such
+        // as read and write to indirectly interact with the socket
+        var stream = FS.createStream({
+          path: name,
+          node: node,
+          flags: FS.modeStringToFlags('r+'),
+          seekable: false,
+          stream_ops: SOCKFS.stream_ops
+        });
+
+        // map the new stream to the socket structure (sockets have a 1:1
+        // relationship with a stream)
+        sock.stream = stream;
+
+        return sock;
+      },getSocket:function (fd) {
+        var stream = FS.getStream(fd);
+        if (!stream || !FS.isSocket(stream.node.mode)) {
+          return null;
+        }
+        return stream.node.sock;
+      },stream_ops:{poll:function (stream) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.poll(sock);
+        },ioctl:function (stream, request, varargs) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.ioctl(sock, request, varargs);
+        },read:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          var msg = sock.sock_ops.recvmsg(sock, length);
+          if (!msg) {
+            // socket is closed
+            return 0;
+          }
+          buffer.set(msg.buffer, offset);
+          return msg.buffer.length;
+        },write:function (stream, buffer, offset, length, position /* ignored */) {
+          var sock = stream.node.sock;
+          return sock.sock_ops.sendmsg(sock, buffer, offset, length);
+        },close:function (stream) {
+          var sock = stream.node.sock;
+          sock.sock_ops.close(sock);
+        }},nextname:function () {
+        if (!SOCKFS.nextname.current) {
+          SOCKFS.nextname.current = 0;
+        }
+        return 'socket[' + (SOCKFS.nextname.current++) + ']';
+      },websocket_sock_ops:{createPeer:function (sock, addr, port) {
+          var ws;
+
+          if (typeof addr === 'object') {
+            ws = addr;
+            addr = null;
+            port = null;
+          }
+
+          if (ws) {
+            // for sockets that've already connected (e.g. we're the server)
+            // we can inspect the _socket property for the address
+            if (ws._socket) {
+              addr = ws._socket.remoteAddress;
+              port = ws._socket.remotePort;
+            }
+            // if we're just now initializing a connection to the remote,
+            // inspect the url property
+            else {
+              var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
+              if (!result) {
+                throw new Error('WebSocket URL must be in the format ws(s)://address:port');
+              }
+              addr = result[1];
+              port = parseInt(result[2], 10);
+            }
+          } else {
+            // create the actual websocket object and connect
+            try {
+              // runtimeConfig gets set to true if WebSocket runtime configuration is available.
+              var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
+
+              // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#'
+              // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again.
+              var url = 'ws:#'.replace('#', '//');
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['url']) {
+                  url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
+                }
+              }
+
+              if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
+                url = url + addr + ':' + port;
+              }
+
+              // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
+              var subProtocols = 'binary'; // The default value is 'binary'
+
+              if (runtimeConfig) {
+                if ('string' === typeof Module['websocket']['subprotocol']) {
+                  subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
+                }
+              }
+
+              // The regex trims the string (removes spaces at the beginning and end, then splits the string by
+              // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
+              subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
+
+              // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
+              var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
+
+              // If node we use the ws library.
+              var WebSocket = ENVIRONMENT_IS_NODE ? require('ws') : window['WebSocket'];
+              ws = new WebSocket(url, opts);
+              ws.binaryType = 'arraybuffer';
+            } catch (e) {
+              throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
+            }
+          }
+
+
+          var peer = {
+            addr: addr,
+            port: port,
+            socket: ws,
+            dgram_send_queue: []
+          };
+
+          SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+          SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
+
+          // if this is a bound dgram socket, send the port number first to allow
+          // us to override the ephemeral port reported to us by remotePort on the
+          // remote end.
+          if (sock.type === 2 && typeof sock.sport !== 'undefined') {
+            peer.dgram_send_queue.push(new Uint8Array([
+                255, 255, 255, 255,
+                'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
+                ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
+            ]));
+          }
+
+          return peer;
+        },getPeer:function (sock, addr, port) {
+          return sock.peers[addr + ':' + port];
+        },addPeer:function (sock, peer) {
+          sock.peers[peer.addr + ':' + peer.port] = peer;
+        },removePeer:function (sock, peer) {
+          delete sock.peers[peer.addr + ':' + peer.port];
+        },handlePeerEvents:function (sock, peer) {
+          var first = true;
+
+          var handleOpen = function () {
+            try {
+              var queued = peer.dgram_send_queue.shift();
+              while (queued) {
+                peer.socket.send(queued);
+                queued = peer.dgram_send_queue.shift();
+              }
+            } catch (e) {
+              // not much we can do here in the way of proper error handling as we've already
+              // lied and said this data was sent. shut it down.
+              peer.socket.close();
+            }
+          };
+
+          function handleMessage(data) {
+            assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
+            data = new Uint8Array(data);  // make a typed array view on the array buffer
+
+
+            // if this is the port message, override the peer's port with it
+            var wasfirst = first;
+            first = false;
+            if (wasfirst &&
+                data.length === 10 &&
+                data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
+                data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
+              // update the peer's port and it's key in the peer map
+              var newport = ((data[8] << 8) | data[9]);
+              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+              peer.port = newport;
+              SOCKFS.websocket_sock_ops.addPeer(sock, peer);
+              return;
+            }
+
+            sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
+          };
+
+          if (ENVIRONMENT_IS_NODE) {
+            peer.socket.on('open', handleOpen);
+            peer.socket.on('message', function(data, flags) {
+              if (!flags.binary) {
+                return;
+              }
+              handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
+            });
+            peer.socket.on('error', function() {
+              // don't throw
+            });
+          } else {
+            peer.socket.onopen = handleOpen;
+            peer.socket.onmessage = function peer_socket_onmessage(event) {
+              handleMessage(event.data);
+            };
+          }
+        },poll:function (sock) {
+          if (sock.type === 1 && sock.server) {
+            // listen sockets should only say they're available for reading
+            // if there are pending clients.
+            return sock.pending.length ? (64 | 1) : 0;
+          }
+
+          var mask = 0;
+          var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
+            SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
+            null;
+
+          if (sock.recv_queue.length ||
+              !dest ||  // connection-less sockets are always ready to read
+              (dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
+            mask |= (64 | 1);
+          }
+
+          if (!dest ||  // connection-less sockets are always ready to write
+              (dest && dest.socket.readyState === dest.socket.OPEN)) {
+            mask |= 4;
+          }
+
+          if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
+              (dest && dest.socket.readyState === dest.socket.CLOSED)) {
+            mask |= 16;
+          }
+
+          return mask;
+        },ioctl:function (sock, request, arg) {
+          switch (request) {
+            case 21531:
+              var bytes = 0;
+              if (sock.recv_queue.length) {
+                bytes = sock.recv_queue[0].data.length;
+              }
+              HEAP32[((arg)>>2)]=bytes;
+              return 0;
+            default:
+              return ERRNO_CODES.EINVAL;
+          }
+        },close:function (sock) {
+          // if we've spawned a listen server, close it
+          if (sock.server) {
+            try {
+              sock.server.close();
+            } catch (e) {
+            }
+            sock.server = null;
+          }
+          // close any peer connections
+          var peers = Object.keys(sock.peers);
+          for (var i = 0; i < peers.length; i++) {
+            var peer = sock.peers[peers[i]];
+            try {
+              peer.socket.close();
+            } catch (e) {
+            }
+            SOCKFS.websocket_sock_ops.removePeer(sock, peer);
+          }
+          return 0;
+        },bind:function (sock, addr, port) {
+          if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
+          }
+          sock.saddr = addr;
+          sock.sport = port || _mkport();
+          // in order to emulate dgram sockets, we need to launch a listen server when
+          // binding on a connection-less socket
+          // note: this is only required on the server side
+          if (sock.type === 2) {
+            // close the existing server if it exists
+            if (sock.server) {
+              sock.server.close();
+              sock.server = null;
+            }
+            // swallow error operation not supported error that occurs when binding in the
+            // browser where this isn't supported
+            try {
+              sock.sock_ops.listen(sock, 0);
+            } catch (e) {
+              if (!(e instanceof FS.ErrnoError)) throw e;
+              if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
+            }
+          }
+        },connect:function (sock, addr, port) {
+          if (sock.server) {
+            throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP);
+          }
+
+          // TODO autobind
+          // if (!sock.addr && sock.type == 2) {
+          // }
+
+          // early out if we're already connected / in the middle of connecting
+          if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
+            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+            if (dest) {
+              if (dest.socket.readyState === dest.socket.CONNECTING) {
+                throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
+              } else {
+                throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
+              }
+            }
+          }
+
+          // add the socket to our peer list and set our
+          // destination address / port to match
+          var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+          sock.daddr = peer.addr;
+          sock.dport = peer.port;
+
+          // always "fail" in non-blocking mode
+          throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
+        },listen:function (sock, backlog) {
+          if (!ENVIRONMENT_IS_NODE) {
+            throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
+          }
+          if (sock.server) {
+             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
+          }
+          var WebSocketServer = require('ws').Server;
+          var host = sock.saddr;
+          sock.server = new WebSocketServer({
+            host: host,
+            port: sock.sport
+            // TODO support backlog
+          });
+
+          sock.server.on('connection', function(ws) {
+            if (sock.type === 1) {
+              var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
+
+              // create a peer on the new socket
+              var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
+              newsock.daddr = peer.addr;
+              newsock.dport = peer.port;
+
+              // push to queue for accept to pick up
+              sock.pending.push(newsock);
+            } else {
+              // create a peer on the listen socket so calling sendto
+              // with the listen socket and an address will resolve
+              // to the correct client
+              SOCKFS.websocket_sock_ops.createPeer(sock, ws);
+            }
+          });
+          sock.server.on('closed', function() {
+            sock.server = null;
+          });
+          sock.server.on('error', function() {
+            // don't throw
+          });
+        },accept:function (listensock) {
+          if (!listensock.server) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+          var newsock = listensock.pending.shift();
+          newsock.stream.flags = listensock.stream.flags;
+          return newsock;
+        },getname:function (sock, peer) {
+          var addr, port;
+          if (peer) {
+            if (sock.daddr === undefined || sock.dport === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            }
+            addr = sock.daddr;
+            port = sock.dport;
+          } else {
+            // TODO saddr and sport will be set for bind()'d UDP sockets, but what
+            // should we be returning for TCP sockets that've been connect()'d?
+            addr = sock.saddr || 0;
+            port = sock.sport || 0;
+          }
+          return { addr: addr, port: port };
+        },sendmsg:function (sock, buffer, offset, length, addr, port) {
+          if (sock.type === 2) {
+            // connection-less sockets will honor the message address,
+            // and otherwise fall back to the bound destination address
+            if (addr === undefined || port === undefined) {
+              addr = sock.daddr;
+              port = sock.dport;
+            }
+            // if there was no address to fall back to, error out
+            if (addr === undefined || port === undefined) {
+              throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
+            }
+          } else {
+            // connection-based sockets will only use the bound
+            addr = sock.daddr;
+            port = sock.dport;
+          }
+
+          // find the peer for the destination address
+          var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
+
+          // early out if not connected with a connection-based socket
+          if (sock.type === 1) {
+            if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+            } else if (dest.socket.readyState === dest.socket.CONNECTING) {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // create a copy of the incoming data to send, as the WebSocket API
+          // doesn't work entirely with an ArrayBufferView, it'll just send
+          // the entire underlying buffer
+          var data;
+          if (buffer instanceof Array || buffer instanceof ArrayBuffer) {
+            data = buffer.slice(offset, offset + length);
+          } else {  // ArrayBufferView
+            data = buffer.buffer.slice(buffer.byteOffset + offset, buffer.byteOffset + offset + length);
+          }
+
+          // if we're emulating a connection-less dgram socket and don't have
+          // a cached connection, queue the buffer to send upon connect and
+          // lie, saying the data was sent now.
+          if (sock.type === 2) {
+            if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
+              // if we're not connected, open a new connection
+              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
+              }
+              dest.dgram_send_queue.push(data);
+              return length;
+            }
+          }
+
+          try {
+            // send the actual data
+            dest.socket.send(data);
+            return length;
+          } catch (e) {
+            throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+          }
+        },recvmsg:function (sock, length) {
+          // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
+          if (sock.type === 1 && sock.server) {
+            // tcp servers should not be recv()'ing on the listen socket
+            throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+          }
+
+          var queued = sock.recv_queue.shift();
+          if (!queued) {
+            if (sock.type === 1) {
+              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
+
+              if (!dest) {
+                // if we have a destination address but are not connected, error out
+                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
+              }
+              else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
+                // return null if the socket has closed
+                return null;
+              }
+              else {
+                // else, our socket is in a valid state but truly has nothing available
+                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+              }
+            } else {
+              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
+            }
+          }
+
+          // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
+          // requeued TCP data it'll be an ArrayBufferView
+          var queuedLength = queued.data.byteLength || queued.data.length;
+          var queuedOffset = queued.data.byteOffset || 0;
+          var queuedBuffer = queued.data.buffer || queued.data;
+          var bytesRead = Math.min(length, queuedLength);
+          var res = {
+            buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
+            addr: queued.addr,
+            port: queued.port
+          };
+
+
+          // push back any unread data for TCP connections
+          if (sock.type === 1 && bytesRead < queuedLength) {
+            var bytesRemaining = queuedLength - bytesRead;
+            queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
+            sock.recv_queue.unshift(queued);
+          }
+
+          return res;
+        }}};function _send(fd, buf, len, flags) {
+      var sock = SOCKFS.getSocket(fd);
+      if (!sock) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      // TODO honor flags
+      return _write(fd, buf, len);
+    }
+
+  function _pwrite(fildes, buf, nbyte, offset) {
+      // ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte, offset);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }function _write(fildes, buf, nbyte) {
+      // ssize_t write(int fildes, const void *buf, size_t nbyte);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/write.html
+      var stream = FS.getStream(fildes);
+      if (!stream) {
+        ___setErrNo(ERRNO_CODES.EBADF);
+        return -1;
+      }
+
+
+      try {
+        var slab = HEAP8;
+        return FS.write(stream, slab, buf, nbyte);
+      } catch (e) {
+        FS.handleFSError(e);
+        return -1;
+      }
+    }
+
+  function _fileno(stream) {
+      // int fileno(FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
+      stream = FS.getStreamFromPtr(stream);
+      if (!stream) return -1;
+      return stream.fd;
+    }function _fwrite(ptr, size, nitems, stream) {
+      // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fwrite.html
+      var bytesToWrite = nitems * size;
+      if (bytesToWrite == 0) return 0;
+      var fd = _fileno(stream);
+      var bytesWritten = _write(fd, ptr, bytesToWrite);
+      if (bytesWritten == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return 0;
+      } else {
+        return Math.floor(bytesWritten / size);
+      }
+    }
+
+
+
+  Module["_strlen"] = _strlen;
+
+  function __reallyNegative(x) {
+      return x < 0 || (x === 0 && (1/x) === -Infinity);
+    }function __formatString(format, varargs) {
+      var textIndex = format;
+      var argIndex = 0;
+      function getNextArg(type) {
+        // NOTE: Explicitly ignoring type safety. Otherwise this fails:
+        //       int x = 4; printf("%c\n", (char)x);
+        var ret;
+        if (type === 'double') {
+          ret = HEAPF64[(((varargs)+(argIndex))>>3)];
+        } else if (type == 'i64') {
+          ret = [HEAP32[(((varargs)+(argIndex))>>2)],
+                 HEAP32[(((varargs)+(argIndex+4))>>2)]];
+
+        } else {
+          type = 'i32'; // varargs are always i32, i64, or double
+          ret = HEAP32[(((varargs)+(argIndex))>>2)];
+        }
+        argIndex += Runtime.getNativeFieldSize(type);
+        return ret;
+      }
+
+      var ret = [];
+      var curr, next, currArg;
+      while(1) {
+        var startTextIndex = textIndex;
+        curr = HEAP8[(textIndex)];
+        if (curr === 0) break;
+        next = HEAP8[((textIndex+1)|0)];
+        if (curr == 37) {
+          // Handle flags.
+          var flagAlwaysSigned = false;
+          var flagLeftAlign = false;
+          var flagAlternative = false;
+          var flagZeroPad = false;
+          var flagPadSign = false;
+          flagsLoop: while (1) {
+            switch (next) {
+              case 43:
+                flagAlwaysSigned = true;
+                break;
+              case 45:
+                flagLeftAlign = true;
+                break;
+              case 35:
+                flagAlternative = true;
+                break;
+              case 48:
+                if (flagZeroPad) {
+                  break flagsLoop;
+                } else {
+                  flagZeroPad = true;
+                  break;
+                }
+              case 32:
+                flagPadSign = true;
+                break;
+              default:
+                break flagsLoop;
+            }
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          }
+
+          // Handle width.
+          var width = 0;
+          if (next == 42) {
+            width = getNextArg('i32');
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+          } else {
+            while (next >= 48 && next <= 57) {
+              width = width * 10 + (next - 48);
+              textIndex++;
+              next = HEAP8[((textIndex+1)|0)];
+            }
+          }
+
+          // Handle precision.
+          var precisionSet = false, precision = -1;
+          if (next == 46) {
+            precision = 0;
+            precisionSet = true;
+            textIndex++;
+            next = HEAP8[((textIndex+1)|0)];
+            if (next == 42) {
+              precision = getNextArg('i32');
+              textIndex++;
+            } else {
+              while(1) {
+                var precisionChr = HEAP8[((textIndex+1)|0)];
+                if (precisionChr < 48 ||
+                    precisionChr > 57) break;
+                precision = precision * 10 + (precisionChr - 48);
+                textIndex++;
+              }
+            }
+            next = HEAP8[((textIndex+1)|0)];
+          }
+          if (precision < 0) {
+            precision = 6; // Standard default.
+            precisionSet = false;
+          }
+
+          // Handle integer sizes. WARNING: These assume a 32-bit architecture!
+          var argSize;
+          switch (String.fromCharCode(next)) {
+            case 'h':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 104) {
+                textIndex++;
+                argSize = 1; // char (actually i32 in varargs)
+              } else {
+                argSize = 2; // short (actually i32 in varargs)
+              }
+              break;
+            case 'l':
+              var nextNext = HEAP8[((textIndex+2)|0)];
+              if (nextNext == 108) {
+                textIndex++;
+                argSize = 8; // long long
+              } else {
+                argSize = 4; // long
+              }
+              break;
+            case 'L': // long long
+            case 'q': // int64_t
+            case 'j': // intmax_t
+              argSize = 8;
+              break;
+            case 'z': // size_t
+            case 't': // ptrdiff_t
+            case 'I': // signed ptrdiff_t or unsigned size_t
+              argSize = 4;
+              break;
+            default:
+              argSize = null;
+          }
+          if (argSize) textIndex++;
+          next = HEAP8[((textIndex+1)|0)];
+
+          // Handle type specifier.
+          switch (String.fromCharCode(next)) {
+            case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+              // Integer.
+              var signed = next == 100 || next == 105;
+              argSize = argSize || 4;
+              var currArg = getNextArg('i' + (argSize * 8));
+              var argText;
+              // Flatten i64-1 [low, high] into a (slightly rounded) double
+              if (argSize == 8) {
+                currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 117);
+              }
+              // Truncate to requested size.
+              if (argSize <= 4) {
+                var limit = Math.pow(256, argSize) - 1;
+                currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+              }
+              // Format the number.
+              var currAbsArg = Math.abs(currArg);
+              var prefix = '';
+              if (next == 100 || next == 105) {
+                argText = reSign(currArg, 8 * argSize, 1).toString(10);
+              } else if (next == 117) {
+                argText = unSign(currArg, 8 * argSize, 1).toString(10);
+                currArg = Math.abs(currArg);
+              } else if (next == 111) {
+                argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+              } else if (next == 120 || next == 88) {
+                prefix = (flagAlternative && currArg != 0) ? '0x' : '';
+                if (currArg < 0) {
+                  // Represent negative numbers in hex as 2's complement.
+                  currArg = -currArg;
+                  argText = (currAbsArg - 1).toString(16);
+                  var buffer = [];
+                  for (var i = 0; i < argText.length; i++) {
+                    buffer.push((0xF - parseInt(argText[i], 16)).toString(16));
+                  }
+                  argText = buffer.join('');
+                  while (argText.length < argSize * 2) argText = 'f' + argText;
+                } else {
+                  argText = currAbsArg.toString(16);
+                }
+                if (next == 88) {
+                  prefix = prefix.toUpperCase();
+                  argText = argText.toUpperCase();
+                }
+              } else if (next == 112) {
+                if (currAbsArg === 0) {
+                  argText = '(nil)';
+                } else {
+                  prefix = '0x';
+                  argText = currAbsArg.toString(16);
+                }
+              }
+              if (precisionSet) {
+                while (argText.length < precision) {
+                  argText = '0' + argText;
+                }
+              }
+
+              // Add sign if needed
+              if (currArg >= 0) {
+                if (flagAlwaysSigned) {
+                  prefix = '+' + prefix;
+                } else if (flagPadSign) {
+                  prefix = ' ' + prefix;
+                }
+              }
+
+              // Move sign to prefix so we zero-pad after the sign
+              if (argText.charAt(0) == '-') {
+                prefix = '-' + prefix;
+                argText = argText.substr(1);
+              }
+
+              // Add padding.
+              while (prefix.length + argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad) {
+                    argText = '0' + argText;
+                  } else {
+                    prefix = ' ' + prefix;
+                  }
+                }
+              }
+
+              // Insert the result into the buffer.
+              argText = prefix + argText;
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': {
+              // Float.
+              var currArg = getNextArg('double');
+              var argText;
+              if (isNaN(currArg)) {
+                argText = 'nan';
+                flagZeroPad = false;
+              } else if (!isFinite(currArg)) {
+                argText = (currArg < 0 ? '-' : '') + 'inf';
+                flagZeroPad = false;
+              } else {
+                var isGeneral = false;
+                var effectivePrecision = Math.min(precision, 20);
+
+                // Convert g/G to f/F or e/E, as per:
+                // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html
+                if (next == 103 || next == 71) {
+                  isGeneral = true;
+                  precision = precision || 1;
+                  var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10);
+                  if (precision > exponent && exponent >= -4) {
+                    next = ((next == 103) ? 'f' : 'F').charCodeAt(0);
+                    precision -= exponent + 1;
+                  } else {
+                    next = ((next == 103) ? 'e' : 'E').charCodeAt(0);
+                    precision--;
+                  }
+                  effectivePrecision = Math.min(precision, 20);
+                }
+
+                if (next == 101 || next == 69) {
+                  argText = currArg.toExponential(effectivePrecision);
+                  // Make sure the exponent has at least 2 digits.
+                  if (/[eE][-+]\d$/.test(argText)) {
+                    argText = argText.slice(0, -1) + '0' + argText.slice(-1);
+                  }
+                } else if (next == 102 || next == 70) {
+                  argText = currArg.toFixed(effectivePrecision);
+                  if (currArg === 0 && __reallyNegative(currArg)) {
+                    argText = '-' + argText;
+                  }
+                }
+
+                var parts = argText.split('e');
+                if (isGeneral && !flagAlternative) {
+                  // Discard trailing zeros and periods.
+                  while (parts[0].length > 1 && parts[0].indexOf('.') != -1 &&
+                         (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) {
+                    parts[0] = parts[0].slice(0, -1);
+                  }
+                } else {
+                  // Make sure we have a period in alternative mode.
+                  if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.';
+                  // Zero pad until required precision.
+                  while (precision > effectivePrecision++) parts[0] += '0';
+                }
+                argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : '');
+
+                // Capitalize 'E' if needed.
+                if (next == 69) argText = argText.toUpperCase();
+
+                // Add sign.
+                if (currArg >= 0) {
+                  if (flagAlwaysSigned) {
+                    argText = '+' + argText;
+                  } else if (flagPadSign) {
+                    argText = ' ' + argText;
+                  }
+                }
+              }
+
+              // Add padding.
+              while (argText.length < width) {
+                if (flagLeftAlign) {
+                  argText += ' ';
+                } else {
+                  if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) {
+                    argText = argText[0] + '0' + argText.slice(1);
+                  } else {
+                    argText = (flagZeroPad ? '0' : ' ') + argText;
+                  }
+                }
+              }
+
+              // Adjust case.
+              if (next < 97) argText = argText.toUpperCase();
+
+              // Insert the result into the buffer.
+              argText.split('').forEach(function(chr) {
+                ret.push(chr.charCodeAt(0));
+              });
+              break;
+            }
+            case 's': {
+              // String.
+              var arg = getNextArg('i8*');
+              var argLength = arg ? _strlen(arg) : '(null)'.length;
+              if (precisionSet) argLength = Math.min(argLength, precision);
+              if (!flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              if (arg) {
+                for (var i = 0; i < argLength; i++) {
+                  ret.push(HEAPU8[((arg++)|0)]);
+                }
+              } else {
+                ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true));
+              }
+              if (flagLeftAlign) {
+                while (argLength < width--) {
+                  ret.push(32);
+                }
+              }
+              break;
+            }
+            case 'c': {
+              // Character.
+              if (flagLeftAlign) ret.push(getNextArg('i8'));
+              while (--width > 0) {
+                ret.push(32);
+              }
+              if (!flagLeftAlign) ret.push(getNextArg('i8'));
+              break;
+            }
+            case 'n': {
+              // Write the length written so far to the next parameter.
+              var ptr = getNextArg('i32*');
+              HEAP32[((ptr)>>2)]=ret.length;
+              break;
+            }
+            case '%': {
+              // Literal percent sign.
+              ret.push(curr);
+              break;
+            }
+            default: {
+              // Unknown specifiers remain untouched.
+              for (var i = startTextIndex; i < textIndex + 2; i++) {
+                ret.push(HEAP8[(i)]);
+              }
+            }
+          }
+          textIndex += 2;
+          // TODO: Support a/A (hex float) and m (last error) specifiers.
+          // TODO: Support %1${specifier} for arg selection.
+        } else {
+          ret.push(curr);
+          textIndex += 1;
+        }
+      }
+      return ret;
+    }function _fprintf(stream, format, varargs) {
+      // int fprintf(FILE *restrict stream, const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var result = __formatString(format, varargs);
+      var stack = Runtime.stackSave();
+      var ret = _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream);
+      Runtime.stackRestore(stack);
+      return ret;
+    }function _printf(format, varargs) {
+      // int printf(const char *restrict format, ...);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
+      var stdout = HEAP32[((_stdout)>>2)];
+      return _fprintf(stdout, format, varargs);
+    }
+
+
+  function _fputs(s, stream) {
+      // int fputs(const char *restrict s, FILE *restrict stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputs.html
+      var fd = _fileno(stream);
+      return _write(fd, s, _strlen(s));
+    }
+
+  function _fputc(c, stream) {
+      // int fputc(int c, FILE *stream);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
+      var chr = unSign(c & 0xFF);
+      HEAP8[((_fputc.ret)|0)]=chr;
+      var fd = _fileno(stream);
+      var ret = _write(fd, _fputc.ret, 1);
+      if (ret == -1) {
+        var streamObj = FS.getStreamFromPtr(stream);
+        if (streamObj) streamObj.error = true;
+        return -1;
+      } else {
+        return chr;
+      }
+    }function _puts(s) {
+      // int puts(const char *s);
+      // http://pubs.opengroup.org/onlinepubs/000095399/functions/puts.html
+      // NOTE: puts() always writes an extra newline.
+      var stdout = HEAP32[((_stdout)>>2)];
+      var ret = _fputs(s, stdout);
+      if (ret < 0) {
+        return ret;
+      } else {
+        var newlineRet = _fputc(10, stdout);
+        return (newlineRet < 0) ? -1 : ret + 1;
+      }
+    }
+
+  function _sysconf(name) {
+      // long sysconf(int name);
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
+      switch(name) {
+        case 30: return PAGE_SIZE;
+        case 132:
+        case 133:
+        case 12:
+        case 137:
+        case 138:
+        case 15:
+        case 235:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 149:
+        case 13:
+        case 10:
+        case 236:
+        case 153:
+        case 9:
+        case 21:
+        case 22:
+        case 159:
+        case 154:
+        case 14:
+        case 77:
+        case 78:
+        case 139:
+        case 80:
+        case 81:
+        case 79:
+        case 82:
+        case 68:
+        case 67:
+        case 164:
+        case 11:
+        case 29:
+        case 47:
+        case 48:
+        case 95:
+        case 52:
+        case 51:
+        case 46:
+          return 200809;
+        case 27:
+        case 246:
+        case 127:
+        case 128:
+        case 23:
+        case 24:
+        case 160:
+        case 161:
+        case 181:
+        case 182:
+        case 242:
+        case 183:
+        case 184:
+        case 243:
+        case 244:
+        case 245:
+        case 165:
+        case 178:
+        case 179:
+        case 49:
+        case 50:
+        case 168:
+        case 169:
+        case 175:
+        case 170:
+        case 171:
+        case 172:
+        case 97:
+        case 76:
+        case 32:
+        case 173:
+        case 35:
+          return -1;
+        case 176:
+        case 177:
+        case 7:
+        case 155:
+        case 8:
+        case 157:
+        case 125:
+        case 126:
+        case 92:
+        case 93:
+        case 129:
+        case 130:
+        case 131:
+        case 94:
+        case 91:
+          return 1;
+        case 74:
+        case 60:
+        case 69:
+        case 70:
+        case 4:
+          return 1024;
+        case 31:
+        case 42:
+        case 72:
+          return 32;
+        case 87:
+        case 26:
+        case 33:
+          return 2147483647;
+        case 34:
+        case 1:
+          return 47839;
+        case 38:
+        case 36:
+          return 99;
+        case 43:
+        case 37:
+          return 2048;
+        case 0: return 2097152;
+        case 3: return 65536;
+        case 28: return 32768;
+        case 44: return 32767;
+        case 75: return 16384;
+        case 39: return 1000;
+        case 89: return 700;
+        case 71: return 256;
+        case 40: return 255;
+        case 2: return 100;
+        case 180: return 64;
+        case 25: return 20;
+        case 5: return 16;
+        case 6: return 6;
+        case 73: return 4;
+        case 84: return 1;
+      }
+      ___setErrNo(ERRNO_CODES.EINVAL);
+      return -1;
+    }
+
+
+  Module["_memset"] = _memset;
+
+  function ___errno_location() {
+      return ___errno_state;
+    }
+
+  function _abort() {
+      Module['abort']();
+    }
+
+  var Browser={mainLoop:{scheduler:null,method:"",shouldPause:false,paused:false,queue:[],pause:function () {
+          Browser.mainLoop.shouldPause = true;
+        },resume:function () {
+          if (Browser.mainLoop.paused) {
+            Browser.mainLoop.paused = false;
+            Browser.mainLoop.scheduler();
+          }
+          Browser.mainLoop.shouldPause = false;
+        },updateStatus:function () {
+          if (Module['setStatus']) {
+            var message = Module['statusMessage'] || 'Please wait...';
+            var remaining = Browser.mainLoop.remainingBlockers;
+            var expected = Browser.mainLoop.expectedBlockers;
+            if (remaining) {
+              if (remaining < expected) {
+                Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
+              } else {
+                Module['setStatus'](message);
+              }
+            } else {
+              Module['setStatus']('');
+            }
+          }
+        }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
+        if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
+
+        if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
+        Browser.initted = true;
+
+        try {
+          new Blob();
+          Browser.hasBlobConstructor = true;
+        } catch(e) {
+          Browser.hasBlobConstructor = false;
+          console.log("warning: no blob constructor, cannot create blobs with mimetypes");
+        }
+        Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
+        Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
+        if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
+          console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
+          Module.noImageDecoding = true;
+        }
+
+        // Support for plugins that can process preloaded files. You can add more of these to
+        // your app by creating and appending to Module.preloadPlugins.
+        //
+        // Each plugin is asked if it can handle a file based on the file's name. If it can,
+        // it is given the file's raw data. When it is done, it calls a callback with the file's
+        // (possibly modified) data. For example, a plugin might decompress a file, or it
+        // might create some side data structure for use later (like an Image element, etc.).
+
+        var imagePlugin = {};
+        imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
+          return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
+        };
+        imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
+          var b = null;
+          if (Browser.hasBlobConstructor) {
+            try {
+              b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+              if (b.size !== byteArray.length) { // Safari bug #118630
+                // Safari's Blob can only take an ArrayBuffer
+                b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
+              }
+            } catch(e) {
+              Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
+            }
+          }
+          if (!b) {
+            var bb = new Browser.BlobBuilder();
+            bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
+            b = bb.getBlob();
+          }
+          var url = Browser.URLObject.createObjectURL(b);
+          var img = new Image();
+          img.onload = function img_onload() {
+            assert(img.complete, 'Image ' + name + ' could not be decoded');
+            var canvas = document.createElement('canvas');
+            canvas.width = img.width;
+            canvas.height = img.height;
+            var ctx = canvas.getContext('2d');
+            ctx.drawImage(img, 0, 0);
+            Module["preloadedImages"][name] = canvas;
+            Browser.URLObject.revokeObjectURL(url);
+            if (onload) onload(byteArray);
+          };
+          img.onerror = function img_onerror(event) {
+            console.log('Image ' + url + ' could not be decoded');
+            if (onerror) onerror();
+          };
+          img.src = url;
+        };
+        Module['preloadPlugins'].push(imagePlugin);
+
+        var audioPlugin = {};
+        audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
+          return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
+        };
+        audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
+          var done = false;
+          function finish(audio) {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = audio;
+            if (onload) onload(byteArray);
+          }
+          function fail() {
+            if (done) return;
+            done = true;
+            Module["preloadedAudios"][name] = new Audio(); // empty shim
+            if (onerror) onerror();
+          }
+          if (Browser.hasBlobConstructor) {
+            try {
+              var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
+            } catch(e) {
+              return fail();
+            }
+            var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
+            var audio = new Audio();
+            audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
+            audio.onerror = function audio_onerror(event) {
+              if (done) return;
+              console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
+              function encode64(data) {
+                var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+                var PAD = '=';
+                var ret = '';
+                var leftchar = 0;
+                var leftbits = 0;
+                for (var i = 0; i < data.length; i++) {
+                  leftchar = (leftchar << 8) | data[i];
+                  leftbits += 8;
+                  while (leftbits >= 6) {
+                    var curr = (leftchar >> (leftbits-6)) & 0x3f;
+                    leftbits -= 6;
+                    ret += BASE[curr];
+                  }
+                }
+                if (leftbits == 2) {
+                  ret += BASE[(leftchar&3) << 4];
+                  ret += PAD + PAD;
+                } else if (leftbits == 4) {
+                  ret += BASE[(leftchar&0xf) << 2];
+                  ret += PAD;
+                }
+                return ret;
+              }
+              audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
+              finish(audio); // we don't wait for confirmation this worked - but it's worth trying
+            };
+            audio.src = url;
+            // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
+            Browser.safeSetTimeout(function() {
+              finish(audio); // try to use it even though it is not necessarily ready to play
+            }, 10000);
+          } else {
+            return fail();
+          }
+        };
+        Module['preloadPlugins'].push(audioPlugin);
+
+        // Canvas event setup
+
+        var canvas = Module['canvas'];
+
+        // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+        // Module['forcedAspectRatio'] = 4 / 3;
+
+        canvas.requestPointerLock = canvas['requestPointerLock'] ||
+                                    canvas['mozRequestPointerLock'] ||
+                                    canvas['webkitRequestPointerLock'] ||
+                                    canvas['msRequestPointerLock'] ||
+                                    function(){};
+        canvas.exitPointerLock = document['exitPointerLock'] ||
+                                 document['mozExitPointerLock'] ||
+                                 document['webkitExitPointerLock'] ||
+                                 document['msExitPointerLock'] ||
+                                 function(){}; // no-op if function does not exist
+        canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
+
+        function pointerLockChange() {
+          Browser.pointerLock = document['pointerLockElement'] === canvas ||
+                                document['mozPointerLockElement'] === canvas ||
+                                document['webkitPointerLockElement'] === canvas ||
+                                document['msPointerLockElement'] === canvas;
+        }
+
+        document.addEventListener('pointerlockchange', pointerLockChange, false);
+        document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+        document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+        document.addEventListener('mspointerlockchange', pointerLockChange, false);
+
+        if (Module['elementPointerLock']) {
+          canvas.addEventListener("click", function(ev) {
+            if (!Browser.pointerLock && canvas.requestPointerLock) {
+              canvas.requestPointerLock();
+              ev.preventDefault();
+            }
+          }, false);
+        }
+      },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
+        var ctx;
+        var errorInfo = '?';
+        function onContextCreationError(event) {
+          errorInfo = event.statusMessage || errorInfo;
+        }
+        try {
+          if (useWebGL) {
+            var contextAttributes = {
+              antialias: false,
+              alpha: false
+            };
+
+            if (webGLContextAttributes) {
+              for (var attribute in webGLContextAttributes) {
+                contextAttributes[attribute] = webGLContextAttributes[attribute];
+              }
+            }
+
+
+            canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
+            try {
+              ['experimental-webgl', 'webgl'].some(function(webglId) {
+                return ctx = canvas.getContext(webglId, contextAttributes);
+              });
+            } finally {
+              canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
+            }
+          } else {
+            ctx = canvas.getContext('2d');
+          }
+          if (!ctx) throw ':(';
+        } catch (e) {
+          Module.print('Could not create canvas: ' + [errorInfo, e]);
+          return null;
+        }
+        if (useWebGL) {
+          // Set the background of the WebGL canvas to black
+          canvas.style.backgroundColor = "black";
+
+          // Warn on context loss
+          canvas.addEventListener('webglcontextlost', function(event) {
+            alert('WebGL context lost. You will need to reload the page.');
+          }, false);
+        }
+        if (setInModule) {
+          GLctx = Module.ctx = ctx;
+          Module.useWebGL = useWebGL;
+          Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
+          Browser.init();
+        }
+        return ctx;
+      },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
+        Browser.lockPointer = lockPointer;
+        Browser.resizeCanvas = resizeCanvas;
+        if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
+        if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
+
+        var canvas = Module['canvas'];
+        function fullScreenChange() {
+          Browser.isFullScreen = false;
+          var canvasContainer = canvas.parentNode;
+          if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+               document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+               document['fullScreenElement'] || document['fullscreenElement'] ||
+               document['msFullScreenElement'] || document['msFullscreenElement'] ||
+               document['webkitCurrentFullScreenElement']) === canvasContainer) {
+            canvas.cancelFullScreen = document['cancelFullScreen'] ||
+                                      document['mozCancelFullScreen'] ||
+                                      document['webkitCancelFullScreen'] ||
+                                      document['msExitFullscreen'] ||
+                                      document['exitFullscreen'] ||
+                                      function() {};
+            canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
+            if (Browser.lockPointer) canvas.requestPointerLock();
+            Browser.isFullScreen = true;
+            if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
+          } else {
+
+            // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+            canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+            canvasContainer.parentNode.removeChild(canvasContainer);
+
+            if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
+          }
+          if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+          Browser.updateCanvasDimensions(canvas);
+        }
+
+        if (!Browser.fullScreenHandlersInstalled) {
+          Browser.fullScreenHandlersInstalled = true;
+          document.addEventListener('fullscreenchange', fullScreenChange, false);
+          document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+          document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+          document.addEventListener('MSFullscreenChange', fullScreenChange, false);
+        }
+
+        // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+        var canvasContainer = document.createElement("div");
+        canvas.parentNode.insertBefore(canvasContainer, canvas);
+        canvasContainer.appendChild(canvas);
+
+        // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+        canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+                                            canvasContainer['mozRequestFullScreen'] ||
+                                            canvasContainer['msRequestFullscreen'] ||
+                                           (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+        canvasContainer.requestFullScreen();
+      },requestAnimationFrame:function requestAnimationFrame(func) {
+        if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
+          setTimeout(func, 1000/60);
+        } else {
+          if (!window.requestAnimationFrame) {
+            window.requestAnimationFrame = window['requestAnimationFrame'] ||
+                                           window['mozRequestAnimationFrame'] ||
+                                           window['webkitRequestAnimationFrame'] ||
+                                           window['msRequestAnimationFrame'] ||
+                                           window['oRequestAnimationFrame'] ||
+                                           window['setTimeout'];
+          }
+          window.requestAnimationFrame(func);
+        }
+      },safeCallback:function (func) {
+        return function() {
+          if (!ABORT) return func.apply(null, arguments);
+        };
+      },safeRequestAnimationFrame:function (func) {
+        return Browser.requestAnimationFrame(function() {
+          if (!ABORT) func();
+        });
+      },safeSetTimeout:function (func, timeout) {
+        return setTimeout(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },safeSetInterval:function (func, timeout) {
+        return setInterval(function() {
+          if (!ABORT) func();
+        }, timeout);
+      },getMimetype:function (name) {
+        return {
+          'jpg': 'image/jpeg',
+          'jpeg': 'image/jpeg',
+          'png': 'image/png',
+          'bmp': 'image/bmp',
+          'ogg': 'audio/ogg',
+          'wav': 'audio/wav',
+          'mp3': 'audio/mpeg'
+        }[name.substr(name.lastIndexOf('.')+1)];
+      },getUserMedia:function (func) {
+        if(!window.getUserMedia) {
+          window.getUserMedia = navigator['getUserMedia'] ||
+                                navigator['mozGetUserMedia'];
+        }
+        window.getUserMedia(func);
+      },getMovementX:function (event) {
+        return event['movementX'] ||
+               event['mozMovementX'] ||
+               event['webkitMovementX'] ||
+               0;
+      },getMovementY:function (event) {
+        return event['movementY'] ||
+               event['mozMovementY'] ||
+               event['webkitMovementY'] ||
+               0;
+      },getMouseWheelDelta:function (event) {
+        return Math.max(-1, Math.min(1, event.type === 'DOMMouseScroll' ? event.detail : -event.wheelDelta));
+      },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
+        if (Browser.pointerLock) {
+          // When the pointer is locked, calculate the coordinates
+          // based on the movement of the mouse.
+          // Workaround for Firefox bug 764498
+          if (event.type != 'mousemove' &&
+              ('mozMovementX' in event)) {
+            Browser.mouseMovementX = Browser.mouseMovementY = 0;
+          } else {
+            Browser.mouseMovementX = Browser.getMovementX(event);
+            Browser.mouseMovementY = Browser.getMovementY(event);
+          }
+
+          // check if SDL is available
+          if (typeof SDL != "undefined") {
+    Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
+    Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
+          } else {
+    // just add the mouse delta to the current absolut mouse position
+    // FIXME: ideally this should be clamped against the canvas size and zero
+    Browser.mouseX += Browser.mouseMovementX;
+    Browser.mouseY += Browser.mouseMovementY;
+          }
+        } else {
+          // Otherwise, calculate the movement based on the changes
+          // in the coordinates.
+          var rect = Module["canvas"].getBoundingClientRect();
+          var x, y;
+
+          // Neither .scrollX or .pageXOffset are defined in a spec, but
+          // we prefer .scrollX because it is currently in a spec draft.
+          // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
+          var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
+          var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
+          if (event.type == 'touchstart' ||
+              event.type == 'touchend' ||
+              event.type == 'touchmove') {
+            var t = event.touches.item(0);
+            if (t) {
+              x = t.pageX - (scrollX + rect.left);
+              y = t.pageY - (scrollY + rect.top);
+            } else {
+              return;
+            }
+          } else {
+            x = event.pageX - (scrollX + rect.left);
+            y = event.pageY - (scrollY + rect.top);
+          }
+
+          // the canvas might be CSS-scaled compared to its backbuffer;
+          // SDL-using content will want mouse coordinates in terms
+          // of backbuffer units.
+          var cw = Module["canvas"].width;
+          var ch = Module["canvas"].height;
+          x = x * (cw / rect.width);
+          y = y * (ch / rect.height);
+
+          Browser.mouseMovementX = x - Browser.mouseX;
+          Browser.mouseMovementY = y - Browser.mouseY;
+          Browser.mouseX = x;
+          Browser.mouseY = y;
+        }
+      },xhrLoad:function (url, onload, onerror) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onload = function xhr_onload() {
+          if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+            onload(xhr.response);
+          } else {
+            onerror();
+          }
+        };
+        xhr.onerror = onerror;
+        xhr.send(null);
+      },asyncLoad:function (url, onload, onerror, noRunDep) {
+        Browser.xhrLoad(url, function(arrayBuffer) {
+          assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+          onload(new Uint8Array(arrayBuffer));
+          if (!noRunDep) removeRunDependency('al ' + url);
+        }, function(event) {
+          if (onerror) {
+            onerror();
+          } else {
+            throw 'Loading data file "' + url + '" failed.';
+          }
+        });
+        if (!noRunDep) addRunDependency('al ' + url);
+      },resizeListeners:[],updateResizeListeners:function () {
+        var canvas = Module['canvas'];
+        Browser.resizeListeners.forEach(function(listener) {
+          listener(canvas.width, canvas.height);
+        });
+      },setCanvasSize:function (width, height, noUpdates) {
+        var canvas = Module['canvas'];
+        Browser.updateCanvasDimensions(canvas, width, height);
+        if (!noUpdates) Browser.updateResizeListeners();
+      },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },setWindowedCanvasSize:function () {
+        // check if SDL is available
+        if (typeof SDL != "undefined") {
+    var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
+    flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
+    HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
+        }
+        Browser.updateResizeListeners();
+      },updateCanvasDimensions:function (canvas, wNative, hNative) {
+        if (wNative && hNative) {
+          canvas.widthNative = wNative;
+          canvas.heightNative = hNative;
+        } else {
+          wNative = canvas.widthNative;
+          hNative = canvas.heightNative;
+        }
+        var w = wNative;
+        var h = hNative;
+        if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+          if (w/h < Module['forcedAspectRatio']) {
+            w = Math.round(h * Module['forcedAspectRatio']);
+          } else {
+            h = Math.round(w / Module['forcedAspectRatio']);
+          }
+        }
+        if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+             document['fullScreenElement'] || document['fullscreenElement'] ||
+             document['msFullScreenElement'] || document['msFullscreenElement'] ||
+             document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+           var factor = Math.min(screen.width / w, screen.height / h);
+           w = Math.round(w * factor);
+           h = Math.round(h * factor);
+        }
+        if (Browser.resizeCanvas) {
+          if (canvas.width  != w) canvas.width  = w;
+          if (canvas.height != h) canvas.height = h;
+          if (typeof canvas.style != 'undefined') {
+            canvas.style.removeProperty( "width");
+            canvas.style.removeProperty("height");
+          }
+        } else {
+          if (canvas.width  != wNative) canvas.width  = wNative;
+          if (canvas.height != hNative) canvas.height = hNative;
+          if (typeof canvas.style != 'undefined') {
+            if (w != wNative || h != hNative) {
+              canvas.style.setProperty( "width", w + "px", "important");
+              canvas.style.setProperty("height", h + "px", "important");
+            } else {
+              canvas.style.removeProperty( "width");
+              canvas.style.removeProperty("height");
+            }
+          }
+        }
+      }};
+
+  function _sbrk(bytes) {
+      // Implement a Linux-like 'memory area' for our 'process'.
+      // Changes the size of the memory area by |bytes|; returns the
+      // address of the previous top ('break') of the memory area
+      // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
+      var self = _sbrk;
+      if (!self.called) {
+        DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
+        self.called = true;
+        assert(Runtime.dynamicAlloc);
+        self.alloc = Runtime.dynamicAlloc;
+        Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
+      }
+      var ret = DYNAMICTOP;
+      if (bytes != 0) self.alloc(bytes);
+      return ret;  // Previous break location.
+    }
+
+  function ___assert_fail(condition, filename, line, func) {
+      ABORT = true;
+      throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace();
+    }
+
+  function _time(ptr) {
+      var ret = Math.floor(Date.now()/1000);
+      if (ptr) {
+        HEAP32[((ptr)>>2)]=ret;
+      }
+      return ret;
+    }
+
+  function _llvm_bswap_i32(x) {
+      return ((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24);
+    }
+
+
+
+  function _emscripten_memcpy_big(dest, src, num) {
+      HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
+      return dest;
+    }
+  Module["_memcpy"] = _memcpy;
+FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
+___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
+__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
+if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
+__ATINIT__.push({ func: function() { SOCKFS.root = FS.mount(SOCKFS, {}, null); } });
+_fputc.ret = allocate([0], "i8", ALLOC_STATIC);
+Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
+  Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
+  Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
+  Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
+  Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
+  Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
+STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
+
+staticSealed = true; // seal the static portion of memory
+
+STACK_MAX = STACK_BASE + 5242880;
+
+DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
+
+assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
+
+
+var Math_min = Math.min;
+function invoke_iiii(index,a1,a2,a3) {
+  try {
+    return Module["dynCall_iiii"](index,a1,a2,a3);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_vii(index,a1,a2) {
+  try {
+    Module["dynCall_vii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function invoke_iii(index,a1,a2) {
+  try {
+    return Module["dynCall_iii"](index,a1,a2);
+  } catch(e) {
+    if (typeof e !== 'number' && e !== 'longjmp') throw e;
+    asm["setThrew"](1, 0);
+  }
+}
+
+function asmPrintInt(x, y) {
+  Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+function asmPrintFloat(x, y) {
+  Module.print('float ' + x + ',' + y);// + ' ' + new Error().stack);
+}
+// EMSCRIPTEN_START_ASM
+var asm = (function(global, env, buffer) {
+  'use asm';
+  var HEAP8 = new global.Int8Array(buffer);
+  var HEAP16 = new global.Int16Array(buffer);
+  var HEAP32 = new global.Int32Array(buffer);
+  var HEAPU8 = new global.Uint8Array(buffer);
+  var HEAPU16 = new global.Uint16Array(buffer);
+  var HEAPU32 = new global.Uint32Array(buffer);
+  var HEAPF32 = new global.Float32Array(buffer);
+  var HEAPF64 = new global.Float64Array(buffer);
+
+  var STACKTOP=env.STACKTOP|0;
+  var STACK_MAX=env.STACK_MAX|0;
+  var tempDoublePtr=env.tempDoublePtr|0;
+  var ABORT=env.ABORT|0;
+
+  var __THREW__ = 0;
+  var threwValue = 0;
+  var setjmpId = 0;
+  var undef = 0;
+  var nan = +env.NaN, inf = +env.Infinity;
+  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
+
+  var tempRet0 = 0;
+  var tempRet1 = 0;
+  var tempRet2 = 0;
+  var tempRet3 = 0;
+  var tempRet4 = 0;
+  var tempRet5 = 0;
+  var tempRet6 = 0;
+  var tempRet7 = 0;
+  var tempRet8 = 0;
+  var tempRet9 = 0;
+  var Math_floor=global.Math.floor;
+  var Math_abs=global.Math.abs;
+  var Math_sqrt=global.Math.sqrt;
+  var Math_pow=global.Math.pow;
+  var Math_cos=global.Math.cos;
+  var Math_sin=global.Math.sin;
+  var Math_tan=global.Math.tan;
+  var Math_acos=global.Math.acos;
+  var Math_asin=global.Math.asin;
+  var Math_atan=global.Math.atan;
+  var Math_atan2=global.Math.atan2;
+  var Math_exp=global.Math.exp;
+  var Math_log=global.Math.log;
+  var Math_ceil=global.Math.ceil;
+  var Math_imul=global.Math.imul;
+  var abort=env.abort;
+  var assert=env.assert;
+  var asmPrintInt=env.asmPrintInt;
+  var asmPrintFloat=env.asmPrintFloat;
+  var Math_min=env.min;
+  var invoke_iiii=env.invoke_iiii;
+  var invoke_vii=env.invoke_vii;
+  var invoke_iii=env.invoke_iii;
+  var _send=env._send;
+  var ___setErrNo=env.___setErrNo;
+  var ___assert_fail=env.___assert_fail;
+  var _fflush=env._fflush;
+  var _pwrite=env._pwrite;
+  var __reallyNegative=env.__reallyNegative;
+  var _sbrk=env._sbrk;
+  var ___errno_location=env.___errno_location;
+  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
+  var _fileno=env._fileno;
+  var _sysconf=env._sysconf;
+  var _puts=env._puts;
+  var _mkport=env._mkport;
+  var _write=env._write;
+  var _llvm_bswap_i32=env._llvm_bswap_i32;
+  var _fputc=env._fputc;
+  var _abort=env._abort;
+  var _fwrite=env._fwrite;
+  var _time=env._time;
+  var _fprintf=env._fprintf;
+  var __formatString=env.__formatString;
+  var _fputs=env._fputs;
+  var _printf=env._printf;
+  var tempFloat = 0.0;
+
+// EMSCRIPTEN_START_FUNCS
+function _inflate(i2, i3) {
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, i39 = 0, i40 = 0, i41 = 0, i42 = 0, i43 = 0, i44 = 0, i45 = 0, i46 = 0, i47 = 0, i48 = 0, i49 = 0, i50 = 0, i51 = 0, i52 = 0, i53 = 0, i54 = 0, i55 = 0, i56 = 0, i57 = 0, i58 = 0, i59 = 0, i60 = 0, i61 = 0, i62 = 0, i63 = 0, i64 = 0, i65 = 0, i66 = 0, i67 = 0, i68 = 0, i69 = 0, i70 = 0, i71 = 0, i72 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i25 = i1;
+ if ((i2 | 0) == 0) {
+  i72 = -2;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i4 = HEAP32[i2 + 28 >> 2] | 0;
+ if ((i4 | 0) == 0) {
+  i72 = -2;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i8 = i2 + 12 | 0;
+ i19 = HEAP32[i8 >> 2] | 0;
+ if ((i19 | 0) == 0) {
+  i72 = -2;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i62 = HEAP32[i2 >> 2] | 0;
+ if ((i62 | 0) == 0 ? (HEAP32[i2 + 4 >> 2] | 0) != 0 : 0) {
+  i72 = -2;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i68 = HEAP32[i4 >> 2] | 0;
+ if ((i68 | 0) == 11) {
+  HEAP32[i4 >> 2] = 12;
+  i68 = 12;
+  i62 = HEAP32[i2 >> 2] | 0;
+  i19 = HEAP32[i8 >> 2] | 0;
+ }
+ i15 = i2 + 16 | 0;
+ i59 = HEAP32[i15 >> 2] | 0;
+ i16 = i2 + 4 | 0;
+ i5 = HEAP32[i16 >> 2] | 0;
+ i17 = i4 + 56 | 0;
+ i6 = i4 + 60 | 0;
+ i12 = i4 + 8 | 0;
+ i10 = i4 + 24 | 0;
+ i39 = i25 + 1 | 0;
+ i11 = i4 + 16 | 0;
+ i38 = i4 + 32 | 0;
+ i35 = i2 + 24 | 0;
+ i40 = i4 + 36 | 0;
+ i41 = i4 + 20 | 0;
+ i9 = i2 + 48 | 0;
+ i42 = i4 + 64 | 0;
+ i46 = i4 + 12 | 0;
+ i47 = (i3 + -5 | 0) >>> 0 < 2;
+ i7 = i4 + 4 | 0;
+ i48 = i4 + 76 | 0;
+ i49 = i4 + 84 | 0;
+ i50 = i4 + 80 | 0;
+ i51 = i4 + 88 | 0;
+ i43 = (i3 | 0) == 6;
+ i57 = i4 + 7108 | 0;
+ i37 = i4 + 72 | 0;
+ i58 = i4 + 7112 | 0;
+ i54 = i4 + 68 | 0;
+ i28 = i4 + 44 | 0;
+ i29 = i4 + 7104 | 0;
+ i30 = i4 + 48 | 0;
+ i31 = i4 + 52 | 0;
+ i18 = i4 + 40 | 0;
+ i13 = i2 + 20 | 0;
+ i14 = i4 + 28 | 0;
+ i32 = i4 + 96 | 0;
+ i33 = i4 + 100 | 0;
+ i34 = i4 + 92 | 0;
+ i36 = i4 + 104 | 0;
+ i52 = i4 + 1328 | 0;
+ i53 = i4 + 108 | 0;
+ i27 = i4 + 112 | 0;
+ i55 = i4 + 752 | 0;
+ i56 = i4 + 624 | 0;
+ i44 = i25 + 2 | 0;
+ i45 = i25 + 3 | 0;
+ i67 = HEAP32[i6 >> 2] | 0;
+ i65 = i5;
+ i64 = HEAP32[i17 >> 2] | 0;
+ i26 = i59;
+ i61 = 0;
+ L17 : while (1) {
+  L19 : do {
+   switch (i68 | 0) {
+   case 16:
+    {
+     if (i67 >>> 0 < 14) {
+      i63 = i67;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i66 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 14) {
+        i62 = i66;
+       } else {
+        i62 = i66;
+        break;
+       }
+      }
+     } else {
+      i63 = i67;
+     }
+     i71 = (i64 & 31) + 257 | 0;
+     HEAP32[i32 >> 2] = i71;
+     i72 = (i64 >>> 5 & 31) + 1 | 0;
+     HEAP32[i33 >> 2] = i72;
+     HEAP32[i34 >> 2] = (i64 >>> 10 & 15) + 4;
+     i64 = i64 >>> 14;
+     i63 = i63 + -14 | 0;
+     if (i71 >>> 0 > 286 | i72 >>> 0 > 30) {
+      HEAP32[i35 >> 2] = 11616;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break L19;
+     } else {
+      HEAP32[i36 >> 2] = 0;
+      HEAP32[i4 >> 2] = 17;
+      i66 = 0;
+      i60 = 154;
+      break L19;
+     }
+    }
+   case 2:
+    {
+     if (i67 >>> 0 < 32) {
+      i63 = i67;
+      i60 = 47;
+     } else {
+      i60 = 49;
+     }
+     break;
+    }
+   case 23:
+    {
+     i66 = HEAP32[i37 >> 2] | 0;
+     i63 = i67;
+     i60 = 240;
+     break;
+    }
+   case 18:
+    {
+     i63 = HEAP32[i36 >> 2] | 0;
+     i69 = i65;
+     i60 = 164;
+     break;
+    }
+   case 1:
+    {
+     if (i67 >>> 0 < 16) {
+      i63 = i67;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i66 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 16) {
+        i62 = i66;
+       } else {
+        i62 = i66;
+        break;
+       }
+      }
+     } else {
+      i63 = i67;
+     }
+     HEAP32[i11 >> 2] = i64;
+     if ((i64 & 255 | 0) != 8) {
+      HEAP32[i35 >> 2] = 11448;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break L19;
+     }
+     if ((i64 & 57344 | 0) != 0) {
+      HEAP32[i35 >> 2] = 11504;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break L19;
+     }
+     i60 = HEAP32[i38 >> 2] | 0;
+     if ((i60 | 0) == 0) {
+      i60 = i64;
+     } else {
+      HEAP32[i60 >> 2] = i64 >>> 8 & 1;
+      i60 = HEAP32[i11 >> 2] | 0;
+     }
+     if ((i60 & 512 | 0) != 0) {
+      HEAP8[i25] = i64;
+      HEAP8[i39] = i64 >>> 8;
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 2) | 0;
+     }
+     HEAP32[i4 >> 2] = 2;
+     i63 = 0;
+     i64 = 0;
+     i60 = 47;
+     break;
+    }
+   case 8:
+    {
+     i63 = i67;
+     i60 = 109;
+     break;
+    }
+   case 22:
+    {
+     i63 = i67;
+     i60 = 228;
+     break;
+    }
+   case 24:
+    {
+     i63 = i67;
+     i60 = 246;
+     break;
+    }
+   case 19:
+    {
+     i63 = i67;
+     i60 = 201;
+     break;
+    }
+   case 20:
+    {
+     i63 = i67;
+     i60 = 202;
+     break;
+    }
+   case 21:
+    {
+     i66 = HEAP32[i37 >> 2] | 0;
+     i63 = i67;
+     i60 = 221;
+     break;
+    }
+   case 10:
+    {
+     i63 = i67;
+     i60 = 121;
+     break;
+    }
+   case 11:
+    {
+     i63 = i67;
+     i60 = 124;
+     break;
+    }
+   case 12:
+    {
+     i63 = i67;
+     i60 = 125;
+     break;
+    }
+   case 5:
+    {
+     i63 = i67;
+     i60 = 73;
+     break;
+    }
+   case 4:
+    {
+     i63 = i67;
+     i60 = 62;
+     break;
+    }
+   case 0:
+    {
+     i66 = HEAP32[i12 >> 2] | 0;
+     if ((i66 | 0) == 0) {
+      HEAP32[i4 >> 2] = 12;
+      i63 = i67;
+      i66 = i26;
+      break L19;
+     }
+     if (i67 >>> 0 < 16) {
+      i63 = i67;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i67 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 16) {
+        i62 = i67;
+       } else {
+        i62 = i67;
+        break;
+       }
+      }
+     } else {
+      i63 = i67;
+     }
+     if ((i66 & 2 | 0) != 0 & (i64 | 0) == 35615) {
+      HEAP32[i10 >> 2] = _crc32(0, 0, 0) | 0;
+      HEAP8[i25] = 31;
+      HEAP8[i39] = -117;
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 2) | 0;
+      HEAP32[i4 >> 2] = 1;
+      i63 = 0;
+      i64 = 0;
+      i66 = i26;
+      break L19;
+     }
+     HEAP32[i11 >> 2] = 0;
+     i67 = HEAP32[i38 >> 2] | 0;
+     if ((i67 | 0) != 0) {
+      HEAP32[i67 + 48 >> 2] = -1;
+      i66 = HEAP32[i12 >> 2] | 0;
+     }
+     if ((i66 & 1 | 0) != 0 ? ((((i64 << 8 & 65280) + (i64 >>> 8) | 0) >>> 0) % 31 | 0 | 0) == 0 : 0) {
+      if ((i64 & 15 | 0) != 8) {
+       HEAP32[i35 >> 2] = 11448;
+       HEAP32[i4 >> 2] = 29;
+       i66 = i26;
+       break L19;
+      }
+      i66 = i64 >>> 4;
+      i63 = i63 + -4 | 0;
+      i68 = (i66 & 15) + 8 | 0;
+      i67 = HEAP32[i40 >> 2] | 0;
+      if ((i67 | 0) != 0) {
+       if (i68 >>> 0 > i67 >>> 0) {
+        HEAP32[i35 >> 2] = 11480;
+        HEAP32[i4 >> 2] = 29;
+        i64 = i66;
+        i66 = i26;
+        break L19;
+       }
+      } else {
+       HEAP32[i40 >> 2] = i68;
+      }
+      HEAP32[i41 >> 2] = 1 << i68;
+      i63 = _adler32(0, 0, 0) | 0;
+      HEAP32[i10 >> 2] = i63;
+      HEAP32[i9 >> 2] = i63;
+      HEAP32[i4 >> 2] = i64 >>> 12 & 2 ^ 11;
+      i63 = 0;
+      i64 = 0;
+      i66 = i26;
+      break L19;
+     }
+     HEAP32[i35 >> 2] = 11424;
+     HEAP32[i4 >> 2] = 29;
+     i66 = i26;
+     break;
+    }
+   case 26:
+    {
+     if ((HEAP32[i12 >> 2] | 0) != 0) {
+      if (i67 >>> 0 < 32) {
+       i63 = i67;
+       while (1) {
+        if ((i65 | 0) == 0) {
+         i65 = 0;
+         break L17;
+        }
+        i65 = i65 + -1 | 0;
+        i66 = i62 + 1 | 0;
+        i64 = (HEAPU8[i62] << i63) + i64 | 0;
+        i63 = i63 + 8 | 0;
+        if (i63 >>> 0 < 32) {
+         i62 = i66;
+        } else {
+         i62 = i66;
+         break;
+        }
+       }
+      } else {
+       i63 = i67;
+      }
+      i66 = i59 - i26 | 0;
+      HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i66;
+      HEAP32[i14 >> 2] = (HEAP32[i14 >> 2] | 0) + i66;
+      if ((i59 | 0) != (i26 | 0)) {
+       i59 = HEAP32[i10 >> 2] | 0;
+       i67 = i19 + (0 - i66) | 0;
+       if ((HEAP32[i11 >> 2] | 0) == 0) {
+        i59 = _adler32(i59, i67, i66) | 0;
+       } else {
+        i59 = _crc32(i59, i67, i66) | 0;
+       }
+       HEAP32[i10 >> 2] = i59;
+       HEAP32[i9 >> 2] = i59;
+      }
+      if ((HEAP32[i11 >> 2] | 0) == 0) {
+       i59 = _llvm_bswap_i32(i64 | 0) | 0;
+      } else {
+       i59 = i64;
+      }
+      if ((i59 | 0) == (HEAP32[i10 >> 2] | 0)) {
+       i63 = 0;
+       i64 = 0;
+       i59 = i26;
+      } else {
+       HEAP32[i35 >> 2] = 11904;
+       HEAP32[i4 >> 2] = 29;
+       i66 = i26;
+       i59 = i26;
+       break L19;
+      }
+     } else {
+      i63 = i67;
+     }
+     HEAP32[i4 >> 2] = 27;
+     i60 = 277;
+     break;
+    }
+   case 27:
+    {
+     i63 = i67;
+     i60 = 277;
+     break;
+    }
+   case 28:
+    {
+     i63 = i67;
+     i61 = 1;
+     i60 = 285;
+     break L17;
+    }
+   case 29:
+    {
+     i63 = i67;
+     i61 = -3;
+     break L17;
+    }
+   case 25:
+    {
+     if ((i26 | 0) == 0) {
+      i63 = i67;
+      i26 = 0;
+      i60 = 285;
+      break L17;
+     }
+     HEAP8[i19] = HEAP32[i42 >> 2];
+     HEAP32[i4 >> 2] = 20;
+     i63 = i67;
+     i66 = i26 + -1 | 0;
+     i19 = i19 + 1 | 0;
+     break;
+    }
+   case 17:
+    {
+     i66 = HEAP32[i36 >> 2] | 0;
+     if (i66 >>> 0 < (HEAP32[i34 >> 2] | 0) >>> 0) {
+      i63 = i67;
+      i60 = 154;
+     } else {
+      i60 = 158;
+     }
+     break;
+    }
+   case 13:
+    {
+     i63 = i67 & 7;
+     i64 = i64 >>> i63;
+     i63 = i67 - i63 | 0;
+     if (i63 >>> 0 < 32) {
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i66 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 32) {
+        i62 = i66;
+       } else {
+        i62 = i66;
+        break;
+       }
+      }
+     }
+     i66 = i64 & 65535;
+     if ((i66 | 0) == (i64 >>> 16 ^ 65535 | 0)) {
+      HEAP32[i42 >> 2] = i66;
+      HEAP32[i4 >> 2] = 14;
+      if (i43) {
+       i63 = 0;
+       i64 = 0;
+       i60 = 285;
+       break L17;
+      } else {
+       i63 = 0;
+       i64 = 0;
+       i60 = 143;
+       break L19;
+      }
+     } else {
+      HEAP32[i35 >> 2] = 11584;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break L19;
+     }
+    }
+   case 7:
+    {
+     i63 = i67;
+     i60 = 96;
+     break;
+    }
+   case 14:
+    {
+     i63 = i67;
+     i60 = 143;
+     break;
+    }
+   case 15:
+    {
+     i63 = i67;
+     i60 = 144;
+     break;
+    }
+   case 9:
+    {
+     if (i67 >>> 0 < 32) {
+      i63 = i67;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i66 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 32) {
+        i62 = i66;
+       } else {
+        i62 = i66;
+        break;
+       }
+      }
+     }
+     i63 = _llvm_bswap_i32(i64 | 0) | 0;
+     HEAP32[i10 >> 2] = i63;
+     HEAP32[i9 >> 2] = i63;
+     HEAP32[i4 >> 2] = 10;
+     i63 = 0;
+     i64 = 0;
+     i60 = 121;
+     break;
+    }
+   case 30:
+    {
+     i60 = 299;
+     break L17;
+    }
+   case 6:
+    {
+     i63 = i67;
+     i60 = 83;
+     break;
+    }
+   case 3:
+    {
+     if (i67 >>> 0 < 16) {
+      i63 = i67;
+      i66 = i62;
+      i60 = 55;
+     } else {
+      i60 = 57;
+     }
+     break;
+    }
+   default:
+    {
+     i2 = -2;
+     i60 = 300;
+     break L17;
+    }
+   }
+  } while (0);
+  if ((i60 | 0) == 47) {
+   while (1) {
+    i60 = 0;
+    if ((i65 | 0) == 0) {
+     i65 = 0;
+     break L17;
+    }
+    i65 = i65 + -1 | 0;
+    i60 = i62 + 1 | 0;
+    i64 = (HEAPU8[i62] << i63) + i64 | 0;
+    i63 = i63 + 8 | 0;
+    if (i63 >>> 0 < 32) {
+     i62 = i60;
+     i60 = 47;
+    } else {
+     i62 = i60;
+     i60 = 49;
+     break;
+    }
+   }
+  } else if ((i60 | 0) == 121) {
+   if ((HEAP32[i46 >> 2] | 0) == 0) {
+    i60 = 122;
+    break;
+   }
+   i60 = _adler32(0, 0, 0) | 0;
+   HEAP32[i10 >> 2] = i60;
+   HEAP32[i9 >> 2] = i60;
+   HEAP32[i4 >> 2] = 11;
+   i60 = 124;
+  } else if ((i60 | 0) == 143) {
+   HEAP32[i4 >> 2] = 15;
+   i60 = 144;
+  } else if ((i60 | 0) == 154) {
+   while (1) {
+    i60 = 0;
+    if (i63 >>> 0 < 3) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i67 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      if (i63 >>> 0 < 3) {
+       i62 = i67;
+      } else {
+       i62 = i67;
+       break;
+      }
+     }
+    }
+    HEAP32[i36 >> 2] = i66 + 1;
+    HEAP16[i4 + (HEAPU16[11384 + (i66 << 1) >> 1] << 1) + 112 >> 1] = i64 & 7;
+    i64 = i64 >>> 3;
+    i63 = i63 + -3 | 0;
+    i66 = HEAP32[i36 >> 2] | 0;
+    if (i66 >>> 0 < (HEAP32[i34 >> 2] | 0) >>> 0) {
+     i60 = 154;
+    } else {
+     i67 = i63;
+     i60 = 158;
+     break;
+    }
+   }
+  } else if ((i60 | 0) == 277) {
+   i60 = 0;
+   if ((HEAP32[i12 >> 2] | 0) == 0) {
+    i60 = 284;
+    break;
+   }
+   if ((HEAP32[i11 >> 2] | 0) == 0) {
+    i60 = 284;
+    break;
+   }
+   if (i63 >>> 0 < 32) {
+    i66 = i62;
+    while (1) {
+     if ((i65 | 0) == 0) {
+      i65 = 0;
+      i62 = i66;
+      break L17;
+     }
+     i65 = i65 + -1 | 0;
+     i62 = i66 + 1 | 0;
+     i64 = (HEAPU8[i66] << i63) + i64 | 0;
+     i63 = i63 + 8 | 0;
+     if (i63 >>> 0 < 32) {
+      i66 = i62;
+     } else {
+      break;
+     }
+    }
+   }
+   if ((i64 | 0) == (HEAP32[i14 >> 2] | 0)) {
+    i63 = 0;
+    i64 = 0;
+    i60 = 284;
+    break;
+   }
+   HEAP32[i35 >> 2] = 11928;
+   HEAP32[i4 >> 2] = 29;
+   i66 = i26;
+  }
+  do {
+   if ((i60 | 0) == 49) {
+    i60 = HEAP32[i38 >> 2] | 0;
+    if ((i60 | 0) != 0) {
+     HEAP32[i60 + 4 >> 2] = i64;
+    }
+    if ((HEAP32[i11 >> 2] & 512 | 0) != 0) {
+     HEAP8[i25] = i64;
+     HEAP8[i39] = i64 >>> 8;
+     HEAP8[i44] = i64 >>> 16;
+     HEAP8[i45] = i64 >>> 24;
+     HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 4) | 0;
+    }
+    HEAP32[i4 >> 2] = 3;
+    i63 = 0;
+    i64 = 0;
+    i66 = i62;
+    i60 = 55;
+   } else if ((i60 | 0) == 124) {
+    if (i47) {
+     i60 = 285;
+     break L17;
+    } else {
+     i60 = 125;
+    }
+   } else if ((i60 | 0) == 144) {
+    i60 = 0;
+    i66 = HEAP32[i42 >> 2] | 0;
+    if ((i66 | 0) == 0) {
+     HEAP32[i4 >> 2] = 11;
+     i66 = i26;
+     break;
+    }
+    i66 = i66 >>> 0 > i65 >>> 0 ? i65 : i66;
+    i67 = i66 >>> 0 > i26 >>> 0 ? i26 : i66;
+    if ((i67 | 0) == 0) {
+     i60 = 285;
+     break L17;
+    }
+    _memcpy(i19 | 0, i62 | 0, i67 | 0) | 0;
+    HEAP32[i42 >> 2] = (HEAP32[i42 >> 2] | 0) - i67;
+    i65 = i65 - i67 | 0;
+    i66 = i26 - i67 | 0;
+    i62 = i62 + i67 | 0;
+    i19 = i19 + i67 | 0;
+   } else if ((i60 | 0) == 158) {
+    i60 = 0;
+    if (i66 >>> 0 < 19) {
+     while (1) {
+      i61 = i66 + 1 | 0;
+      HEAP16[i4 + (HEAPU16[11384 + (i66 << 1) >> 1] << 1) + 112 >> 1] = 0;
+      if ((i61 | 0) == 19) {
+       break;
+      } else {
+       i66 = i61;
+      }
+     }
+     HEAP32[i36 >> 2] = 19;
+    }
+    HEAP32[i53 >> 2] = i52;
+    HEAP32[i48 >> 2] = i52;
+    HEAP32[i49 >> 2] = 7;
+    i61 = _inflate_table(0, i27, 19, i53, i49, i55) | 0;
+    if ((i61 | 0) == 0) {
+     HEAP32[i36 >> 2] = 0;
+     HEAP32[i4 >> 2] = 18;
+     i63 = 0;
+     i69 = i65;
+     i61 = 0;
+     i60 = 164;
+     break;
+    } else {
+     HEAP32[i35 >> 2] = 11656;
+     HEAP32[i4 >> 2] = 29;
+     i63 = i67;
+     i66 = i26;
+     break;
+    }
+   }
+  } while (0);
+  L163 : do {
+   if ((i60 | 0) == 55) {
+    while (1) {
+     i60 = 0;
+     if ((i65 | 0) == 0) {
+      i65 = 0;
+      i62 = i66;
+      break L17;
+     }
+     i65 = i65 + -1 | 0;
+     i62 = i66 + 1 | 0;
+     i64 = (HEAPU8[i66] << i63) + i64 | 0;
+     i63 = i63 + 8 | 0;
+     if (i63 >>> 0 < 16) {
+      i66 = i62;
+      i60 = 55;
+     } else {
+      i60 = 57;
+      break;
+     }
+    }
+   } else if ((i60 | 0) == 125) {
+    i60 = 0;
+    if ((HEAP32[i7 >> 2] | 0) != 0) {
+     i66 = i63 & 7;
+     HEAP32[i4 >> 2] = 26;
+     i63 = i63 - i66 | 0;
+     i64 = i64 >>> i66;
+     i66 = i26;
+     break;
+    }
+    if (i63 >>> 0 < 3) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i66 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      if (i63 >>> 0 < 3) {
+       i62 = i66;
+      } else {
+       i62 = i66;
+       break;
+      }
+     }
+    }
+    HEAP32[i7 >> 2] = i64 & 1;
+    i66 = i64 >>> 1 & 3;
+    if ((i66 | 0) == 0) {
+     HEAP32[i4 >> 2] = 13;
+    } else if ((i66 | 0) == 1) {
+     HEAP32[i48 >> 2] = 11952;
+     HEAP32[i49 >> 2] = 9;
+     HEAP32[i50 >> 2] = 14e3;
+     HEAP32[i51 >> 2] = 5;
+     HEAP32[i4 >> 2] = 19;
+     if (i43) {
+      i60 = 133;
+      break L17;
+     }
+    } else if ((i66 | 0) == 2) {
+     HEAP32[i4 >> 2] = 16;
+    } else if ((i66 | 0) == 3) {
+     HEAP32[i35 >> 2] = 11560;
+     HEAP32[i4 >> 2] = 29;
+    }
+    i63 = i63 + -3 | 0;
+    i64 = i64 >>> 3;
+    i66 = i26;
+   } else if ((i60 | 0) == 164) {
+    i60 = 0;
+    i65 = HEAP32[i32 >> 2] | 0;
+    i66 = HEAP32[i33 >> 2] | 0;
+    do {
+     if (i63 >>> 0 < (i66 + i65 | 0) >>> 0) {
+      i71 = i67;
+      L181 : while (1) {
+       i70 = (1 << HEAP32[i49 >> 2]) + -1 | 0;
+       i72 = i70 & i64;
+       i68 = HEAP32[i48 >> 2] | 0;
+       i67 = HEAPU8[i68 + (i72 << 2) + 1 | 0] | 0;
+       if (i67 >>> 0 > i71 >>> 0) {
+        i67 = i71;
+        while (1) {
+         if ((i69 | 0) == 0) {
+          i63 = i67;
+          i65 = 0;
+          break L17;
+         }
+         i69 = i69 + -1 | 0;
+         i71 = i62 + 1 | 0;
+         i64 = (HEAPU8[i62] << i67) + i64 | 0;
+         i62 = i67 + 8 | 0;
+         i72 = i70 & i64;
+         i67 = HEAPU8[i68 + (i72 << 2) + 1 | 0] | 0;
+         if (i67 >>> 0 > i62 >>> 0) {
+          i67 = i62;
+          i62 = i71;
+         } else {
+          i70 = i62;
+          i62 = i71;
+          break;
+         }
+        }
+       } else {
+        i70 = i71;
+       }
+       i68 = HEAP16[i68 + (i72 << 2) + 2 >> 1] | 0;
+       L188 : do {
+        if ((i68 & 65535) < 16) {
+         if (i70 >>> 0 < i67 >>> 0) {
+          while (1) {
+           if ((i69 | 0) == 0) {
+            i63 = i70;
+            i65 = 0;
+            break L17;
+           }
+           i69 = i69 + -1 | 0;
+           i65 = i62 + 1 | 0;
+           i64 = (HEAPU8[i62] << i70) + i64 | 0;
+           i70 = i70 + 8 | 0;
+           if (i70 >>> 0 < i67 >>> 0) {
+            i62 = i65;
+           } else {
+            i62 = i65;
+            break;
+           }
+          }
+         }
+         HEAP32[i36 >> 2] = i63 + 1;
+         HEAP16[i4 + (i63 << 1) + 112 >> 1] = i68;
+         i71 = i70 - i67 | 0;
+         i64 = i64 >>> i67;
+        } else {
+         if (i68 << 16 >> 16 == 16) {
+          i68 = i67 + 2 | 0;
+          if (i70 >>> 0 < i68 >>> 0) {
+           i71 = i62;
+           while (1) {
+            if ((i69 | 0) == 0) {
+             i63 = i70;
+             i65 = 0;
+             i62 = i71;
+             break L17;
+            }
+            i69 = i69 + -1 | 0;
+            i62 = i71 + 1 | 0;
+            i64 = (HEAPU8[i71] << i70) + i64 | 0;
+            i70 = i70 + 8 | 0;
+            if (i70 >>> 0 < i68 >>> 0) {
+             i71 = i62;
+            } else {
+             break;
+            }
+           }
+          }
+          i64 = i64 >>> i67;
+          i67 = i70 - i67 | 0;
+          if ((i63 | 0) == 0) {
+           i60 = 181;
+           break L181;
+          }
+          i67 = i67 + -2 | 0;
+          i68 = (i64 & 3) + 3 | 0;
+          i64 = i64 >>> 2;
+          i70 = HEAP16[i4 + (i63 + -1 << 1) + 112 >> 1] | 0;
+         } else if (i68 << 16 >> 16 == 17) {
+          i68 = i67 + 3 | 0;
+          if (i70 >>> 0 < i68 >>> 0) {
+           i71 = i62;
+           while (1) {
+            if ((i69 | 0) == 0) {
+             i63 = i70;
+             i65 = 0;
+             i62 = i71;
+             break L17;
+            }
+            i69 = i69 + -1 | 0;
+            i62 = i71 + 1 | 0;
+            i64 = (HEAPU8[i71] << i70) + i64 | 0;
+            i70 = i70 + 8 | 0;
+            if (i70 >>> 0 < i68 >>> 0) {
+             i71 = i62;
+            } else {
+             break;
+            }
+           }
+          }
+          i64 = i64 >>> i67;
+          i67 = -3 - i67 + i70 | 0;
+          i68 = (i64 & 7) + 3 | 0;
+          i64 = i64 >>> 3;
+          i70 = 0;
+         } else {
+          i68 = i67 + 7 | 0;
+          if (i70 >>> 0 < i68 >>> 0) {
+           i71 = i62;
+           while (1) {
+            if ((i69 | 0) == 0) {
+             i63 = i70;
+             i65 = 0;
+             i62 = i71;
+             break L17;
+            }
+            i69 = i69 + -1 | 0;
+            i62 = i71 + 1 | 0;
+            i64 = (HEAPU8[i71] << i70) + i64 | 0;
+            i70 = i70 + 8 | 0;
+            if (i70 >>> 0 < i68 >>> 0) {
+             i71 = i62;
+            } else {
+             break;
+            }
+           }
+          }
+          i64 = i64 >>> i67;
+          i67 = -7 - i67 + i70 | 0;
+          i68 = (i64 & 127) + 11 | 0;
+          i64 = i64 >>> 7;
+          i70 = 0;
+         }
+         if ((i63 + i68 | 0) >>> 0 > (i66 + i65 | 0) >>> 0) {
+          i60 = 190;
+          break L181;
+         }
+         while (1) {
+          i68 = i68 + -1 | 0;
+          HEAP32[i36 >> 2] = i63 + 1;
+          HEAP16[i4 + (i63 << 1) + 112 >> 1] = i70;
+          if ((i68 | 0) == 0) {
+           i71 = i67;
+           break L188;
+          }
+          i63 = HEAP32[i36 >> 2] | 0;
+         }
+        }
+       } while (0);
+       i63 = HEAP32[i36 >> 2] | 0;
+       i65 = HEAP32[i32 >> 2] | 0;
+       i66 = HEAP32[i33 >> 2] | 0;
+       if (!(i63 >>> 0 < (i66 + i65 | 0) >>> 0)) {
+        i60 = 193;
+        break;
+       }
+      }
+      if ((i60 | 0) == 181) {
+       i60 = 0;
+       HEAP32[i35 >> 2] = 11688;
+       HEAP32[i4 >> 2] = 29;
+       i63 = i67;
+       i65 = i69;
+       i66 = i26;
+       break L163;
+      } else if ((i60 | 0) == 190) {
+       i60 = 0;
+       HEAP32[i35 >> 2] = 11688;
+       HEAP32[i4 >> 2] = 29;
+       i63 = i67;
+       i65 = i69;
+       i66 = i26;
+       break L163;
+      } else if ((i60 | 0) == 193) {
+       i60 = 0;
+       if ((HEAP32[i4 >> 2] | 0) == 29) {
+        i63 = i71;
+        i65 = i69;
+        i66 = i26;
+        break L163;
+       } else {
+        i63 = i71;
+        break;
+       }
+      }
+     } else {
+      i63 = i67;
+     }
+    } while (0);
+    if ((HEAP16[i56 >> 1] | 0) == 0) {
+     HEAP32[i35 >> 2] = 11720;
+     HEAP32[i4 >> 2] = 29;
+     i65 = i69;
+     i66 = i26;
+     break;
+    }
+    HEAP32[i53 >> 2] = i52;
+    HEAP32[i48 >> 2] = i52;
+    HEAP32[i49 >> 2] = 9;
+    i61 = _inflate_table(1, i27, i65, i53, i49, i55) | 0;
+    if ((i61 | 0) != 0) {
+     HEAP32[i35 >> 2] = 11760;
+     HEAP32[i4 >> 2] = 29;
+     i65 = i69;
+     i66 = i26;
+     break;
+    }
+    HEAP32[i50 >> 2] = HEAP32[i53 >> 2];
+    HEAP32[i51 >> 2] = 6;
+    i61 = _inflate_table(2, i4 + (HEAP32[i32 >> 2] << 1) + 112 | 0, HEAP32[i33 >> 2] | 0, i53, i51, i55) | 0;
+    if ((i61 | 0) == 0) {
+     HEAP32[i4 >> 2] = 19;
+     if (i43) {
+      i65 = i69;
+      i61 = 0;
+      i60 = 285;
+      break L17;
+     } else {
+      i65 = i69;
+      i61 = 0;
+      i60 = 201;
+      break;
+     }
+    } else {
+     HEAP32[i35 >> 2] = 11792;
+     HEAP32[i4 >> 2] = 29;
+     i65 = i69;
+     i66 = i26;
+     break;
+    }
+   }
+  } while (0);
+  if ((i60 | 0) == 57) {
+   i60 = HEAP32[i38 >> 2] | 0;
+   if ((i60 | 0) != 0) {
+    HEAP32[i60 + 8 >> 2] = i64 & 255;
+    HEAP32[i60 + 12 >> 2] = i64 >>> 8;
+   }
+   if ((HEAP32[i11 >> 2] & 512 | 0) != 0) {
+    HEAP8[i25] = i64;
+    HEAP8[i39] = i64 >>> 8;
+    HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 2) | 0;
+   }
+   HEAP32[i4 >> 2] = 4;
+   i63 = 0;
+   i64 = 0;
+   i60 = 62;
+  } else if ((i60 | 0) == 201) {
+   HEAP32[i4 >> 2] = 20;
+   i60 = 202;
+  }
+  do {
+   if ((i60 | 0) == 62) {
+    i60 = 0;
+    i66 = HEAP32[i11 >> 2] | 0;
+    if ((i66 & 1024 | 0) == 0) {
+     i60 = HEAP32[i38 >> 2] | 0;
+     if ((i60 | 0) != 0) {
+      HEAP32[i60 + 16 >> 2] = 0;
+     }
+    } else {
+     if (i63 >>> 0 < 16) {
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i67 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 16) {
+        i62 = i67;
+       } else {
+        i62 = i67;
+        break;
+       }
+      }
+     }
+     HEAP32[i42 >> 2] = i64;
+     i60 = HEAP32[i38 >> 2] | 0;
+     if ((i60 | 0) != 0) {
+      HEAP32[i60 + 20 >> 2] = i64;
+      i66 = HEAP32[i11 >> 2] | 0;
+     }
+     if ((i66 & 512 | 0) == 0) {
+      i63 = 0;
+      i64 = 0;
+     } else {
+      HEAP8[i25] = i64;
+      HEAP8[i39] = i64 >>> 8;
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i25, 2) | 0;
+      i63 = 0;
+      i64 = 0;
+     }
+    }
+    HEAP32[i4 >> 2] = 5;
+    i60 = 73;
+   } else if ((i60 | 0) == 202) {
+    i60 = 0;
+    if (i65 >>> 0 > 5 & i26 >>> 0 > 257) {
+     HEAP32[i8 >> 2] = i19;
+     HEAP32[i15 >> 2] = i26;
+     HEAP32[i2 >> 2] = i62;
+     HEAP32[i16 >> 2] = i65;
+     HEAP32[i17 >> 2] = i64;
+     HEAP32[i6 >> 2] = i63;
+     _inflate_fast(i2, i59);
+     i19 = HEAP32[i8 >> 2] | 0;
+     i66 = HEAP32[i15 >> 2] | 0;
+     i62 = HEAP32[i2 >> 2] | 0;
+     i65 = HEAP32[i16 >> 2] | 0;
+     i64 = HEAP32[i17 >> 2] | 0;
+     i63 = HEAP32[i6 >> 2] | 0;
+     if ((HEAP32[i4 >> 2] | 0) != 11) {
+      break;
+     }
+     HEAP32[i57 >> 2] = -1;
+     break;
+    }
+    HEAP32[i57 >> 2] = 0;
+    i69 = (1 << HEAP32[i49 >> 2]) + -1 | 0;
+    i71 = i69 & i64;
+    i66 = HEAP32[i48 >> 2] | 0;
+    i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+    i67 = i68 & 255;
+    if (i67 >>> 0 > i63 >>> 0) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i70 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      i71 = i69 & i64;
+      i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+      i67 = i68 & 255;
+      if (i67 >>> 0 > i63 >>> 0) {
+       i62 = i70;
+      } else {
+       i62 = i70;
+       break;
+      }
+     }
+    }
+    i69 = HEAP8[i66 + (i71 << 2) | 0] | 0;
+    i70 = HEAP16[i66 + (i71 << 2) + 2 >> 1] | 0;
+    i71 = i69 & 255;
+    if (!(i69 << 24 >> 24 == 0)) {
+     if ((i71 & 240 | 0) == 0) {
+      i69 = i70 & 65535;
+      i70 = (1 << i67 + i71) + -1 | 0;
+      i71 = ((i64 & i70) >>> i67) + i69 | 0;
+      i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+      if (((i68 & 255) + i67 | 0) >>> 0 > i63 >>> 0) {
+       while (1) {
+        if ((i65 | 0) == 0) {
+         i65 = 0;
+         break L17;
+        }
+        i65 = i65 + -1 | 0;
+        i71 = i62 + 1 | 0;
+        i64 = (HEAPU8[i62] << i63) + i64 | 0;
+        i63 = i63 + 8 | 0;
+        i62 = ((i64 & i70) >>> i67) + i69 | 0;
+        i68 = HEAP8[i66 + (i62 << 2) + 1 | 0] | 0;
+        if (((i68 & 255) + i67 | 0) >>> 0 > i63 >>> 0) {
+         i62 = i71;
+        } else {
+         i69 = i62;
+         i62 = i71;
+         break;
+        }
+       }
+      } else {
+       i69 = i71;
+      }
+      i70 = HEAP16[i66 + (i69 << 2) + 2 >> 1] | 0;
+      i69 = HEAP8[i66 + (i69 << 2) | 0] | 0;
+      HEAP32[i57 >> 2] = i67;
+      i66 = i67;
+      i63 = i63 - i67 | 0;
+      i64 = i64 >>> i67;
+     } else {
+      i66 = 0;
+     }
+    } else {
+     i66 = 0;
+     i69 = 0;
+    }
+    i72 = i68 & 255;
+    i64 = i64 >>> i72;
+    i63 = i63 - i72 | 0;
+    HEAP32[i57 >> 2] = i66 + i72;
+    HEAP32[i42 >> 2] = i70 & 65535;
+    i66 = i69 & 255;
+    if (i69 << 24 >> 24 == 0) {
+     HEAP32[i4 >> 2] = 25;
+     i66 = i26;
+     break;
+    }
+    if ((i66 & 32 | 0) != 0) {
+     HEAP32[i57 >> 2] = -1;
+     HEAP32[i4 >> 2] = 11;
+     i66 = i26;
+     break;
+    }
+    if ((i66 & 64 | 0) == 0) {
+     i66 = i66 & 15;
+     HEAP32[i37 >> 2] = i66;
+     HEAP32[i4 >> 2] = 21;
+     i60 = 221;
+     break;
+    } else {
+     HEAP32[i35 >> 2] = 11816;
+     HEAP32[i4 >> 2] = 29;
+     i66 = i26;
+     break;
+    }
+   }
+  } while (0);
+  if ((i60 | 0) == 73) {
+   i68 = HEAP32[i11 >> 2] | 0;
+   if ((i68 & 1024 | 0) != 0) {
+    i67 = HEAP32[i42 >> 2] | 0;
+    i60 = i67 >>> 0 > i65 >>> 0 ? i65 : i67;
+    if ((i60 | 0) != 0) {
+     i66 = HEAP32[i38 >> 2] | 0;
+     if ((i66 | 0) != 0 ? (i20 = HEAP32[i66 + 16 >> 2] | 0, (i20 | 0) != 0) : 0) {
+      i67 = (HEAP32[i66 + 20 >> 2] | 0) - i67 | 0;
+      i66 = HEAP32[i66 + 24 >> 2] | 0;
+      _memcpy(i20 + i67 | 0, i62 | 0, ((i67 + i60 | 0) >>> 0 > i66 >>> 0 ? i66 - i67 | 0 : i60) | 0) | 0;
+      i68 = HEAP32[i11 >> 2] | 0;
+     }
+     if ((i68 & 512 | 0) != 0) {
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i62, i60) | 0;
+     }
+     i67 = (HEAP32[i42 >> 2] | 0) - i60 | 0;
+     HEAP32[i42 >> 2] = i67;
+     i65 = i65 - i60 | 0;
+     i62 = i62 + i60 | 0;
+    }
+    if ((i67 | 0) != 0) {
+     i60 = 285;
+     break;
+    }
+   }
+   HEAP32[i42 >> 2] = 0;
+   HEAP32[i4 >> 2] = 6;
+   i60 = 83;
+  } else if ((i60 | 0) == 221) {
+   i60 = 0;
+   if ((i66 | 0) == 0) {
+    i60 = HEAP32[i42 >> 2] | 0;
+   } else {
+    if (i63 >>> 0 < i66 >>> 0) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i67 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      if (i63 >>> 0 < i66 >>> 0) {
+       i62 = i67;
+      } else {
+       i62 = i67;
+       break;
+      }
+     }
+    }
+    i60 = (HEAP32[i42 >> 2] | 0) + ((1 << i66) + -1 & i64) | 0;
+    HEAP32[i42 >> 2] = i60;
+    HEAP32[i57 >> 2] = (HEAP32[i57 >> 2] | 0) + i66;
+    i63 = i63 - i66 | 0;
+    i64 = i64 >>> i66;
+   }
+   HEAP32[i58 >> 2] = i60;
+   HEAP32[i4 >> 2] = 22;
+   i60 = 228;
+  }
+  do {
+   if ((i60 | 0) == 83) {
+    if ((HEAP32[i11 >> 2] & 2048 | 0) == 0) {
+     i60 = HEAP32[i38 >> 2] | 0;
+     if ((i60 | 0) != 0) {
+      HEAP32[i60 + 28 >> 2] = 0;
+     }
+    } else {
+     if ((i65 | 0) == 0) {
+      i65 = 0;
+      i60 = 285;
+      break L17;
+     } else {
+      i66 = 0;
+     }
+     while (1) {
+      i60 = i66 + 1 | 0;
+      i67 = HEAP8[i62 + i66 | 0] | 0;
+      i66 = HEAP32[i38 >> 2] | 0;
+      if (((i66 | 0) != 0 ? (i23 = HEAP32[i66 + 28 >> 2] | 0, (i23 | 0) != 0) : 0) ? (i21 = HEAP32[i42 >> 2] | 0, i21 >>> 0 < (HEAP32[i66 + 32 >> 2] | 0) >>> 0) : 0) {
+       HEAP32[i42 >> 2] = i21 + 1;
+       HEAP8[i23 + i21 | 0] = i67;
+      }
+      i66 = i67 << 24 >> 24 != 0;
+      if (i66 & i60 >>> 0 < i65 >>> 0) {
+       i66 = i60;
+      } else {
+       break;
+      }
+     }
+     if ((HEAP32[i11 >> 2] & 512 | 0) != 0) {
+      HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i62, i60) | 0;
+     }
+     i65 = i65 - i60 | 0;
+     i62 = i62 + i60 | 0;
+     if (i66) {
+      i60 = 285;
+      break L17;
+     }
+    }
+    HEAP32[i42 >> 2] = 0;
+    HEAP32[i4 >> 2] = 7;
+    i60 = 96;
+   } else if ((i60 | 0) == 228) {
+    i60 = 0;
+    i69 = (1 << HEAP32[i51 >> 2]) + -1 | 0;
+    i71 = i69 & i64;
+    i66 = HEAP32[i50 >> 2] | 0;
+    i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+    i67 = i68 & 255;
+    if (i67 >>> 0 > i63 >>> 0) {
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i70 = i62 + 1 | 0;
+      i64 = (HEAPU8[i62] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      i71 = i69 & i64;
+      i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+      i67 = i68 & 255;
+      if (i67 >>> 0 > i63 >>> 0) {
+       i62 = i70;
+      } else {
+       i62 = i70;
+       break;
+      }
+     }
+    }
+    i69 = HEAP8[i66 + (i71 << 2) | 0] | 0;
+    i70 = HEAP16[i66 + (i71 << 2) + 2 >> 1] | 0;
+    i71 = i69 & 255;
+    if ((i71 & 240 | 0) == 0) {
+     i69 = i70 & 65535;
+     i70 = (1 << i67 + i71) + -1 | 0;
+     i71 = ((i64 & i70) >>> i67) + i69 | 0;
+     i68 = HEAP8[i66 + (i71 << 2) + 1 | 0] | 0;
+     if (((i68 & 255) + i67 | 0) >>> 0 > i63 >>> 0) {
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i71 = i62 + 1 | 0;
+       i64 = (HEAPU8[i62] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       i62 = ((i64 & i70) >>> i67) + i69 | 0;
+       i68 = HEAP8[i66 + (i62 << 2) + 1 | 0] | 0;
+       if (((i68 & 255) + i67 | 0) >>> 0 > i63 >>> 0) {
+        i62 = i71;
+       } else {
+        i69 = i62;
+        i62 = i71;
+        break;
+       }
+      }
+     } else {
+      i69 = i71;
+     }
+     i70 = HEAP16[i66 + (i69 << 2) + 2 >> 1] | 0;
+     i69 = HEAP8[i66 + (i69 << 2) | 0] | 0;
+     i66 = (HEAP32[i57 >> 2] | 0) + i67 | 0;
+     HEAP32[i57 >> 2] = i66;
+     i63 = i63 - i67 | 0;
+     i64 = i64 >>> i67;
+    } else {
+     i66 = HEAP32[i57 >> 2] | 0;
+    }
+    i72 = i68 & 255;
+    i64 = i64 >>> i72;
+    i63 = i63 - i72 | 0;
+    HEAP32[i57 >> 2] = i66 + i72;
+    i66 = i69 & 255;
+    if ((i66 & 64 | 0) == 0) {
+     HEAP32[i54 >> 2] = i70 & 65535;
+     i66 = i66 & 15;
+     HEAP32[i37 >> 2] = i66;
+     HEAP32[i4 >> 2] = 23;
+     i60 = 240;
+     break;
+    } else {
+     HEAP32[i35 >> 2] = 11848;
+     HEAP32[i4 >> 2] = 29;
+     i66 = i26;
+     break;
+    }
+   }
+  } while (0);
+  if ((i60 | 0) == 96) {
+   if ((HEAP32[i11 >> 2] & 4096 | 0) == 0) {
+    i60 = HEAP32[i38 >> 2] | 0;
+    if ((i60 | 0) != 0) {
+     HEAP32[i60 + 36 >> 2] = 0;
+    }
+   } else {
+    if ((i65 | 0) == 0) {
+     i65 = 0;
+     i60 = 285;
+     break;
+    } else {
+     i66 = 0;
+    }
+    while (1) {
+     i60 = i66 + 1 | 0;
+     i66 = HEAP8[i62 + i66 | 0] | 0;
+     i67 = HEAP32[i38 >> 2] | 0;
+     if (((i67 | 0) != 0 ? (i24 = HEAP32[i67 + 36 >> 2] | 0, (i24 | 0) != 0) : 0) ? (i22 = HEAP32[i42 >> 2] | 0, i22 >>> 0 < (HEAP32[i67 + 40 >> 2] | 0) >>> 0) : 0) {
+      HEAP32[i42 >> 2] = i22 + 1;
+      HEAP8[i24 + i22 | 0] = i66;
+     }
+     i66 = i66 << 24 >> 24 != 0;
+     if (i66 & i60 >>> 0 < i65 >>> 0) {
+      i66 = i60;
+     } else {
+      break;
+     }
+    }
+    if ((HEAP32[i11 >> 2] & 512 | 0) != 0) {
+     HEAP32[i10 >> 2] = _crc32(HEAP32[i10 >> 2] | 0, i62, i60) | 0;
+    }
+    i65 = i65 - i60 | 0;
+    i62 = i62 + i60 | 0;
+    if (i66) {
+     i60 = 285;
+     break;
+    }
+   }
+   HEAP32[i4 >> 2] = 8;
+   i60 = 109;
+  } else if ((i60 | 0) == 240) {
+   i60 = 0;
+   if ((i66 | 0) != 0) {
+    if (i63 >>> 0 < i66 >>> 0) {
+     i67 = i62;
+     while (1) {
+      if ((i65 | 0) == 0) {
+       i65 = 0;
+       i62 = i67;
+       break L17;
+      }
+      i65 = i65 + -1 | 0;
+      i62 = i67 + 1 | 0;
+      i64 = (HEAPU8[i67] << i63) + i64 | 0;
+      i63 = i63 + 8 | 0;
+      if (i63 >>> 0 < i66 >>> 0) {
+       i67 = i62;
+      } else {
+       break;
+      }
+     }
+    }
+    HEAP32[i54 >> 2] = (HEAP32[i54 >> 2] | 0) + ((1 << i66) + -1 & i64);
+    HEAP32[i57 >> 2] = (HEAP32[i57 >> 2] | 0) + i66;
+    i63 = i63 - i66 | 0;
+    i64 = i64 >>> i66;
+   }
+   HEAP32[i4 >> 2] = 24;
+   i60 = 246;
+  }
+  do {
+   if ((i60 | 0) == 109) {
+    i60 = 0;
+    i66 = HEAP32[i11 >> 2] | 0;
+    if ((i66 & 512 | 0) != 0) {
+     if (i63 >>> 0 < 16) {
+      i67 = i62;
+      while (1) {
+       if ((i65 | 0) == 0) {
+        i65 = 0;
+        i62 = i67;
+        break L17;
+       }
+       i65 = i65 + -1 | 0;
+       i62 = i67 + 1 | 0;
+       i64 = (HEAPU8[i67] << i63) + i64 | 0;
+       i63 = i63 + 8 | 0;
+       if (i63 >>> 0 < 16) {
+        i67 = i62;
+       } else {
+        break;
+       }
+      }
+     }
+     if ((i64 | 0) == (HEAP32[i10 >> 2] & 65535 | 0)) {
+      i63 = 0;
+      i64 = 0;
+     } else {
+      HEAP32[i35 >> 2] = 11536;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break;
+     }
+    }
+    i67 = HEAP32[i38 >> 2] | 0;
+    if ((i67 | 0) != 0) {
+     HEAP32[i67 + 44 >> 2] = i66 >>> 9 & 1;
+     HEAP32[i67 + 48 >> 2] = 1;
+    }
+    i66 = _crc32(0, 0, 0) | 0;
+    HEAP32[i10 >> 2] = i66;
+    HEAP32[i9 >> 2] = i66;
+    HEAP32[i4 >> 2] = 11;
+    i66 = i26;
+   } else if ((i60 | 0) == 246) {
+    i60 = 0;
+    if ((i26 | 0) == 0) {
+     i26 = 0;
+     i60 = 285;
+     break L17;
+    }
+    i67 = i59 - i26 | 0;
+    i66 = HEAP32[i54 >> 2] | 0;
+    if (i66 >>> 0 > i67 >>> 0) {
+     i67 = i66 - i67 | 0;
+     if (i67 >>> 0 > (HEAP32[i28 >> 2] | 0) >>> 0 ? (HEAP32[i29 >> 2] | 0) != 0 : 0) {
+      HEAP32[i35 >> 2] = 11872;
+      HEAP32[i4 >> 2] = 29;
+      i66 = i26;
+      break;
+     }
+     i68 = HEAP32[i30 >> 2] | 0;
+     if (i67 >>> 0 > i68 >>> 0) {
+      i68 = i67 - i68 | 0;
+      i66 = i68;
+      i68 = (HEAP32[i31 >> 2] | 0) + ((HEAP32[i18 >> 2] | 0) - i68) | 0;
+     } else {
+      i66 = i67;
+      i68 = (HEAP32[i31 >> 2] | 0) + (i68 - i67) | 0;
+     }
+     i69 = HEAP32[i42 >> 2] | 0;
+     i67 = i69;
+     i69 = i66 >>> 0 > i69 >>> 0 ? i69 : i66;
+    } else {
+     i69 = HEAP32[i42 >> 2] | 0;
+     i67 = i69;
+     i68 = i19 + (0 - i66) | 0;
+    }
+    i66 = i69 >>> 0 > i26 >>> 0 ? i26 : i69;
+    HEAP32[i42 >> 2] = i67 - i66;
+    i67 = ~i26;
+    i69 = ~i69;
+    i67 = i67 >>> 0 > i69 >>> 0 ? i67 : i69;
+    i69 = i66;
+    i70 = i19;
+    while (1) {
+     HEAP8[i70] = HEAP8[i68] | 0;
+     i69 = i69 + -1 | 0;
+     if ((i69 | 0) == 0) {
+      break;
+     } else {
+      i68 = i68 + 1 | 0;
+      i70 = i70 + 1 | 0;
+     }
+    }
+    i66 = i26 - i66 | 0;
+    i19 = i19 + ~i67 | 0;
+    if ((HEAP32[i42 >> 2] | 0) == 0) {
+     HEAP32[i4 >> 2] = 20;
+    }
+   }
+  } while (0);
+  i68 = HEAP32[i4 >> 2] | 0;
+  i67 = i63;
+  i26 = i66;
+ }
+ if ((i60 | 0) == 122) {
+  HEAP32[i8 >> 2] = i19;
+  HEAP32[i15 >> 2] = i26;
+  HEAP32[i2 >> 2] = i62;
+  HEAP32[i16 >> 2] = i65;
+  HEAP32[i17 >> 2] = i64;
+  HEAP32[i6 >> 2] = i63;
+  i72 = 2;
+  STACKTOP = i1;
+  return i72 | 0;
+ } else if ((i60 | 0) == 133) {
+  i63 = i63 + -3 | 0;
+  i64 = i64 >>> 3;
+ } else if ((i60 | 0) == 284) {
+  HEAP32[i4 >> 2] = 28;
+  i61 = 1;
+ } else if ((i60 | 0) != 285) if ((i60 | 0) == 299) {
+  i72 = -4;
+  STACKTOP = i1;
+  return i72 | 0;
+ } else if ((i60 | 0) == 300) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ HEAP32[i8 >> 2] = i19;
+ HEAP32[i15 >> 2] = i26;
+ HEAP32[i2 >> 2] = i62;
+ HEAP32[i16 >> 2] = i65;
+ HEAP32[i17 >> 2] = i64;
+ HEAP32[i6 >> 2] = i63;
+ if ((HEAP32[i18 >> 2] | 0) == 0) {
+  if ((HEAP32[i4 >> 2] | 0) >>> 0 < 26 ? (i59 | 0) != (HEAP32[i15 >> 2] | 0) : 0) {
+   i60 = 289;
+  }
+ } else {
+  i60 = 289;
+ }
+ if ((i60 | 0) == 289 ? (_updatewindow(i2, i59) | 0) != 0 : 0) {
+  HEAP32[i4 >> 2] = 30;
+  i72 = -4;
+  STACKTOP = i1;
+  return i72 | 0;
+ }
+ i16 = HEAP32[i16 >> 2] | 0;
+ i72 = HEAP32[i15 >> 2] | 0;
+ i15 = i59 - i72 | 0;
+ i71 = i2 + 8 | 0;
+ HEAP32[i71 >> 2] = i5 - i16 + (HEAP32[i71 >> 2] | 0);
+ HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i15;
+ HEAP32[i14 >> 2] = (HEAP32[i14 >> 2] | 0) + i15;
+ i13 = (i59 | 0) == (i72 | 0);
+ if (!((HEAP32[i12 >> 2] | 0) == 0 | i13)) {
+  i12 = HEAP32[i10 >> 2] | 0;
+  i8 = (HEAP32[i8 >> 2] | 0) + (0 - i15) | 0;
+  if ((HEAP32[i11 >> 2] | 0) == 0) {
+   i8 = _adler32(i12, i8, i15) | 0;
+  } else {
+   i8 = _crc32(i12, i8, i15) | 0;
+  }
+  HEAP32[i10 >> 2] = i8;
+  HEAP32[i9 >> 2] = i8;
+ }
+ i4 = HEAP32[i4 >> 2] | 0;
+ if ((i4 | 0) == 19) {
+  i8 = 256;
+ } else {
+  i8 = (i4 | 0) == 14 ? 256 : 0;
+ }
+ HEAP32[i2 + 44 >> 2] = ((HEAP32[i7 >> 2] | 0) != 0 ? 64 : 0) + (HEAP32[i6 >> 2] | 0) + ((i4 | 0) == 11 ? 128 : 0) + i8;
+ i72 = ((i5 | 0) == (i16 | 0) & i13 | (i3 | 0) == 4) & (i61 | 0) == 0 ? -5 : i61;
+ STACKTOP = i1;
+ return i72 | 0;
+}
+function _malloc(i12) {
+ i12 = i12 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0;
+ i1 = STACKTOP;
+ do {
+  if (i12 >>> 0 < 245) {
+   if (i12 >>> 0 < 11) {
+    i12 = 16;
+   } else {
+    i12 = i12 + 11 & -8;
+   }
+   i20 = i12 >>> 3;
+   i18 = HEAP32[3618] | 0;
+   i21 = i18 >>> i20;
+   if ((i21 & 3 | 0) != 0) {
+    i6 = (i21 & 1 ^ 1) + i20 | 0;
+    i5 = i6 << 1;
+    i3 = 14512 + (i5 << 2) | 0;
+    i5 = 14512 + (i5 + 2 << 2) | 0;
+    i7 = HEAP32[i5 >> 2] | 0;
+    i2 = i7 + 8 | 0;
+    i4 = HEAP32[i2 >> 2] | 0;
+    do {
+     if ((i3 | 0) != (i4 | 0)) {
+      if (i4 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i8 = i4 + 12 | 0;
+      if ((HEAP32[i8 >> 2] | 0) == (i7 | 0)) {
+       HEAP32[i8 >> 2] = i3;
+       HEAP32[i5 >> 2] = i4;
+       break;
+      } else {
+       _abort();
+      }
+     } else {
+      HEAP32[3618] = i18 & ~(1 << i6);
+     }
+    } while (0);
+    i32 = i6 << 3;
+    HEAP32[i7 + 4 >> 2] = i32 | 3;
+    i32 = i7 + (i32 | 4) | 0;
+    HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+    i32 = i2;
+    STACKTOP = i1;
+    return i32 | 0;
+   }
+   if (i12 >>> 0 > (HEAP32[14480 >> 2] | 0) >>> 0) {
+    if ((i21 | 0) != 0) {
+     i7 = 2 << i20;
+     i7 = i21 << i20 & (i7 | 0 - i7);
+     i7 = (i7 & 0 - i7) + -1 | 0;
+     i2 = i7 >>> 12 & 16;
+     i7 = i7 >>> i2;
+     i6 = i7 >>> 5 & 8;
+     i7 = i7 >>> i6;
+     i5 = i7 >>> 2 & 4;
+     i7 = i7 >>> i5;
+     i4 = i7 >>> 1 & 2;
+     i7 = i7 >>> i4;
+     i3 = i7 >>> 1 & 1;
+     i3 = (i6 | i2 | i5 | i4 | i3) + (i7 >>> i3) | 0;
+     i7 = i3 << 1;
+     i4 = 14512 + (i7 << 2) | 0;
+     i7 = 14512 + (i7 + 2 << 2) | 0;
+     i5 = HEAP32[i7 >> 2] | 0;
+     i2 = i5 + 8 | 0;
+     i6 = HEAP32[i2 >> 2] | 0;
+     do {
+      if ((i4 | 0) != (i6 | 0)) {
+       if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       i8 = i6 + 12 | 0;
+       if ((HEAP32[i8 >> 2] | 0) == (i5 | 0)) {
+        HEAP32[i8 >> 2] = i4;
+        HEAP32[i7 >> 2] = i6;
+        break;
+       } else {
+        _abort();
+       }
+      } else {
+       HEAP32[3618] = i18 & ~(1 << i3);
+      }
+     } while (0);
+     i6 = i3 << 3;
+     i4 = i6 - i12 | 0;
+     HEAP32[i5 + 4 >> 2] = i12 | 3;
+     i3 = i5 + i12 | 0;
+     HEAP32[i5 + (i12 | 4) >> 2] = i4 | 1;
+     HEAP32[i5 + i6 >> 2] = i4;
+     i6 = HEAP32[14480 >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      i5 = HEAP32[14492 >> 2] | 0;
+      i8 = i6 >>> 3;
+      i9 = i8 << 1;
+      i6 = 14512 + (i9 << 2) | 0;
+      i7 = HEAP32[3618] | 0;
+      i8 = 1 << i8;
+      if ((i7 & i8 | 0) != 0) {
+       i7 = 14512 + (i9 + 2 << 2) | 0;
+       i8 = HEAP32[i7 >> 2] | 0;
+       if (i8 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i28 = i7;
+        i27 = i8;
+       }
+      } else {
+       HEAP32[3618] = i7 | i8;
+       i28 = 14512 + (i9 + 2 << 2) | 0;
+       i27 = i6;
+      }
+      HEAP32[i28 >> 2] = i5;
+      HEAP32[i27 + 12 >> 2] = i5;
+      HEAP32[i5 + 8 >> 2] = i27;
+      HEAP32[i5 + 12 >> 2] = i6;
+     }
+     HEAP32[14480 >> 2] = i4;
+     HEAP32[14492 >> 2] = i3;
+     i32 = i2;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i18 = HEAP32[14476 >> 2] | 0;
+    if ((i18 | 0) != 0) {
+     i2 = (i18 & 0 - i18) + -1 | 0;
+     i31 = i2 >>> 12 & 16;
+     i2 = i2 >>> i31;
+     i30 = i2 >>> 5 & 8;
+     i2 = i2 >>> i30;
+     i32 = i2 >>> 2 & 4;
+     i2 = i2 >>> i32;
+     i6 = i2 >>> 1 & 2;
+     i2 = i2 >>> i6;
+     i3 = i2 >>> 1 & 1;
+     i3 = HEAP32[14776 + ((i30 | i31 | i32 | i6 | i3) + (i2 >>> i3) << 2) >> 2] | 0;
+     i2 = (HEAP32[i3 + 4 >> 2] & -8) - i12 | 0;
+     i6 = i3;
+     while (1) {
+      i5 = HEAP32[i6 + 16 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       i5 = HEAP32[i6 + 20 >> 2] | 0;
+       if ((i5 | 0) == 0) {
+        break;
+       }
+      }
+      i6 = (HEAP32[i5 + 4 >> 2] & -8) - i12 | 0;
+      i4 = i6 >>> 0 < i2 >>> 0;
+      i2 = i4 ? i6 : i2;
+      i6 = i5;
+      i3 = i4 ? i5 : i3;
+     }
+     i6 = HEAP32[14488 >> 2] | 0;
+     if (i3 >>> 0 < i6 >>> 0) {
+      _abort();
+     }
+     i4 = i3 + i12 | 0;
+     if (!(i3 >>> 0 < i4 >>> 0)) {
+      _abort();
+     }
+     i5 = HEAP32[i3 + 24 >> 2] | 0;
+     i7 = HEAP32[i3 + 12 >> 2] | 0;
+     do {
+      if ((i7 | 0) == (i3 | 0)) {
+       i8 = i3 + 20 | 0;
+       i7 = HEAP32[i8 >> 2] | 0;
+       if ((i7 | 0) == 0) {
+        i8 = i3 + 16 | 0;
+        i7 = HEAP32[i8 >> 2] | 0;
+        if ((i7 | 0) == 0) {
+         i26 = 0;
+         break;
+        }
+       }
+       while (1) {
+        i10 = i7 + 20 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) != 0) {
+         i7 = i9;
+         i8 = i10;
+         continue;
+        }
+        i10 = i7 + 16 | 0;
+        i9 = HEAP32[i10 >> 2] | 0;
+        if ((i9 | 0) == 0) {
+         break;
+        } else {
+         i7 = i9;
+         i8 = i10;
+        }
+       }
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i8 >> 2] = 0;
+        i26 = i7;
+        break;
+       }
+      } else {
+       i8 = HEAP32[i3 + 8 >> 2] | 0;
+       if (i8 >>> 0 < i6 >>> 0) {
+        _abort();
+       }
+       i6 = i8 + 12 | 0;
+       if ((HEAP32[i6 >> 2] | 0) != (i3 | 0)) {
+        _abort();
+       }
+       i9 = i7 + 8 | 0;
+       if ((HEAP32[i9 >> 2] | 0) == (i3 | 0)) {
+        HEAP32[i6 >> 2] = i7;
+        HEAP32[i9 >> 2] = i8;
+        i26 = i7;
+        break;
+       } else {
+        _abort();
+       }
+      }
+     } while (0);
+     do {
+      if ((i5 | 0) != 0) {
+       i7 = HEAP32[i3 + 28 >> 2] | 0;
+       i6 = 14776 + (i7 << 2) | 0;
+       if ((i3 | 0) == (HEAP32[i6 >> 2] | 0)) {
+        HEAP32[i6 >> 2] = i26;
+        if ((i26 | 0) == 0) {
+         HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i7);
+         break;
+        }
+       } else {
+        if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        i6 = i5 + 16 | 0;
+        if ((HEAP32[i6 >> 2] | 0) == (i3 | 0)) {
+         HEAP32[i6 >> 2] = i26;
+        } else {
+         HEAP32[i5 + 20 >> 2] = i26;
+        }
+        if ((i26 | 0) == 0) {
+         break;
+        }
+       }
+       if (i26 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       }
+       HEAP32[i26 + 24 >> 2] = i5;
+       i5 = HEAP32[i3 + 16 >> 2] | 0;
+       do {
+        if ((i5 | 0) != 0) {
+         if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i26 + 16 >> 2] = i5;
+          HEAP32[i5 + 24 >> 2] = i26;
+          break;
+         }
+        }
+       } while (0);
+       i5 = HEAP32[i3 + 20 >> 2] | 0;
+       if ((i5 | 0) != 0) {
+        if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i26 + 20 >> 2] = i5;
+         HEAP32[i5 + 24 >> 2] = i26;
+         break;
+        }
+       }
+      }
+     } while (0);
+     if (i2 >>> 0 < 16) {
+      i32 = i2 + i12 | 0;
+      HEAP32[i3 + 4 >> 2] = i32 | 3;
+      i32 = i3 + (i32 + 4) | 0;
+      HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+     } else {
+      HEAP32[i3 + 4 >> 2] = i12 | 3;
+      HEAP32[i3 + (i12 | 4) >> 2] = i2 | 1;
+      HEAP32[i3 + (i2 + i12) >> 2] = i2;
+      i6 = HEAP32[14480 >> 2] | 0;
+      if ((i6 | 0) != 0) {
+       i5 = HEAP32[14492 >> 2] | 0;
+       i8 = i6 >>> 3;
+       i9 = i8 << 1;
+       i6 = 14512 + (i9 << 2) | 0;
+       i7 = HEAP32[3618] | 0;
+       i8 = 1 << i8;
+       if ((i7 & i8 | 0) != 0) {
+        i7 = 14512 + (i9 + 2 << 2) | 0;
+        i8 = HEAP32[i7 >> 2] | 0;
+        if (i8 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+         _abort();
+        } else {
+         i25 = i7;
+         i24 = i8;
+        }
+       } else {
+        HEAP32[3618] = i7 | i8;
+        i25 = 14512 + (i9 + 2 << 2) | 0;
+        i24 = i6;
+       }
+       HEAP32[i25 >> 2] = i5;
+       HEAP32[i24 + 12 >> 2] = i5;
+       HEAP32[i5 + 8 >> 2] = i24;
+       HEAP32[i5 + 12 >> 2] = i6;
+      }
+      HEAP32[14480 >> 2] = i2;
+      HEAP32[14492 >> 2] = i4;
+     }
+     i32 = i3 + 8 | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+   }
+  } else {
+   if (!(i12 >>> 0 > 4294967231)) {
+    i24 = i12 + 11 | 0;
+    i12 = i24 & -8;
+    i26 = HEAP32[14476 >> 2] | 0;
+    if ((i26 | 0) != 0) {
+     i25 = 0 - i12 | 0;
+     i24 = i24 >>> 8;
+     if ((i24 | 0) != 0) {
+      if (i12 >>> 0 > 16777215) {
+       i27 = 31;
+      } else {
+       i31 = (i24 + 1048320 | 0) >>> 16 & 8;
+       i32 = i24 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i27 = (i32 + 245760 | 0) >>> 16 & 2;
+       i27 = 14 - (i30 | i31 | i27) + (i32 << i27 >>> 15) | 0;
+       i27 = i12 >>> (i27 + 7 | 0) & 1 | i27 << 1;
+      }
+     } else {
+      i27 = 0;
+     }
+     i30 = HEAP32[14776 + (i27 << 2) >> 2] | 0;
+     L126 : do {
+      if ((i30 | 0) == 0) {
+       i29 = 0;
+       i24 = 0;
+      } else {
+       if ((i27 | 0) == 31) {
+        i24 = 0;
+       } else {
+        i24 = 25 - (i27 >>> 1) | 0;
+       }
+       i29 = 0;
+       i28 = i12 << i24;
+       i24 = 0;
+       while (1) {
+        i32 = HEAP32[i30 + 4 >> 2] & -8;
+        i31 = i32 - i12 | 0;
+        if (i31 >>> 0 < i25 >>> 0) {
+         if ((i32 | 0) == (i12 | 0)) {
+          i25 = i31;
+          i29 = i30;
+          i24 = i30;
+          break L126;
+         } else {
+          i25 = i31;
+          i24 = i30;
+         }
+        }
+        i31 = HEAP32[i30 + 20 >> 2] | 0;
+        i30 = HEAP32[i30 + (i28 >>> 31 << 2) + 16 >> 2] | 0;
+        i29 = (i31 | 0) == 0 | (i31 | 0) == (i30 | 0) ? i29 : i31;
+        if ((i30 | 0) == 0) {
+         break;
+        } else {
+         i28 = i28 << 1;
+        }
+       }
+      }
+     } while (0);
+     if ((i29 | 0) == 0 & (i24 | 0) == 0) {
+      i32 = 2 << i27;
+      i26 = i26 & (i32 | 0 - i32);
+      if ((i26 | 0) == 0) {
+       break;
+      }
+      i32 = (i26 & 0 - i26) + -1 | 0;
+      i28 = i32 >>> 12 & 16;
+      i32 = i32 >>> i28;
+      i27 = i32 >>> 5 & 8;
+      i32 = i32 >>> i27;
+      i30 = i32 >>> 2 & 4;
+      i32 = i32 >>> i30;
+      i31 = i32 >>> 1 & 2;
+      i32 = i32 >>> i31;
+      i29 = i32 >>> 1 & 1;
+      i29 = HEAP32[14776 + ((i27 | i28 | i30 | i31 | i29) + (i32 >>> i29) << 2) >> 2] | 0;
+     }
+     if ((i29 | 0) != 0) {
+      while (1) {
+       i27 = (HEAP32[i29 + 4 >> 2] & -8) - i12 | 0;
+       i26 = i27 >>> 0 < i25 >>> 0;
+       i25 = i26 ? i27 : i25;
+       i24 = i26 ? i29 : i24;
+       i26 = HEAP32[i29 + 16 >> 2] | 0;
+       if ((i26 | 0) != 0) {
+        i29 = i26;
+        continue;
+       }
+       i29 = HEAP32[i29 + 20 >> 2] | 0;
+       if ((i29 | 0) == 0) {
+        break;
+       }
+      }
+     }
+     if ((i24 | 0) != 0 ? i25 >>> 0 < ((HEAP32[14480 >> 2] | 0) - i12 | 0) >>> 0 : 0) {
+      i4 = HEAP32[14488 >> 2] | 0;
+      if (i24 >>> 0 < i4 >>> 0) {
+       _abort();
+      }
+      i2 = i24 + i12 | 0;
+      if (!(i24 >>> 0 < i2 >>> 0)) {
+       _abort();
+      }
+      i3 = HEAP32[i24 + 24 >> 2] | 0;
+      i6 = HEAP32[i24 + 12 >> 2] | 0;
+      do {
+       if ((i6 | 0) == (i24 | 0)) {
+        i6 = i24 + 20 | 0;
+        i5 = HEAP32[i6 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         i6 = i24 + 16 | 0;
+         i5 = HEAP32[i6 >> 2] | 0;
+         if ((i5 | 0) == 0) {
+          i22 = 0;
+          break;
+         }
+        }
+        while (1) {
+         i8 = i5 + 20 | 0;
+         i7 = HEAP32[i8 >> 2] | 0;
+         if ((i7 | 0) != 0) {
+          i5 = i7;
+          i6 = i8;
+          continue;
+         }
+         i7 = i5 + 16 | 0;
+         i8 = HEAP32[i7 >> 2] | 0;
+         if ((i8 | 0) == 0) {
+          break;
+         } else {
+          i5 = i8;
+          i6 = i7;
+         }
+        }
+        if (i6 >>> 0 < i4 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i6 >> 2] = 0;
+         i22 = i5;
+         break;
+        }
+       } else {
+        i5 = HEAP32[i24 + 8 >> 2] | 0;
+        if (i5 >>> 0 < i4 >>> 0) {
+         _abort();
+        }
+        i7 = i5 + 12 | 0;
+        if ((HEAP32[i7 >> 2] | 0) != (i24 | 0)) {
+         _abort();
+        }
+        i4 = i6 + 8 | 0;
+        if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+         HEAP32[i7 >> 2] = i6;
+         HEAP32[i4 >> 2] = i5;
+         i22 = i6;
+         break;
+        } else {
+         _abort();
+        }
+       }
+      } while (0);
+      do {
+       if ((i3 | 0) != 0) {
+        i4 = HEAP32[i24 + 28 >> 2] | 0;
+        i5 = 14776 + (i4 << 2) | 0;
+        if ((i24 | 0) == (HEAP32[i5 >> 2] | 0)) {
+         HEAP32[i5 >> 2] = i22;
+         if ((i22 | 0) == 0) {
+          HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i4);
+          break;
+         }
+        } else {
+         if (i3 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         }
+         i4 = i3 + 16 | 0;
+         if ((HEAP32[i4 >> 2] | 0) == (i24 | 0)) {
+          HEAP32[i4 >> 2] = i22;
+         } else {
+          HEAP32[i3 + 20 >> 2] = i22;
+         }
+         if ((i22 | 0) == 0) {
+          break;
+         }
+        }
+        if (i22 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+         _abort();
+        }
+        HEAP32[i22 + 24 >> 2] = i3;
+        i3 = HEAP32[i24 + 16 >> 2] | 0;
+        do {
+         if ((i3 | 0) != 0) {
+          if (i3 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i22 + 16 >> 2] = i3;
+           HEAP32[i3 + 24 >> 2] = i22;
+           break;
+          }
+         }
+        } while (0);
+        i3 = HEAP32[i24 + 20 >> 2] | 0;
+        if ((i3 | 0) != 0) {
+         if (i3 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i22 + 20 >> 2] = i3;
+          HEAP32[i3 + 24 >> 2] = i22;
+          break;
+         }
+        }
+       }
+      } while (0);
+      L204 : do {
+       if (!(i25 >>> 0 < 16)) {
+        HEAP32[i24 + 4 >> 2] = i12 | 3;
+        HEAP32[i24 + (i12 | 4) >> 2] = i25 | 1;
+        HEAP32[i24 + (i25 + i12) >> 2] = i25;
+        i4 = i25 >>> 3;
+        if (i25 >>> 0 < 256) {
+         i6 = i4 << 1;
+         i3 = 14512 + (i6 << 2) | 0;
+         i5 = HEAP32[3618] | 0;
+         i4 = 1 << i4;
+         if ((i5 & i4 | 0) != 0) {
+          i5 = 14512 + (i6 + 2 << 2) | 0;
+          i4 = HEAP32[i5 >> 2] | 0;
+          if (i4 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           i21 = i5;
+           i20 = i4;
+          }
+         } else {
+          HEAP32[3618] = i5 | i4;
+          i21 = 14512 + (i6 + 2 << 2) | 0;
+          i20 = i3;
+         }
+         HEAP32[i21 >> 2] = i2;
+         HEAP32[i20 + 12 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i20;
+         HEAP32[i24 + (i12 + 12) >> 2] = i3;
+         break;
+        }
+        i3 = i25 >>> 8;
+        if ((i3 | 0) != 0) {
+         if (i25 >>> 0 > 16777215) {
+          i3 = 31;
+         } else {
+          i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+          i32 = i3 << i31;
+          i30 = (i32 + 520192 | 0) >>> 16 & 4;
+          i32 = i32 << i30;
+          i3 = (i32 + 245760 | 0) >>> 16 & 2;
+          i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+          i3 = i25 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+         }
+        } else {
+         i3 = 0;
+        }
+        i6 = 14776 + (i3 << 2) | 0;
+        HEAP32[i24 + (i12 + 28) >> 2] = i3;
+        HEAP32[i24 + (i12 + 20) >> 2] = 0;
+        HEAP32[i24 + (i12 + 16) >> 2] = 0;
+        i4 = HEAP32[14476 >> 2] | 0;
+        i5 = 1 << i3;
+        if ((i4 & i5 | 0) == 0) {
+         HEAP32[14476 >> 2] = i4 | i5;
+         HEAP32[i6 >> 2] = i2;
+         HEAP32[i24 + (i12 + 24) >> 2] = i6;
+         HEAP32[i24 + (i12 + 12) >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i2;
+         break;
+        }
+        i4 = HEAP32[i6 >> 2] | 0;
+        if ((i3 | 0) == 31) {
+         i3 = 0;
+        } else {
+         i3 = 25 - (i3 >>> 1) | 0;
+        }
+        L225 : do {
+         if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i25 | 0)) {
+          i3 = i25 << i3;
+          while (1) {
+           i6 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+           i5 = HEAP32[i6 >> 2] | 0;
+           if ((i5 | 0) == 0) {
+            break;
+           }
+           if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i25 | 0)) {
+            i18 = i5;
+            break L225;
+           } else {
+            i3 = i3 << 1;
+            i4 = i5;
+           }
+          }
+          if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+           _abort();
+          } else {
+           HEAP32[i6 >> 2] = i2;
+           HEAP32[i24 + (i12 + 24) >> 2] = i4;
+           HEAP32[i24 + (i12 + 12) >> 2] = i2;
+           HEAP32[i24 + (i12 + 8) >> 2] = i2;
+           break L204;
+          }
+         } else {
+          i18 = i4;
+         }
+        } while (0);
+        i4 = i18 + 8 | 0;
+        i3 = HEAP32[i4 >> 2] | 0;
+        i5 = HEAP32[14488 >> 2] | 0;
+        if (i18 >>> 0 < i5 >>> 0) {
+         _abort();
+        }
+        if (i3 >>> 0 < i5 >>> 0) {
+         _abort();
+        } else {
+         HEAP32[i3 + 12 >> 2] = i2;
+         HEAP32[i4 >> 2] = i2;
+         HEAP32[i24 + (i12 + 8) >> 2] = i3;
+         HEAP32[i24 + (i12 + 12) >> 2] = i18;
+         HEAP32[i24 + (i12 + 24) >> 2] = 0;
+         break;
+        }
+       } else {
+        i32 = i25 + i12 | 0;
+        HEAP32[i24 + 4 >> 2] = i32 | 3;
+        i32 = i24 + (i32 + 4) | 0;
+        HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+       }
+      } while (0);
+      i32 = i24 + 8 | 0;
+      STACKTOP = i1;
+      return i32 | 0;
+     }
+    }
+   } else {
+    i12 = -1;
+   }
+  }
+ } while (0);
+ i18 = HEAP32[14480 >> 2] | 0;
+ if (!(i12 >>> 0 > i18 >>> 0)) {
+  i3 = i18 - i12 | 0;
+  i2 = HEAP32[14492 >> 2] | 0;
+  if (i3 >>> 0 > 15) {
+   HEAP32[14492 >> 2] = i2 + i12;
+   HEAP32[14480 >> 2] = i3;
+   HEAP32[i2 + (i12 + 4) >> 2] = i3 | 1;
+   HEAP32[i2 + i18 >> 2] = i3;
+   HEAP32[i2 + 4 >> 2] = i12 | 3;
+  } else {
+   HEAP32[14480 >> 2] = 0;
+   HEAP32[14492 >> 2] = 0;
+   HEAP32[i2 + 4 >> 2] = i18 | 3;
+   i32 = i2 + (i18 + 4) | 0;
+   HEAP32[i32 >> 2] = HEAP32[i32 >> 2] | 1;
+  }
+  i32 = i2 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i18 = HEAP32[14484 >> 2] | 0;
+ if (i12 >>> 0 < i18 >>> 0) {
+  i31 = i18 - i12 | 0;
+  HEAP32[14484 >> 2] = i31;
+  i32 = HEAP32[14496 >> 2] | 0;
+  HEAP32[14496 >> 2] = i32 + i12;
+  HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+  HEAP32[i32 + 4 >> 2] = i12 | 3;
+  i32 = i32 + 8 | 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ do {
+  if ((HEAP32[3736] | 0) == 0) {
+   i18 = _sysconf(30) | 0;
+   if ((i18 + -1 & i18 | 0) == 0) {
+    HEAP32[14952 >> 2] = i18;
+    HEAP32[14948 >> 2] = i18;
+    HEAP32[14956 >> 2] = -1;
+    HEAP32[14960 >> 2] = -1;
+    HEAP32[14964 >> 2] = 0;
+    HEAP32[14916 >> 2] = 0;
+    HEAP32[3736] = (_time(0) | 0) & -16 ^ 1431655768;
+    break;
+   } else {
+    _abort();
+   }
+  }
+ } while (0);
+ i20 = i12 + 48 | 0;
+ i25 = HEAP32[14952 >> 2] | 0;
+ i21 = i12 + 47 | 0;
+ i22 = i25 + i21 | 0;
+ i25 = 0 - i25 | 0;
+ i18 = i22 & i25;
+ if (!(i18 >>> 0 > i12 >>> 0)) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ i24 = HEAP32[14912 >> 2] | 0;
+ if ((i24 | 0) != 0 ? (i31 = HEAP32[14904 >> 2] | 0, i32 = i31 + i18 | 0, i32 >>> 0 <= i31 >>> 0 | i32 >>> 0 > i24 >>> 0) : 0) {
+  i32 = 0;
+  STACKTOP = i1;
+  return i32 | 0;
+ }
+ L269 : do {
+  if ((HEAP32[14916 >> 2] & 4 | 0) == 0) {
+   i26 = HEAP32[14496 >> 2] | 0;
+   L271 : do {
+    if ((i26 | 0) != 0) {
+     i24 = 14920 | 0;
+     while (1) {
+      i27 = HEAP32[i24 >> 2] | 0;
+      if (!(i27 >>> 0 > i26 >>> 0) ? (i23 = i24 + 4 | 0, (i27 + (HEAP32[i23 >> 2] | 0) | 0) >>> 0 > i26 >>> 0) : 0) {
+       break;
+      }
+      i24 = HEAP32[i24 + 8 >> 2] | 0;
+      if ((i24 | 0) == 0) {
+       i13 = 182;
+       break L271;
+      }
+     }
+     if ((i24 | 0) != 0) {
+      i25 = i22 - (HEAP32[14484 >> 2] | 0) & i25;
+      if (i25 >>> 0 < 2147483647) {
+       i13 = _sbrk(i25 | 0) | 0;
+       i26 = (i13 | 0) == ((HEAP32[i24 >> 2] | 0) + (HEAP32[i23 >> 2] | 0) | 0);
+       i22 = i13;
+       i24 = i25;
+       i23 = i26 ? i13 : -1;
+       i25 = i26 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i13 = 182;
+     }
+    } else {
+     i13 = 182;
+    }
+   } while (0);
+   do {
+    if ((i13 | 0) == 182) {
+     i23 = _sbrk(0) | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i24 = i23;
+      i22 = HEAP32[14948 >> 2] | 0;
+      i25 = i22 + -1 | 0;
+      if ((i25 & i24 | 0) == 0) {
+       i25 = i18;
+      } else {
+       i25 = i18 - i24 + (i25 + i24 & 0 - i22) | 0;
+      }
+      i24 = HEAP32[14904 >> 2] | 0;
+      i26 = i24 + i25 | 0;
+      if (i25 >>> 0 > i12 >>> 0 & i25 >>> 0 < 2147483647) {
+       i22 = HEAP32[14912 >> 2] | 0;
+       if ((i22 | 0) != 0 ? i26 >>> 0 <= i24 >>> 0 | i26 >>> 0 > i22 >>> 0 : 0) {
+        i25 = 0;
+        break;
+       }
+       i22 = _sbrk(i25 | 0) | 0;
+       i13 = (i22 | 0) == (i23 | 0);
+       i24 = i25;
+       i23 = i13 ? i23 : -1;
+       i25 = i13 ? i25 : 0;
+       i13 = 191;
+      } else {
+       i25 = 0;
+      }
+     } else {
+      i25 = 0;
+     }
+    }
+   } while (0);
+   L291 : do {
+    if ((i13 | 0) == 191) {
+     i13 = 0 - i24 | 0;
+     if ((i23 | 0) != (-1 | 0)) {
+      i17 = i23;
+      i14 = i25;
+      i13 = 202;
+      break L269;
+     }
+     do {
+      if ((i22 | 0) != (-1 | 0) & i24 >>> 0 < 2147483647 & i24 >>> 0 < i20 >>> 0 ? (i19 = HEAP32[14952 >> 2] | 0, i19 = i21 - i24 + i19 & 0 - i19, i19 >>> 0 < 2147483647) : 0) {
+       if ((_sbrk(i19 | 0) | 0) == (-1 | 0)) {
+        _sbrk(i13 | 0) | 0;
+        break L291;
+       } else {
+        i24 = i19 + i24 | 0;
+        break;
+       }
+      }
+     } while (0);
+     if ((i22 | 0) != (-1 | 0)) {
+      i17 = i22;
+      i14 = i24;
+      i13 = 202;
+      break L269;
+     }
+    }
+   } while (0);
+   HEAP32[14916 >> 2] = HEAP32[14916 >> 2] | 4;
+   i13 = 199;
+  } else {
+   i25 = 0;
+   i13 = 199;
+  }
+ } while (0);
+ if ((((i13 | 0) == 199 ? i18 >>> 0 < 2147483647 : 0) ? (i17 = _sbrk(i18 | 0) | 0, i16 = _sbrk(0) | 0, (i16 | 0) != (-1 | 0) & (i17 | 0) != (-1 | 0) & i17 >>> 0 < i16 >>> 0) : 0) ? (i15 = i16 - i17 | 0, i14 = i15 >>> 0 > (i12 + 40 | 0) >>> 0, i14) : 0) {
+  i14 = i14 ? i15 : i25;
+  i13 = 202;
+ }
+ if ((i13 | 0) == 202) {
+  i15 = (HEAP32[14904 >> 2] | 0) + i14 | 0;
+  HEAP32[14904 >> 2] = i15;
+  if (i15 >>> 0 > (HEAP32[14908 >> 2] | 0) >>> 0) {
+   HEAP32[14908 >> 2] = i15;
+  }
+  i15 = HEAP32[14496 >> 2] | 0;
+  L311 : do {
+   if ((i15 | 0) != 0) {
+    i21 = 14920 | 0;
+    while (1) {
+     i16 = HEAP32[i21 >> 2] | 0;
+     i19 = i21 + 4 | 0;
+     i20 = HEAP32[i19 >> 2] | 0;
+     if ((i17 | 0) == (i16 + i20 | 0)) {
+      i13 = 214;
+      break;
+     }
+     i18 = HEAP32[i21 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i21 = i18;
+     }
+    }
+    if (((i13 | 0) == 214 ? (HEAP32[i21 + 12 >> 2] & 8 | 0) == 0 : 0) ? i15 >>> 0 >= i16 >>> 0 & i15 >>> 0 < i17 >>> 0 : 0) {
+     HEAP32[i19 >> 2] = i20 + i14;
+     i2 = (HEAP32[14484 >> 2] | 0) + i14 | 0;
+     i3 = i15 + 8 | 0;
+     if ((i3 & 7 | 0) == 0) {
+      i3 = 0;
+     } else {
+      i3 = 0 - i3 & 7;
+     }
+     i32 = i2 - i3 | 0;
+     HEAP32[14496 >> 2] = i15 + i3;
+     HEAP32[14484 >> 2] = i32;
+     HEAP32[i15 + (i3 + 4) >> 2] = i32 | 1;
+     HEAP32[i15 + (i2 + 4) >> 2] = 40;
+     HEAP32[14500 >> 2] = HEAP32[14960 >> 2];
+     break;
+    }
+    if (i17 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+     HEAP32[14488 >> 2] = i17;
+    }
+    i19 = i17 + i14 | 0;
+    i16 = 14920 | 0;
+    while (1) {
+     if ((HEAP32[i16 >> 2] | 0) == (i19 | 0)) {
+      i13 = 224;
+      break;
+     }
+     i18 = HEAP32[i16 + 8 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      break;
+     } else {
+      i16 = i18;
+     }
+    }
+    if ((i13 | 0) == 224 ? (HEAP32[i16 + 12 >> 2] & 8 | 0) == 0 : 0) {
+     HEAP32[i16 >> 2] = i17;
+     i6 = i16 + 4 | 0;
+     HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i14;
+     i6 = i17 + 8 | 0;
+     if ((i6 & 7 | 0) == 0) {
+      i6 = 0;
+     } else {
+      i6 = 0 - i6 & 7;
+     }
+     i7 = i17 + (i14 + 8) | 0;
+     if ((i7 & 7 | 0) == 0) {
+      i13 = 0;
+     } else {
+      i13 = 0 - i7 & 7;
+     }
+     i15 = i17 + (i13 + i14) | 0;
+     i8 = i6 + i12 | 0;
+     i7 = i17 + i8 | 0;
+     i10 = i15 - (i17 + i6) - i12 | 0;
+     HEAP32[i17 + (i6 + 4) >> 2] = i12 | 3;
+     L348 : do {
+      if ((i15 | 0) != (HEAP32[14496 >> 2] | 0)) {
+       if ((i15 | 0) == (HEAP32[14492 >> 2] | 0)) {
+        i32 = (HEAP32[14480 >> 2] | 0) + i10 | 0;
+        HEAP32[14480 >> 2] = i32;
+        HEAP32[14492 >> 2] = i7;
+        HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+        HEAP32[i17 + (i32 + i8) >> 2] = i32;
+        break;
+       }
+       i12 = i14 + 4 | 0;
+       i18 = HEAP32[i17 + (i12 + i13) >> 2] | 0;
+       if ((i18 & 3 | 0) == 1) {
+        i11 = i18 & -8;
+        i16 = i18 >>> 3;
+        do {
+         if (!(i18 >>> 0 < 256)) {
+          i9 = HEAP32[i17 + ((i13 | 24) + i14) >> 2] | 0;
+          i19 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          do {
+           if ((i19 | 0) == (i15 | 0)) {
+            i19 = i13 | 16;
+            i18 = i17 + (i12 + i19) | 0;
+            i16 = HEAP32[i18 >> 2] | 0;
+            if ((i16 | 0) == 0) {
+             i18 = i17 + (i19 + i14) | 0;
+             i16 = HEAP32[i18 >> 2] | 0;
+             if ((i16 | 0) == 0) {
+              i5 = 0;
+              break;
+             }
+            }
+            while (1) {
+             i20 = i16 + 20 | 0;
+             i19 = HEAP32[i20 >> 2] | 0;
+             if ((i19 | 0) != 0) {
+              i16 = i19;
+              i18 = i20;
+              continue;
+             }
+             i19 = i16 + 16 | 0;
+             i20 = HEAP32[i19 >> 2] | 0;
+             if ((i20 | 0) == 0) {
+              break;
+             } else {
+              i16 = i20;
+              i18 = i19;
+             }
+            }
+            if (i18 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i18 >> 2] = 0;
+             i5 = i16;
+             break;
+            }
+           } else {
+            i18 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+            if (i18 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i18 + 12 | 0;
+            if ((HEAP32[i16 >> 2] | 0) != (i15 | 0)) {
+             _abort();
+            }
+            i20 = i19 + 8 | 0;
+            if ((HEAP32[i20 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i19;
+             HEAP32[i20 >> 2] = i18;
+             i5 = i19;
+             break;
+            } else {
+             _abort();
+            }
+           }
+          } while (0);
+          if ((i9 | 0) != 0) {
+           i16 = HEAP32[i17 + (i14 + 28 + i13) >> 2] | 0;
+           i18 = 14776 + (i16 << 2) | 0;
+           if ((i15 | 0) == (HEAP32[i18 >> 2] | 0)) {
+            HEAP32[i18 >> 2] = i5;
+            if ((i5 | 0) == 0) {
+             HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i16);
+             break;
+            }
+           } else {
+            if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+             _abort();
+            }
+            i16 = i9 + 16 | 0;
+            if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+             HEAP32[i16 >> 2] = i5;
+            } else {
+             HEAP32[i9 + 20 >> 2] = i5;
+            }
+            if ((i5 | 0) == 0) {
+             break;
+            }
+           }
+           if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           HEAP32[i5 + 24 >> 2] = i9;
+           i15 = i13 | 16;
+           i9 = HEAP32[i17 + (i15 + i14) >> 2] | 0;
+           do {
+            if ((i9 | 0) != 0) {
+             if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+              _abort();
+             } else {
+              HEAP32[i5 + 16 >> 2] = i9;
+              HEAP32[i9 + 24 >> 2] = i5;
+              break;
+             }
+            }
+           } while (0);
+           i9 = HEAP32[i17 + (i12 + i15) >> 2] | 0;
+           if ((i9 | 0) != 0) {
+            if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+             _abort();
+            } else {
+             HEAP32[i5 + 20 >> 2] = i9;
+             HEAP32[i9 + 24 >> 2] = i5;
+             break;
+            }
+           }
+          }
+         } else {
+          i5 = HEAP32[i17 + ((i13 | 8) + i14) >> 2] | 0;
+          i12 = HEAP32[i17 + (i14 + 12 + i13) >> 2] | 0;
+          i18 = 14512 + (i16 << 1 << 2) | 0;
+          if ((i5 | 0) != (i18 | 0)) {
+           if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           if ((HEAP32[i5 + 12 >> 2] | 0) != (i15 | 0)) {
+            _abort();
+           }
+          }
+          if ((i12 | 0) == (i5 | 0)) {
+           HEAP32[3618] = HEAP32[3618] & ~(1 << i16);
+           break;
+          }
+          if ((i12 | 0) != (i18 | 0)) {
+           if (i12 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+            _abort();
+           }
+           i16 = i12 + 8 | 0;
+           if ((HEAP32[i16 >> 2] | 0) == (i15 | 0)) {
+            i9 = i16;
+           } else {
+            _abort();
+           }
+          } else {
+           i9 = i12 + 8 | 0;
+          }
+          HEAP32[i5 + 12 >> 2] = i12;
+          HEAP32[i9 >> 2] = i5;
+         }
+        } while (0);
+        i15 = i17 + ((i11 | i13) + i14) | 0;
+        i10 = i11 + i10 | 0;
+       }
+       i5 = i15 + 4 | 0;
+       HEAP32[i5 >> 2] = HEAP32[i5 >> 2] & -2;
+       HEAP32[i17 + (i8 + 4) >> 2] = i10 | 1;
+       HEAP32[i17 + (i10 + i8) >> 2] = i10;
+       i5 = i10 >>> 3;
+       if (i10 >>> 0 < 256) {
+        i10 = i5 << 1;
+        i2 = 14512 + (i10 << 2) | 0;
+        i9 = HEAP32[3618] | 0;
+        i5 = 1 << i5;
+        if ((i9 & i5 | 0) != 0) {
+         i9 = 14512 + (i10 + 2 << 2) | 0;
+         i5 = HEAP32[i9 >> 2] | 0;
+         if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          i3 = i9;
+          i4 = i5;
+         }
+        } else {
+         HEAP32[3618] = i9 | i5;
+         i3 = 14512 + (i10 + 2 << 2) | 0;
+         i4 = i2;
+        }
+        HEAP32[i3 >> 2] = i7;
+        HEAP32[i4 + 12 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        break;
+       }
+       i3 = i10 >>> 8;
+       if ((i3 | 0) != 0) {
+        if (i10 >>> 0 > 16777215) {
+         i3 = 31;
+        } else {
+         i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+         i32 = i3 << i31;
+         i30 = (i32 + 520192 | 0) >>> 16 & 4;
+         i32 = i32 << i30;
+         i3 = (i32 + 245760 | 0) >>> 16 & 2;
+         i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+         i3 = i10 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+        }
+       } else {
+        i3 = 0;
+       }
+       i4 = 14776 + (i3 << 2) | 0;
+       HEAP32[i17 + (i8 + 28) >> 2] = i3;
+       HEAP32[i17 + (i8 + 20) >> 2] = 0;
+       HEAP32[i17 + (i8 + 16) >> 2] = 0;
+       i9 = HEAP32[14476 >> 2] | 0;
+       i5 = 1 << i3;
+       if ((i9 & i5 | 0) == 0) {
+        HEAP32[14476 >> 2] = i9 | i5;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 24) >> 2] = i4;
+        HEAP32[i17 + (i8 + 12) >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i7;
+        break;
+       }
+       i4 = HEAP32[i4 >> 2] | 0;
+       if ((i3 | 0) == 31) {
+        i3 = 0;
+       } else {
+        i3 = 25 - (i3 >>> 1) | 0;
+       }
+       L444 : do {
+        if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i10 | 0)) {
+         i3 = i10 << i3;
+         while (1) {
+          i5 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+          i9 = HEAP32[i5 >> 2] | 0;
+          if ((i9 | 0) == 0) {
+           break;
+          }
+          if ((HEAP32[i9 + 4 >> 2] & -8 | 0) == (i10 | 0)) {
+           i2 = i9;
+           break L444;
+          } else {
+           i3 = i3 << 1;
+           i4 = i9;
+          }
+         }
+         if (i5 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+          _abort();
+         } else {
+          HEAP32[i5 >> 2] = i7;
+          HEAP32[i17 + (i8 + 24) >> 2] = i4;
+          HEAP32[i17 + (i8 + 12) >> 2] = i7;
+          HEAP32[i17 + (i8 + 8) >> 2] = i7;
+          break L348;
+         }
+        } else {
+         i2 = i4;
+        }
+       } while (0);
+       i4 = i2 + 8 | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       i5 = HEAP32[14488 >> 2] | 0;
+       if (i2 >>> 0 < i5 >>> 0) {
+        _abort();
+       }
+       if (i3 >>> 0 < i5 >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i3 + 12 >> 2] = i7;
+        HEAP32[i4 >> 2] = i7;
+        HEAP32[i17 + (i8 + 8) >> 2] = i3;
+        HEAP32[i17 + (i8 + 12) >> 2] = i2;
+        HEAP32[i17 + (i8 + 24) >> 2] = 0;
+        break;
+       }
+      } else {
+       i32 = (HEAP32[14484 >> 2] | 0) + i10 | 0;
+       HEAP32[14484 >> 2] = i32;
+       HEAP32[14496 >> 2] = i7;
+       HEAP32[i17 + (i8 + 4) >> 2] = i32 | 1;
+      }
+     } while (0);
+     i32 = i17 + (i6 | 8) | 0;
+     STACKTOP = i1;
+     return i32 | 0;
+    }
+    i3 = 14920 | 0;
+    while (1) {
+     i2 = HEAP32[i3 >> 2] | 0;
+     if (!(i2 >>> 0 > i15 >>> 0) ? (i11 = HEAP32[i3 + 4 >> 2] | 0, i10 = i2 + i11 | 0, i10 >>> 0 > i15 >>> 0) : 0) {
+      break;
+     }
+     i3 = HEAP32[i3 + 8 >> 2] | 0;
+    }
+    i3 = i2 + (i11 + -39) | 0;
+    if ((i3 & 7 | 0) == 0) {
+     i3 = 0;
+    } else {
+     i3 = 0 - i3 & 7;
+    }
+    i2 = i2 + (i11 + -47 + i3) | 0;
+    i2 = i2 >>> 0 < (i15 + 16 | 0) >>> 0 ? i15 : i2;
+    i3 = i2 + 8 | 0;
+    i4 = i17 + 8 | 0;
+    if ((i4 & 7 | 0) == 0) {
+     i4 = 0;
+    } else {
+     i4 = 0 - i4 & 7;
+    }
+    i32 = i14 + -40 - i4 | 0;
+    HEAP32[14496 >> 2] = i17 + i4;
+    HEAP32[14484 >> 2] = i32;
+    HEAP32[i17 + (i4 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[14500 >> 2] = HEAP32[14960 >> 2];
+    HEAP32[i2 + 4 >> 2] = 27;
+    HEAP32[i3 + 0 >> 2] = HEAP32[14920 >> 2];
+    HEAP32[i3 + 4 >> 2] = HEAP32[14924 >> 2];
+    HEAP32[i3 + 8 >> 2] = HEAP32[14928 >> 2];
+    HEAP32[i3 + 12 >> 2] = HEAP32[14932 >> 2];
+    HEAP32[14920 >> 2] = i17;
+    HEAP32[14924 >> 2] = i14;
+    HEAP32[14932 >> 2] = 0;
+    HEAP32[14928 >> 2] = i3;
+    i4 = i2 + 28 | 0;
+    HEAP32[i4 >> 2] = 7;
+    if ((i2 + 32 | 0) >>> 0 < i10 >>> 0) {
+     while (1) {
+      i3 = i4 + 4 | 0;
+      HEAP32[i3 >> 2] = 7;
+      if ((i4 + 8 | 0) >>> 0 < i10 >>> 0) {
+       i4 = i3;
+      } else {
+       break;
+      }
+     }
+    }
+    if ((i2 | 0) != (i15 | 0)) {
+     i2 = i2 - i15 | 0;
+     i3 = i15 + (i2 + 4) | 0;
+     HEAP32[i3 >> 2] = HEAP32[i3 >> 2] & -2;
+     HEAP32[i15 + 4 >> 2] = i2 | 1;
+     HEAP32[i15 + i2 >> 2] = i2;
+     i3 = i2 >>> 3;
+     if (i2 >>> 0 < 256) {
+      i4 = i3 << 1;
+      i2 = 14512 + (i4 << 2) | 0;
+      i5 = HEAP32[3618] | 0;
+      i3 = 1 << i3;
+      if ((i5 & i3 | 0) != 0) {
+       i4 = 14512 + (i4 + 2 << 2) | 0;
+       i3 = HEAP32[i4 >> 2] | 0;
+       if (i3 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        i7 = i4;
+        i8 = i3;
+       }
+      } else {
+       HEAP32[3618] = i5 | i3;
+       i7 = 14512 + (i4 + 2 << 2) | 0;
+       i8 = i2;
+      }
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i8 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i8;
+      HEAP32[i15 + 12 >> 2] = i2;
+      break;
+     }
+     i3 = i2 >>> 8;
+     if ((i3 | 0) != 0) {
+      if (i2 >>> 0 > 16777215) {
+       i3 = 31;
+      } else {
+       i31 = (i3 + 1048320 | 0) >>> 16 & 8;
+       i32 = i3 << i31;
+       i30 = (i32 + 520192 | 0) >>> 16 & 4;
+       i32 = i32 << i30;
+       i3 = (i32 + 245760 | 0) >>> 16 & 2;
+       i3 = 14 - (i30 | i31 | i3) + (i32 << i3 >>> 15) | 0;
+       i3 = i2 >>> (i3 + 7 | 0) & 1 | i3 << 1;
+      }
+     } else {
+      i3 = 0;
+     }
+     i7 = 14776 + (i3 << 2) | 0;
+     HEAP32[i15 + 28 >> 2] = i3;
+     HEAP32[i15 + 20 >> 2] = 0;
+     HEAP32[i15 + 16 >> 2] = 0;
+     i4 = HEAP32[14476 >> 2] | 0;
+     i5 = 1 << i3;
+     if ((i4 & i5 | 0) == 0) {
+      HEAP32[14476 >> 2] = i4 | i5;
+      HEAP32[i7 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i7;
+      HEAP32[i15 + 12 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i15;
+      break;
+     }
+     i4 = HEAP32[i7 >> 2] | 0;
+     if ((i3 | 0) == 31) {
+      i3 = 0;
+     } else {
+      i3 = 25 - (i3 >>> 1) | 0;
+     }
+     L499 : do {
+      if ((HEAP32[i4 + 4 >> 2] & -8 | 0) != (i2 | 0)) {
+       i3 = i2 << i3;
+       while (1) {
+        i7 = i4 + (i3 >>> 31 << 2) + 16 | 0;
+        i5 = HEAP32[i7 >> 2] | 0;
+        if ((i5 | 0) == 0) {
+         break;
+        }
+        if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i2 | 0)) {
+         i6 = i5;
+         break L499;
+        } else {
+         i3 = i3 << 1;
+         i4 = i5;
+        }
+       }
+       if (i7 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i7 >> 2] = i15;
+        HEAP32[i15 + 24 >> 2] = i4;
+        HEAP32[i15 + 12 >> 2] = i15;
+        HEAP32[i15 + 8 >> 2] = i15;
+        break L311;
+       }
+      } else {
+       i6 = i4;
+      }
+     } while (0);
+     i4 = i6 + 8 | 0;
+     i3 = HEAP32[i4 >> 2] | 0;
+     i2 = HEAP32[14488 >> 2] | 0;
+     if (i6 >>> 0 < i2 >>> 0) {
+      _abort();
+     }
+     if (i3 >>> 0 < i2 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i3 + 12 >> 2] = i15;
+      HEAP32[i4 >> 2] = i15;
+      HEAP32[i15 + 8 >> 2] = i3;
+      HEAP32[i15 + 12 >> 2] = i6;
+      HEAP32[i15 + 24 >> 2] = 0;
+      break;
+     }
+    }
+   } else {
+    i32 = HEAP32[14488 >> 2] | 0;
+    if ((i32 | 0) == 0 | i17 >>> 0 < i32 >>> 0) {
+     HEAP32[14488 >> 2] = i17;
+    }
+    HEAP32[14920 >> 2] = i17;
+    HEAP32[14924 >> 2] = i14;
+    HEAP32[14932 >> 2] = 0;
+    HEAP32[14508 >> 2] = HEAP32[3736];
+    HEAP32[14504 >> 2] = -1;
+    i2 = 0;
+    do {
+     i32 = i2 << 1;
+     i31 = 14512 + (i32 << 2) | 0;
+     HEAP32[14512 + (i32 + 3 << 2) >> 2] = i31;
+     HEAP32[14512 + (i32 + 2 << 2) >> 2] = i31;
+     i2 = i2 + 1 | 0;
+    } while ((i2 | 0) != 32);
+    i2 = i17 + 8 | 0;
+    if ((i2 & 7 | 0) == 0) {
+     i2 = 0;
+    } else {
+     i2 = 0 - i2 & 7;
+    }
+    i32 = i14 + -40 - i2 | 0;
+    HEAP32[14496 >> 2] = i17 + i2;
+    HEAP32[14484 >> 2] = i32;
+    HEAP32[i17 + (i2 + 4) >> 2] = i32 | 1;
+    HEAP32[i17 + (i14 + -36) >> 2] = 40;
+    HEAP32[14500 >> 2] = HEAP32[14960 >> 2];
+   }
+  } while (0);
+  i2 = HEAP32[14484 >> 2] | 0;
+  if (i2 >>> 0 > i12 >>> 0) {
+   i31 = i2 - i12 | 0;
+   HEAP32[14484 >> 2] = i31;
+   i32 = HEAP32[14496 >> 2] | 0;
+   HEAP32[14496 >> 2] = i32 + i12;
+   HEAP32[i32 + (i12 + 4) >> 2] = i31 | 1;
+   HEAP32[i32 + 4 >> 2] = i12 | 3;
+   i32 = i32 + 8 | 0;
+   STACKTOP = i1;
+   return i32 | 0;
+  }
+ }
+ HEAP32[(___errno_location() | 0) >> 2] = 12;
+ i32 = 0;
+ STACKTOP = i1;
+ return i32 | 0;
+}
+function _deflate(i2, i10) {
+ i2 = i2 | 0;
+ i10 = i10 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0;
+ i1 = STACKTOP;
+ if ((i2 | 0) == 0) {
+  i37 = -2;
+  STACKTOP = i1;
+  return i37 | 0;
+ }
+ i5 = i2 + 28 | 0;
+ i7 = HEAP32[i5 >> 2] | 0;
+ if ((i7 | 0) == 0 | i10 >>> 0 > 5) {
+  i37 = -2;
+  STACKTOP = i1;
+  return i37 | 0;
+ }
+ i4 = i2 + 12 | 0;
+ do {
+  if ((HEAP32[i4 >> 2] | 0) != 0) {
+   if ((HEAP32[i2 >> 2] | 0) == 0 ? (HEAP32[i2 + 4 >> 2] | 0) != 0 : 0) {
+    break;
+   }
+   i11 = i7 + 4 | 0;
+   i29 = HEAP32[i11 >> 2] | 0;
+   i9 = (i10 | 0) == 4;
+   if ((i29 | 0) != 666 | i9) {
+    i3 = i2 + 16 | 0;
+    if ((HEAP32[i3 >> 2] | 0) == 0) {
+     HEAP32[i2 + 24 >> 2] = HEAP32[3180 >> 2];
+     i37 = -5;
+     STACKTOP = i1;
+     return i37 | 0;
+    }
+    HEAP32[i7 >> 2] = i2;
+    i8 = i7 + 40 | 0;
+    i18 = HEAP32[i8 >> 2] | 0;
+    HEAP32[i8 >> 2] = i10;
+    do {
+     if ((i29 | 0) == 42) {
+      if ((HEAP32[i7 + 24 >> 2] | 0) != 2) {
+       i17 = (HEAP32[i7 + 48 >> 2] << 12) + -30720 | 0;
+       if ((HEAP32[i7 + 136 >> 2] | 0) <= 1 ? (i28 = HEAP32[i7 + 132 >> 2] | 0, (i28 | 0) >= 2) : 0) {
+        if ((i28 | 0) < 6) {
+         i28 = 64;
+        } else {
+         i28 = (i28 | 0) == 6 ? 128 : 192;
+        }
+       } else {
+        i28 = 0;
+       }
+       i28 = i28 | i17;
+       i17 = i7 + 108 | 0;
+       i37 = (HEAP32[i17 >> 2] | 0) == 0 ? i28 : i28 | 32;
+       HEAP32[i11 >> 2] = 113;
+       i29 = i7 + 20 | 0;
+       i30 = HEAP32[i29 >> 2] | 0;
+       HEAP32[i29 >> 2] = i30 + 1;
+       i28 = i7 + 8 | 0;
+       HEAP8[(HEAP32[i28 >> 2] | 0) + i30 | 0] = i37 >>> 8;
+       i30 = HEAP32[i29 >> 2] | 0;
+       HEAP32[i29 >> 2] = i30 + 1;
+       HEAP8[(HEAP32[i28 >> 2] | 0) + i30 | 0] = (i37 | ((i37 >>> 0) % 31 | 0)) ^ 31;
+       i30 = i2 + 48 | 0;
+       if ((HEAP32[i17 >> 2] | 0) != 0) {
+        i37 = HEAP32[i30 >> 2] | 0;
+        i36 = HEAP32[i29 >> 2] | 0;
+        HEAP32[i29 >> 2] = i36 + 1;
+        HEAP8[(HEAP32[i28 >> 2] | 0) + i36 | 0] = i37 >>> 24;
+        i36 = HEAP32[i29 >> 2] | 0;
+        HEAP32[i29 >> 2] = i36 + 1;
+        HEAP8[(HEAP32[i28 >> 2] | 0) + i36 | 0] = i37 >>> 16;
+        i36 = HEAP32[i30 >> 2] | 0;
+        i37 = HEAP32[i29 >> 2] | 0;
+        HEAP32[i29 >> 2] = i37 + 1;
+        HEAP8[(HEAP32[i28 >> 2] | 0) + i37 | 0] = i36 >>> 8;
+        i37 = HEAP32[i29 >> 2] | 0;
+        HEAP32[i29 >> 2] = i37 + 1;
+        HEAP8[(HEAP32[i28 >> 2] | 0) + i37 | 0] = i36;
+       }
+       HEAP32[i30 >> 2] = _adler32(0, 0, 0) | 0;
+       i31 = HEAP32[i11 >> 2] | 0;
+       i17 = 32;
+       break;
+      }
+      i32 = i2 + 48 | 0;
+      HEAP32[i32 >> 2] = _crc32(0, 0, 0) | 0;
+      i30 = i7 + 20 | 0;
+      i28 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i28 + 1;
+      i29 = i7 + 8 | 0;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i28 | 0] = 31;
+      i28 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i28 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i28 | 0] = -117;
+      i28 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i28 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i28 | 0] = 8;
+      i28 = i7 + 28 | 0;
+      i33 = HEAP32[i28 >> 2] | 0;
+      if ((i33 | 0) == 0) {
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i22 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i22 | 0] = 0;
+       i22 = HEAP32[i7 + 132 >> 2] | 0;
+       if ((i22 | 0) != 9) {
+        if ((HEAP32[i7 + 136 >> 2] | 0) > 1) {
+         i22 = 4;
+        } else {
+         i22 = (i22 | 0) < 2 ? 4 : 0;
+        }
+       } else {
+        i22 = 2;
+       }
+       i37 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i37 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i22;
+       i37 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i37 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = 3;
+       HEAP32[i11 >> 2] = 113;
+       break;
+      }
+      i37 = (((HEAP32[i33 + 44 >> 2] | 0) != 0 ? 2 : 0) | (HEAP32[i33 >> 2] | 0) != 0 | ((HEAP32[i33 + 16 >> 2] | 0) == 0 ? 0 : 4) | ((HEAP32[i33 + 28 >> 2] | 0) == 0 ? 0 : 8) | ((HEAP32[i33 + 36 >> 2] | 0) == 0 ? 0 : 16)) & 255;
+      i17 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+      i17 = HEAP32[(HEAP32[i28 >> 2] | 0) + 4 >> 2] & 255;
+      i37 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i37 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i17;
+      i37 = (HEAP32[(HEAP32[i28 >> 2] | 0) + 4 >> 2] | 0) >>> 8 & 255;
+      i17 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+      i17 = (HEAP32[(HEAP32[i28 >> 2] | 0) + 4 >> 2] | 0) >>> 16 & 255;
+      i37 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i37 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i17;
+      i37 = (HEAP32[(HEAP32[i28 >> 2] | 0) + 4 >> 2] | 0) >>> 24 & 255;
+      i17 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+      i17 = HEAP32[i7 + 132 >> 2] | 0;
+      if ((i17 | 0) != 9) {
+       if ((HEAP32[i7 + 136 >> 2] | 0) > 1) {
+        i17 = 4;
+       } else {
+        i17 = (i17 | 0) < 2 ? 4 : 0;
+       }
+      } else {
+       i17 = 2;
+      }
+      i37 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i37 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i17;
+      i37 = HEAP32[(HEAP32[i28 >> 2] | 0) + 12 >> 2] & 255;
+      i17 = HEAP32[i30 >> 2] | 0;
+      HEAP32[i30 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+      i17 = HEAP32[i28 >> 2] | 0;
+      if ((HEAP32[i17 + 16 >> 2] | 0) != 0) {
+       i17 = HEAP32[i17 + 20 >> 2] & 255;
+       i37 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i37 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i37 | 0] = i17;
+       i37 = (HEAP32[(HEAP32[i28 >> 2] | 0) + 20 >> 2] | 0) >>> 8 & 255;
+       i17 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i17 + 1;
+       HEAP8[(HEAP32[i29 >> 2] | 0) + i17 | 0] = i37;
+       i17 = HEAP32[i28 >> 2] | 0;
+      }
+      if ((HEAP32[i17 + 44 >> 2] | 0) != 0) {
+       HEAP32[i32 >> 2] = _crc32(HEAP32[i32 >> 2] | 0, HEAP32[i29 >> 2] | 0, HEAP32[i30 >> 2] | 0) | 0;
+      }
+      HEAP32[i7 + 32 >> 2] = 0;
+      HEAP32[i11 >> 2] = 69;
+      i17 = 34;
+     } else {
+      i31 = i29;
+      i17 = 32;
+     }
+    } while (0);
+    if ((i17 | 0) == 32) {
+     if ((i31 | 0) == 69) {
+      i28 = i7 + 28 | 0;
+      i17 = 34;
+     } else {
+      i17 = 55;
+     }
+    }
+    do {
+     if ((i17 | 0) == 34) {
+      i37 = HEAP32[i28 >> 2] | 0;
+      if ((HEAP32[i37 + 16 >> 2] | 0) == 0) {
+       HEAP32[i11 >> 2] = 73;
+       i17 = 57;
+       break;
+      }
+      i29 = i7 + 20 | 0;
+      i34 = HEAP32[i29 >> 2] | 0;
+      i17 = i7 + 32 | 0;
+      i36 = HEAP32[i17 >> 2] | 0;
+      L55 : do {
+       if (i36 >>> 0 < (HEAP32[i37 + 20 >> 2] & 65535) >>> 0) {
+        i30 = i7 + 12 | 0;
+        i32 = i2 + 48 | 0;
+        i31 = i7 + 8 | 0;
+        i33 = i2 + 20 | 0;
+        i35 = i34;
+        while (1) {
+         if ((i35 | 0) == (HEAP32[i30 >> 2] | 0)) {
+          if ((HEAP32[i37 + 44 >> 2] | 0) != 0 & i35 >>> 0 > i34 >>> 0) {
+           HEAP32[i32 >> 2] = _crc32(HEAP32[i32 >> 2] | 0, (HEAP32[i31 >> 2] | 0) + i34 | 0, i35 - i34 | 0) | 0;
+          }
+          i34 = HEAP32[i5 >> 2] | 0;
+          i35 = HEAP32[i34 + 20 >> 2] | 0;
+          i36 = HEAP32[i3 >> 2] | 0;
+          i35 = i35 >>> 0 > i36 >>> 0 ? i36 : i35;
+          if ((i35 | 0) != 0 ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i34 + 16 >> 2] | 0, i35 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i35, i27 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i27 >> 2] = (HEAP32[i27 >> 2] | 0) + i35, HEAP32[i33 >> 2] = (HEAP32[i33 >> 2] | 0) + i35, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i35, i27 = HEAP32[i5 >> 2] | 0, i36 = i27 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i35, (i37 | 0) == (i35 | 0)) : 0) {
+           HEAP32[i27 + 16 >> 2] = HEAP32[i27 + 8 >> 2];
+          }
+          i34 = HEAP32[i29 >> 2] | 0;
+          if ((i34 | 0) == (HEAP32[i30 >> 2] | 0)) {
+           break;
+          }
+          i37 = HEAP32[i28 >> 2] | 0;
+          i36 = HEAP32[i17 >> 2] | 0;
+          i35 = i34;
+         }
+         i36 = HEAP8[(HEAP32[i37 + 16 >> 2] | 0) + i36 | 0] | 0;
+         HEAP32[i29 >> 2] = i35 + 1;
+         HEAP8[(HEAP32[i31 >> 2] | 0) + i35 | 0] = i36;
+         i36 = (HEAP32[i17 >> 2] | 0) + 1 | 0;
+         HEAP32[i17 >> 2] = i36;
+         i37 = HEAP32[i28 >> 2] | 0;
+         if (!(i36 >>> 0 < (HEAP32[i37 + 20 >> 2] & 65535) >>> 0)) {
+          break L55;
+         }
+         i35 = HEAP32[i29 >> 2] | 0;
+        }
+        i37 = HEAP32[i28 >> 2] | 0;
+       }
+      } while (0);
+      if ((HEAP32[i37 + 44 >> 2] | 0) != 0 ? (i26 = HEAP32[i29 >> 2] | 0, i26 >>> 0 > i34 >>> 0) : 0) {
+       i37 = i2 + 48 | 0;
+       HEAP32[i37 >> 2] = _crc32(HEAP32[i37 >> 2] | 0, (HEAP32[i7 + 8 >> 2] | 0) + i34 | 0, i26 - i34 | 0) | 0;
+       i37 = HEAP32[i28 >> 2] | 0;
+      }
+      if ((HEAP32[i17 >> 2] | 0) == (HEAP32[i37 + 20 >> 2] | 0)) {
+       HEAP32[i17 >> 2] = 0;
+       HEAP32[i11 >> 2] = 73;
+       i17 = 57;
+       break;
+      } else {
+       i31 = HEAP32[i11 >> 2] | 0;
+       i17 = 55;
+       break;
+      }
+     }
+    } while (0);
+    if ((i17 | 0) == 55) {
+     if ((i31 | 0) == 73) {
+      i37 = HEAP32[i7 + 28 >> 2] | 0;
+      i17 = 57;
+     } else {
+      i17 = 76;
+     }
+    }
+    do {
+     if ((i17 | 0) == 57) {
+      i26 = i7 + 28 | 0;
+      if ((HEAP32[i37 + 28 >> 2] | 0) == 0) {
+       HEAP32[i11 >> 2] = 91;
+       i17 = 78;
+       break;
+      }
+      i27 = i7 + 20 | 0;
+      i35 = HEAP32[i27 >> 2] | 0;
+      i32 = i7 + 12 | 0;
+      i29 = i2 + 48 | 0;
+      i28 = i7 + 8 | 0;
+      i31 = i2 + 20 | 0;
+      i30 = i7 + 32 | 0;
+      i33 = i35;
+      while (1) {
+       if ((i33 | 0) == (HEAP32[i32 >> 2] | 0)) {
+        if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) != 0 & i33 >>> 0 > i35 >>> 0) {
+         HEAP32[i29 >> 2] = _crc32(HEAP32[i29 >> 2] | 0, (HEAP32[i28 >> 2] | 0) + i35 | 0, i33 - i35 | 0) | 0;
+        }
+        i33 = HEAP32[i5 >> 2] | 0;
+        i34 = HEAP32[i33 + 20 >> 2] | 0;
+        i35 = HEAP32[i3 >> 2] | 0;
+        i34 = i34 >>> 0 > i35 >>> 0 ? i35 : i34;
+        if ((i34 | 0) != 0 ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i33 + 16 >> 2] | 0, i34 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i34, i25 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i25 >> 2] = (HEAP32[i25 >> 2] | 0) + i34, HEAP32[i31 >> 2] = (HEAP32[i31 >> 2] | 0) + i34, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i34, i25 = HEAP32[i5 >> 2] | 0, i36 = i25 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i34, (i37 | 0) == (i34 | 0)) : 0) {
+         HEAP32[i25 + 16 >> 2] = HEAP32[i25 + 8 >> 2];
+        }
+        i35 = HEAP32[i27 >> 2] | 0;
+        if ((i35 | 0) == (HEAP32[i32 >> 2] | 0)) {
+         i25 = 1;
+         break;
+        } else {
+         i33 = i35;
+        }
+       }
+       i34 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i34 + 1;
+       i34 = HEAP8[(HEAP32[(HEAP32[i26 >> 2] | 0) + 28 >> 2] | 0) + i34 | 0] | 0;
+       HEAP32[i27 >> 2] = i33 + 1;
+       HEAP8[(HEAP32[i28 >> 2] | 0) + i33 | 0] = i34;
+       if (i34 << 24 >> 24 == 0) {
+        i17 = 68;
+        break;
+       }
+       i33 = HEAP32[i27 >> 2] | 0;
+      }
+      if ((i17 | 0) == 68) {
+       i25 = i34 & 255;
+      }
+      if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) != 0 ? (i24 = HEAP32[i27 >> 2] | 0, i24 >>> 0 > i35 >>> 0) : 0) {
+       HEAP32[i29 >> 2] = _crc32(HEAP32[i29 >> 2] | 0, (HEAP32[i28 >> 2] | 0) + i35 | 0, i24 - i35 | 0) | 0;
+      }
+      if ((i25 | 0) == 0) {
+       HEAP32[i30 >> 2] = 0;
+       HEAP32[i11 >> 2] = 91;
+       i17 = 78;
+       break;
+      } else {
+       i31 = HEAP32[i11 >> 2] | 0;
+       i17 = 76;
+       break;
+      }
+     }
+    } while (0);
+    if ((i17 | 0) == 76) {
+     if ((i31 | 0) == 91) {
+      i26 = i7 + 28 | 0;
+      i17 = 78;
+     } else {
+      i17 = 97;
+     }
+    }
+    do {
+     if ((i17 | 0) == 78) {
+      if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 36 >> 2] | 0) == 0) {
+       HEAP32[i11 >> 2] = 103;
+       i17 = 99;
+       break;
+      }
+      i24 = i7 + 20 | 0;
+      i32 = HEAP32[i24 >> 2] | 0;
+      i29 = i7 + 12 | 0;
+      i27 = i2 + 48 | 0;
+      i25 = i7 + 8 | 0;
+      i28 = i2 + 20 | 0;
+      i30 = i7 + 32 | 0;
+      i31 = i32;
+      while (1) {
+       if ((i31 | 0) == (HEAP32[i29 >> 2] | 0)) {
+        if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) != 0 & i31 >>> 0 > i32 >>> 0) {
+         HEAP32[i27 >> 2] = _crc32(HEAP32[i27 >> 2] | 0, (HEAP32[i25 >> 2] | 0) + i32 | 0, i31 - i32 | 0) | 0;
+        }
+        i31 = HEAP32[i5 >> 2] | 0;
+        i33 = HEAP32[i31 + 20 >> 2] | 0;
+        i32 = HEAP32[i3 >> 2] | 0;
+        i32 = i33 >>> 0 > i32 >>> 0 ? i32 : i33;
+        if ((i32 | 0) != 0 ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i31 + 16 >> 2] | 0, i32 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i32, i23 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i23 >> 2] = (HEAP32[i23 >> 2] | 0) + i32, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) + i32, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i32, i23 = HEAP32[i5 >> 2] | 0, i36 = i23 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i32, (i37 | 0) == (i32 | 0)) : 0) {
+         HEAP32[i23 + 16 >> 2] = HEAP32[i23 + 8 >> 2];
+        }
+        i32 = HEAP32[i24 >> 2] | 0;
+        if ((i32 | 0) == (HEAP32[i29 >> 2] | 0)) {
+         i23 = 1;
+         break;
+        } else {
+         i31 = i32;
+        }
+       }
+       i33 = HEAP32[i30 >> 2] | 0;
+       HEAP32[i30 >> 2] = i33 + 1;
+       i33 = HEAP8[(HEAP32[(HEAP32[i26 >> 2] | 0) + 36 >> 2] | 0) + i33 | 0] | 0;
+       HEAP32[i24 >> 2] = i31 + 1;
+       HEAP8[(HEAP32[i25 >> 2] | 0) + i31 | 0] = i33;
+       if (i33 << 24 >> 24 == 0) {
+        i17 = 89;
+        break;
+       }
+       i31 = HEAP32[i24 >> 2] | 0;
+      }
+      if ((i17 | 0) == 89) {
+       i23 = i33 & 255;
+      }
+      if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) != 0 ? (i22 = HEAP32[i24 >> 2] | 0, i22 >>> 0 > i32 >>> 0) : 0) {
+       HEAP32[i27 >> 2] = _crc32(HEAP32[i27 >> 2] | 0, (HEAP32[i25 >> 2] | 0) + i32 | 0, i22 - i32 | 0) | 0;
+      }
+      if ((i23 | 0) == 0) {
+       HEAP32[i11 >> 2] = 103;
+       i17 = 99;
+       break;
+      } else {
+       i31 = HEAP32[i11 >> 2] | 0;
+       i17 = 97;
+       break;
+      }
+     }
+    } while (0);
+    if ((i17 | 0) == 97 ? (i31 | 0) == 103 : 0) {
+     i26 = i7 + 28 | 0;
+     i17 = 99;
+    }
+    do {
+     if ((i17 | 0) == 99) {
+      if ((HEAP32[(HEAP32[i26 >> 2] | 0) + 44 >> 2] | 0) == 0) {
+       HEAP32[i11 >> 2] = 113;
+       break;
+      }
+      i17 = i7 + 20 | 0;
+      i22 = i7 + 12 | 0;
+      if ((((HEAP32[i17 >> 2] | 0) + 2 | 0) >>> 0 > (HEAP32[i22 >> 2] | 0) >>> 0 ? (i20 = HEAP32[i5 >> 2] | 0, i21 = HEAP32[i20 + 20 >> 2] | 0, i23 = HEAP32[i3 >> 2] | 0, i21 = i21 >>> 0 > i23 >>> 0 ? i23 : i21, (i21 | 0) != 0) : 0) ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i20 + 16 >> 2] | 0, i21 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i21, i19 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i19 >> 2] = (HEAP32[i19 >> 2] | 0) + i21, i19 = i2 + 20 | 0, HEAP32[i19 >> 2] = (HEAP32[i19 >> 2] | 0) + i21, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i21, i19 = HEAP32[i5 >> 2] | 0, i36 = i19 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i21, (i37 | 0) == (i21 | 0)) : 0) {
+       HEAP32[i19 + 16 >> 2] = HEAP32[i19 + 8 >> 2];
+      }
+      i19 = HEAP32[i17 >> 2] | 0;
+      if (!((i19 + 2 | 0) >>> 0 > (HEAP32[i22 >> 2] | 0) >>> 0)) {
+       i37 = i2 + 48 | 0;
+       i34 = HEAP32[i37 >> 2] & 255;
+       HEAP32[i17 >> 2] = i19 + 1;
+       i35 = i7 + 8 | 0;
+       HEAP8[(HEAP32[i35 >> 2] | 0) + i19 | 0] = i34;
+       i34 = (HEAP32[i37 >> 2] | 0) >>> 8 & 255;
+       i36 = HEAP32[i17 >> 2] | 0;
+       HEAP32[i17 >> 2] = i36 + 1;
+       HEAP8[(HEAP32[i35 >> 2] | 0) + i36 | 0] = i34;
+       HEAP32[i37 >> 2] = _crc32(0, 0, 0) | 0;
+       HEAP32[i11 >> 2] = 113;
+      }
+     }
+    } while (0);
+    i19 = i7 + 20 | 0;
+    if ((HEAP32[i19 >> 2] | 0) == 0) {
+     if ((HEAP32[i2 + 4 >> 2] | 0) == 0 ? (i18 | 0) >= (i10 | 0) & (i10 | 0) != 4 : 0) {
+      HEAP32[i2 + 24 >> 2] = HEAP32[3180 >> 2];
+      i37 = -5;
+      STACKTOP = i1;
+      return i37 | 0;
+     }
+    } else {
+     i17 = HEAP32[i5 >> 2] | 0;
+     i20 = HEAP32[i17 + 20 >> 2] | 0;
+     i18 = HEAP32[i3 >> 2] | 0;
+     i20 = i20 >>> 0 > i18 >>> 0 ? i18 : i20;
+     if ((i20 | 0) != 0) {
+      _memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i17 + 16 >> 2] | 0, i20 | 0) | 0;
+      HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i20;
+      i17 = (HEAP32[i5 >> 2] | 0) + 16 | 0;
+      HEAP32[i17 >> 2] = (HEAP32[i17 >> 2] | 0) + i20;
+      i17 = i2 + 20 | 0;
+      HEAP32[i17 >> 2] = (HEAP32[i17 >> 2] | 0) + i20;
+      HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i20;
+      i17 = HEAP32[i5 >> 2] | 0;
+      i36 = i17 + 20 | 0;
+      i37 = HEAP32[i36 >> 2] | 0;
+      HEAP32[i36 >> 2] = i37 - i20;
+      if ((i37 | 0) == (i20 | 0)) {
+       HEAP32[i17 + 16 >> 2] = HEAP32[i17 + 8 >> 2];
+      }
+      i18 = HEAP32[i3 >> 2] | 0;
+     }
+     if ((i18 | 0) == 0) {
+      HEAP32[i8 >> 2] = -1;
+      i37 = 0;
+      STACKTOP = i1;
+      return i37 | 0;
+     }
+    }
+    i18 = (HEAP32[i11 >> 2] | 0) == 666;
+    i17 = (HEAP32[i2 + 4 >> 2] | 0) == 0;
+    if (i18) {
+     if (i17) {
+      i17 = 121;
+     } else {
+      HEAP32[i2 + 24 >> 2] = HEAP32[3180 >> 2];
+      i37 = -5;
+      STACKTOP = i1;
+      return i37 | 0;
+     }
+    } else {
+     if (i17) {
+      i17 = 121;
+     } else {
+      i17 = 124;
+     }
+    }
+    do {
+     if ((i17 | 0) == 121) {
+      if ((HEAP32[i7 + 116 >> 2] | 0) == 0) {
+       if ((i10 | 0) != 0) {
+        if (i18) {
+         break;
+        } else {
+         i17 = 124;
+         break;
+        }
+       } else {
+        i37 = 0;
+        STACKTOP = i1;
+        return i37 | 0;
+       }
+      } else {
+       i17 = 124;
+      }
+     }
+    } while (0);
+    do {
+     if ((i17 | 0) == 124) {
+      i18 = HEAP32[i7 + 136 >> 2] | 0;
+      L185 : do {
+       if ((i18 | 0) == 2) {
+        i22 = i7 + 116 | 0;
+        i18 = i7 + 96 | 0;
+        i13 = i7 + 108 | 0;
+        i14 = i7 + 56 | 0;
+        i21 = i7 + 5792 | 0;
+        i20 = i7 + 5796 | 0;
+        i24 = i7 + 5784 | 0;
+        i23 = i7 + 5788 | 0;
+        i12 = i7 + 92 | 0;
+        while (1) {
+         if ((HEAP32[i22 >> 2] | 0) == 0 ? (_fill_window(i7), (HEAP32[i22 >> 2] | 0) == 0) : 0) {
+          break;
+         }
+         HEAP32[i18 >> 2] = 0;
+         i37 = HEAP8[(HEAP32[i14 >> 2] | 0) + (HEAP32[i13 >> 2] | 0) | 0] | 0;
+         i26 = HEAP32[i21 >> 2] | 0;
+         HEAP16[(HEAP32[i20 >> 2] | 0) + (i26 << 1) >> 1] = 0;
+         HEAP32[i21 >> 2] = i26 + 1;
+         HEAP8[(HEAP32[i24 >> 2] | 0) + i26 | 0] = i37;
+         i37 = i7 + ((i37 & 255) << 2) + 148 | 0;
+         HEAP16[i37 >> 1] = (HEAP16[i37 >> 1] | 0) + 1 << 16 >> 16;
+         i37 = (HEAP32[i21 >> 2] | 0) == ((HEAP32[i23 >> 2] | 0) + -1 | 0);
+         HEAP32[i22 >> 2] = (HEAP32[i22 >> 2] | 0) + -1;
+         i26 = (HEAP32[i13 >> 2] | 0) + 1 | 0;
+         HEAP32[i13 >> 2] = i26;
+         if (!i37) {
+          continue;
+         }
+         i25 = HEAP32[i12 >> 2] | 0;
+         if ((i25 | 0) > -1) {
+          i27 = (HEAP32[i14 >> 2] | 0) + i25 | 0;
+         } else {
+          i27 = 0;
+         }
+         __tr_flush_block(i7, i27, i26 - i25 | 0, 0);
+         HEAP32[i12 >> 2] = HEAP32[i13 >> 2];
+         i26 = HEAP32[i7 >> 2] | 0;
+         i25 = i26 + 28 | 0;
+         i27 = HEAP32[i25 >> 2] | 0;
+         i30 = HEAP32[i27 + 20 >> 2] | 0;
+         i28 = i26 + 16 | 0;
+         i29 = HEAP32[i28 >> 2] | 0;
+         i29 = i30 >>> 0 > i29 >>> 0 ? i29 : i30;
+         if ((i29 | 0) != 0 ? (i16 = i26 + 12 | 0, _memcpy(HEAP32[i16 >> 2] | 0, HEAP32[i27 + 16 >> 2] | 0, i29 | 0) | 0, HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) + i29, i16 = (HEAP32[i25 >> 2] | 0) + 16 | 0, HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) + i29, i16 = i26 + 20 | 0, HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) + i29, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) - i29, i16 = HEAP32[i25 >> 2] | 0, i36 = i16 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i29, (i37 | 0) == (i29 | 0)) : 0) {
+          HEAP32[i16 + 16 >> 2] = HEAP32[i16 + 8 >> 2];
+         }
+         if ((HEAP32[(HEAP32[i7 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+          break L185;
+         }
+        }
+        if ((i10 | 0) != 0) {
+         i16 = HEAP32[i12 >> 2] | 0;
+         if ((i16 | 0) > -1) {
+          i14 = (HEAP32[i14 >> 2] | 0) + i16 | 0;
+         } else {
+          i14 = 0;
+         }
+         __tr_flush_block(i7, i14, (HEAP32[i13 >> 2] | 0) - i16 | 0, i9 & 1);
+         HEAP32[i12 >> 2] = HEAP32[i13 >> 2];
+         i14 = HEAP32[i7 >> 2] | 0;
+         i13 = i14 + 28 | 0;
+         i12 = HEAP32[i13 >> 2] | 0;
+         i17 = HEAP32[i12 + 20 >> 2] | 0;
+         i16 = i14 + 16 | 0;
+         i18 = HEAP32[i16 >> 2] | 0;
+         i17 = i17 >>> 0 > i18 >>> 0 ? i18 : i17;
+         if ((i17 | 0) != 0 ? (i15 = i14 + 12 | 0, _memcpy(HEAP32[i15 >> 2] | 0, HEAP32[i12 + 16 >> 2] | 0, i17 | 0) | 0, HEAP32[i15 >> 2] = (HEAP32[i15 >> 2] | 0) + i17, i15 = (HEAP32[i13 >> 2] | 0) + 16 | 0, HEAP32[i15 >> 2] = (HEAP32[i15 >> 2] | 0) + i17, i15 = i14 + 20 | 0, HEAP32[i15 >> 2] = (HEAP32[i15 >> 2] | 0) + i17, HEAP32[i16 >> 2] = (HEAP32[i16 >> 2] | 0) - i17, i15 = HEAP32[i13 >> 2] | 0, i36 = i15 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i17, (i37 | 0) == (i17 | 0)) : 0) {
+          HEAP32[i15 + 16 >> 2] = HEAP32[i15 + 8 >> 2];
+         }
+         if ((HEAP32[(HEAP32[i7 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+          i12 = i9 ? 2 : 0;
+          i17 = 183;
+          break;
+         } else {
+          i12 = i9 ? 3 : 1;
+          i17 = 183;
+          break;
+         }
+        }
+       } else if ((i18 | 0) == 3) {
+        i27 = i7 + 116 | 0;
+        i26 = (i10 | 0) == 0;
+        i22 = i7 + 96 | 0;
+        i15 = i7 + 108 | 0;
+        i20 = i7 + 5792 | 0;
+        i24 = i7 + 5796 | 0;
+        i23 = i7 + 5784 | 0;
+        i21 = i7 + (HEAPU8[296] << 2) + 2440 | 0;
+        i25 = i7 + 5788 | 0;
+        i18 = i7 + 56 | 0;
+        i16 = i7 + 92 | 0;
+        while (1) {
+         i29 = HEAP32[i27 >> 2] | 0;
+         if (i29 >>> 0 < 258) {
+          _fill_window(i7);
+          i29 = HEAP32[i27 >> 2] | 0;
+          if (i29 >>> 0 < 258 & i26) {
+           break L185;
+          }
+          if ((i29 | 0) == 0) {
+           break;
+          }
+          HEAP32[i22 >> 2] = 0;
+          if (i29 >>> 0 > 2) {
+           i17 = 151;
+          } else {
+           i28 = HEAP32[i15 >> 2] | 0;
+           i17 = 166;
+          }
+         } else {
+          HEAP32[i22 >> 2] = 0;
+          i17 = 151;
+         }
+         if ((i17 | 0) == 151) {
+          i17 = 0;
+          i28 = HEAP32[i15 >> 2] | 0;
+          if ((i28 | 0) != 0) {
+           i31 = HEAP32[i18 >> 2] | 0;
+           i30 = HEAP8[i31 + (i28 + -1) | 0] | 0;
+           if ((i30 << 24 >> 24 == (HEAP8[i31 + i28 | 0] | 0) ? i30 << 24 >> 24 == (HEAP8[i31 + (i28 + 1) | 0] | 0) : 0) ? (i14 = i31 + (i28 + 2) | 0, i30 << 24 >> 24 == (HEAP8[i14] | 0)) : 0) {
+            i31 = i31 + (i28 + 258) | 0;
+            i32 = i14;
+            do {
+             i33 = i32 + 1 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 2 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 3 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 4 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 5 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 6 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i33 = i32 + 7 | 0;
+             if (!(i30 << 24 >> 24 == (HEAP8[i33] | 0))) {
+              i32 = i33;
+              break;
+             }
+             i32 = i32 + 8 | 0;
+            } while (i30 << 24 >> 24 == (HEAP8[i32] | 0) & i32 >>> 0 < i31 >>> 0);
+            i30 = i32 - i31 + 258 | 0;
+            i29 = i30 >>> 0 > i29 >>> 0 ? i29 : i30;
+            HEAP32[i22 >> 2] = i29;
+            if (i29 >>> 0 > 2) {
+             i29 = i29 + 253 | 0;
+             i28 = HEAP32[i20 >> 2] | 0;
+             HEAP16[(HEAP32[i24 >> 2] | 0) + (i28 << 1) >> 1] = 1;
+             HEAP32[i20 >> 2] = i28 + 1;
+             HEAP8[(HEAP32[i23 >> 2] | 0) + i28 | 0] = i29;
+             i29 = i7 + ((HEAPU8[808 + (i29 & 255) | 0] | 256) + 1 << 2) + 148 | 0;
+             HEAP16[i29 >> 1] = (HEAP16[i29 >> 1] | 0) + 1 << 16 >> 16;
+             HEAP16[i21 >> 1] = (HEAP16[i21 >> 1] | 0) + 1 << 16 >> 16;
+             i29 = (HEAP32[i20 >> 2] | 0) == ((HEAP32[i25 >> 2] | 0) + -1 | 0) | 0;
+             i28 = HEAP32[i22 >> 2] | 0;
+             HEAP32[i27 >> 2] = (HEAP32[i27 >> 2] | 0) - i28;
+             i28 = (HEAP32[i15 >> 2] | 0) + i28 | 0;
+             HEAP32[i15 >> 2] = i28;
+             HEAP32[i22 >> 2] = 0;
+            } else {
+             i17 = 166;
+            }
+           } else {
+            i17 = 166;
+           }
+          } else {
+           i28 = 0;
+           i17 = 166;
+          }
+         }
+         if ((i17 | 0) == 166) {
+          i17 = 0;
+          i29 = HEAP8[(HEAP32[i18 >> 2] | 0) + i28 | 0] | 0;
+          i28 = HEAP32[i20 >> 2] | 0;
+          HEAP16[(HEAP32[i24 >> 2] | 0) + (i28 << 1) >> 1] = 0;
+          HEAP32[i20 >> 2] = i28 + 1;
+          HEAP8[(HEAP32[i23 >> 2] | 0) + i28 | 0] = i29;
+          i29 = i7 + ((i29 & 255) << 2) + 148 | 0;
+          HEAP16[i29 >> 1] = (HEAP16[i29 >> 1] | 0) + 1 << 16 >> 16;
+          i29 = (HEAP32[i20 >> 2] | 0) == ((HEAP32[i25 >> 2] | 0) + -1 | 0) | 0;
+          HEAP32[i27 >> 2] = (HEAP32[i27 >> 2] | 0) + -1;
+          i28 = (HEAP32[i15 >> 2] | 0) + 1 | 0;
+          HEAP32[i15 >> 2] = i28;
+         }
+         if ((i29 | 0) == 0) {
+          continue;
+         }
+         i29 = HEAP32[i16 >> 2] | 0;
+         if ((i29 | 0) > -1) {
+          i30 = (HEAP32[i18 >> 2] | 0) + i29 | 0;
+         } else {
+          i30 = 0;
+         }
+         __tr_flush_block(i7, i30, i28 - i29 | 0, 0);
+         HEAP32[i16 >> 2] = HEAP32[i15 >> 2];
+         i30 = HEAP32[i7 >> 2] | 0;
+         i28 = i30 + 28 | 0;
+         i29 = HEAP32[i28 >> 2] | 0;
+         i33 = HEAP32[i29 + 20 >> 2] | 0;
+         i31 = i30 + 16 | 0;
+         i32 = HEAP32[i31 >> 2] | 0;
+         i32 = i33 >>> 0 > i32 >>> 0 ? i32 : i33;
+         if ((i32 | 0) != 0 ? (i13 = i30 + 12 | 0, _memcpy(HEAP32[i13 >> 2] | 0, HEAP32[i29 + 16 >> 2] | 0, i32 | 0) | 0, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i32, i13 = (HEAP32[i28 >> 2] | 0) + 16 | 0, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i32, i13 = i30 + 20 | 0, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) + i32, HEAP32[i31 >> 2] = (HEAP32[i31 >> 2] | 0) - i32, i13 = HEAP32[i28 >> 2] | 0, i36 = i13 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i32, (i37 | 0) == (i32 | 0)) : 0) {
+          HEAP32[i13 + 16 >> 2] = HEAP32[i13 + 8 >> 2];
+         }
+         if ((HEAP32[(HEAP32[i7 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+          break L185;
+         }
+        }
+        i13 = HEAP32[i16 >> 2] | 0;
+        if ((i13 | 0) > -1) {
+         i14 = (HEAP32[i18 >> 2] | 0) + i13 | 0;
+        } else {
+         i14 = 0;
+        }
+        __tr_flush_block(i7, i14, (HEAP32[i15 >> 2] | 0) - i13 | 0, i9 & 1);
+        HEAP32[i16 >> 2] = HEAP32[i15 >> 2];
+        i14 = HEAP32[i7 >> 2] | 0;
+        i16 = i14 + 28 | 0;
+        i15 = HEAP32[i16 >> 2] | 0;
+        i18 = HEAP32[i15 + 20 >> 2] | 0;
+        i13 = i14 + 16 | 0;
+        i17 = HEAP32[i13 >> 2] | 0;
+        i17 = i18 >>> 0 > i17 >>> 0 ? i17 : i18;
+        if ((i17 | 0) != 0 ? (i12 = i14 + 12 | 0, _memcpy(HEAP32[i12 >> 2] | 0, HEAP32[i15 + 16 >> 2] | 0, i17 | 0) | 0, HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + i17, i12 = (HEAP32[i16 >> 2] | 0) + 16 | 0, HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + i17, i12 = i14 + 20 | 0, HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) + i17, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) - i17, i12 = HEAP32[i16 >> 2] | 0, i36 = i12 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i17, (i37 | 0) == (i17 | 0)) : 0) {
+         HEAP32[i12 + 16 >> 2] = HEAP32[i12 + 8 >> 2];
+        }
+        if ((HEAP32[(HEAP32[i7 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+         i12 = i9 ? 2 : 0;
+         i17 = 183;
+         break;
+        } else {
+         i12 = i9 ? 3 : 1;
+         i17 = 183;
+         break;
+        }
+       } else {
+        i12 = FUNCTION_TABLE_iii[HEAP32[184 + ((HEAP32[i7 + 132 >> 2] | 0) * 12 | 0) >> 2] & 3](i7, i10) | 0;
+        i17 = 183;
+       }
+      } while (0);
+      if ((i17 | 0) == 183) {
+       if ((i12 & -2 | 0) == 2) {
+        HEAP32[i11 >> 2] = 666;
+       }
+       if ((i12 & -3 | 0) != 0) {
+        if ((i12 | 0) != 1) {
+         break;
+        }
+        if ((i10 | 0) == 1) {
+         __tr_align(i7);
+        } else if (((i10 | 0) != 5 ? (__tr_stored_block(i7, 0, 0, 0), (i10 | 0) == 3) : 0) ? (i37 = HEAP32[i7 + 76 >> 2] | 0, i36 = HEAP32[i7 + 68 >> 2] | 0, HEAP16[i36 + (i37 + -1 << 1) >> 1] = 0, _memset(i36 | 0, 0, (i37 << 1) + -2 | 0) | 0, (HEAP32[i7 + 116 >> 2] | 0) == 0) : 0) {
+         HEAP32[i7 + 108 >> 2] = 0;
+         HEAP32[i7 + 92 >> 2] = 0;
+        }
+        i11 = HEAP32[i5 >> 2] | 0;
+        i12 = HEAP32[i11 + 20 >> 2] | 0;
+        i10 = HEAP32[i3 >> 2] | 0;
+        i12 = i12 >>> 0 > i10 >>> 0 ? i10 : i12;
+        if ((i12 | 0) != 0) {
+         _memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i11 + 16 >> 2] | 0, i12 | 0) | 0;
+         HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i12;
+         i10 = (HEAP32[i5 >> 2] | 0) + 16 | 0;
+         HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + i12;
+         i10 = i2 + 20 | 0;
+         HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + i12;
+         HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i12;
+         i10 = HEAP32[i5 >> 2] | 0;
+         i36 = i10 + 20 | 0;
+         i37 = HEAP32[i36 >> 2] | 0;
+         HEAP32[i36 >> 2] = i37 - i12;
+         if ((i37 | 0) == (i12 | 0)) {
+          HEAP32[i10 + 16 >> 2] = HEAP32[i10 + 8 >> 2];
+         }
+         i10 = HEAP32[i3 >> 2] | 0;
+        }
+        if ((i10 | 0) != 0) {
+         break;
+        }
+        HEAP32[i8 >> 2] = -1;
+        i37 = 0;
+        STACKTOP = i1;
+        return i37 | 0;
+       }
+      }
+      if ((HEAP32[i3 >> 2] | 0) != 0) {
+       i37 = 0;
+       STACKTOP = i1;
+       return i37 | 0;
+      }
+      HEAP32[i8 >> 2] = -1;
+      i37 = 0;
+      STACKTOP = i1;
+      return i37 | 0;
+     }
+    } while (0);
+    if (!i9) {
+     i37 = 0;
+     STACKTOP = i1;
+     return i37 | 0;
+    }
+    i8 = i7 + 24 | 0;
+    i10 = HEAP32[i8 >> 2] | 0;
+    if ((i10 | 0) < 1) {
+     i37 = 1;
+     STACKTOP = i1;
+     return i37 | 0;
+    }
+    i11 = i2 + 48 | 0;
+    i9 = HEAP32[i11 >> 2] | 0;
+    if ((i10 | 0) == 2) {
+     i34 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i34 + 1;
+     i36 = i7 + 8 | 0;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i34 | 0] = i9;
+     i34 = (HEAP32[i11 >> 2] | 0) >>> 8 & 255;
+     i35 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i35 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i35 | 0] = i34;
+     i35 = (HEAP32[i11 >> 2] | 0) >>> 16 & 255;
+     i34 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i34 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i34 | 0] = i35;
+     i34 = (HEAP32[i11 >> 2] | 0) >>> 24 & 255;
+     i35 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i35 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i35 | 0] = i34;
+     i35 = i2 + 8 | 0;
+     i34 = HEAP32[i35 >> 2] & 255;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i34;
+     i37 = (HEAP32[i35 >> 2] | 0) >>> 8 & 255;
+     i34 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i34 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i34 | 0] = i37;
+     i34 = (HEAP32[i35 >> 2] | 0) >>> 16 & 255;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i34;
+     i35 = (HEAP32[i35 >> 2] | 0) >>> 24 & 255;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i35;
+    } else {
+     i35 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i35 + 1;
+     i36 = i7 + 8 | 0;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i35 | 0] = i9 >>> 24;
+     i35 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i35 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i35 | 0] = i9 >>> 16;
+     i35 = HEAP32[i11 >> 2] | 0;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i35 >>> 8;
+     i37 = HEAP32[i19 >> 2] | 0;
+     HEAP32[i19 >> 2] = i37 + 1;
+     HEAP8[(HEAP32[i36 >> 2] | 0) + i37 | 0] = i35;
+    }
+    i7 = HEAP32[i5 >> 2] | 0;
+    i10 = HEAP32[i7 + 20 >> 2] | 0;
+    i9 = HEAP32[i3 >> 2] | 0;
+    i9 = i10 >>> 0 > i9 >>> 0 ? i9 : i10;
+    if ((i9 | 0) != 0 ? (_memcpy(HEAP32[i4 >> 2] | 0, HEAP32[i7 + 16 >> 2] | 0, i9 | 0) | 0, HEAP32[i4 >> 2] = (HEAP32[i4 >> 2] | 0) + i9, i6 = (HEAP32[i5 >> 2] | 0) + 16 | 0, HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i9, i6 = i2 + 20 | 0, HEAP32[i6 >> 2] = (HEAP32[i6 >> 2] | 0) + i9, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) - i9, i6 = HEAP32[i5 >> 2] | 0, i36 = i6 + 20 | 0, i37 = HEAP32[i36 >> 2] | 0, HEAP32[i36 >> 2] = i37 - i9, (i37 | 0) == (i9 | 0)) : 0) {
+     HEAP32[i6 + 16 >> 2] = HEAP32[i6 + 8 >> 2];
+    }
+    i2 = HEAP32[i8 >> 2] | 0;
+    if ((i2 | 0) > 0) {
+     HEAP32[i8 >> 2] = 0 - i2;
+    }
+    i37 = (HEAP32[i19 >> 2] | 0) == 0 | 0;
+    STACKTOP = i1;
+    return i37 | 0;
+   }
+  }
+ } while (0);
+ HEAP32[i2 + 24 >> 2] = HEAP32[3168 >> 2];
+ i37 = -2;
+ STACKTOP = i1;
+ return i37 | 0;
+}
+function _free(i7) {
+ i7 = i7 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0;
+ i1 = STACKTOP;
+ if ((i7 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i15 = i7 + -8 | 0;
+ i16 = HEAP32[14488 >> 2] | 0;
+ if (i15 >>> 0 < i16 >>> 0) {
+  _abort();
+ }
+ i13 = HEAP32[i7 + -4 >> 2] | 0;
+ i12 = i13 & 3;
+ if ((i12 | 0) == 1) {
+  _abort();
+ }
+ i8 = i13 & -8;
+ i6 = i7 + (i8 + -8) | 0;
+ do {
+  if ((i13 & 1 | 0) == 0) {
+   i19 = HEAP32[i15 >> 2] | 0;
+   if ((i12 | 0) == 0) {
+    STACKTOP = i1;
+    return;
+   }
+   i15 = -8 - i19 | 0;
+   i13 = i7 + i15 | 0;
+   i12 = i19 + i8 | 0;
+   if (i13 >>> 0 < i16 >>> 0) {
+    _abort();
+   }
+   if ((i13 | 0) == (HEAP32[14492 >> 2] | 0)) {
+    i2 = i7 + (i8 + -4) | 0;
+    if ((HEAP32[i2 >> 2] & 3 | 0) != 3) {
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    HEAP32[14480 >> 2] = i12;
+    HEAP32[i2 >> 2] = HEAP32[i2 >> 2] & -2;
+    HEAP32[i7 + (i15 + 4) >> 2] = i12 | 1;
+    HEAP32[i6 >> 2] = i12;
+    STACKTOP = i1;
+    return;
+   }
+   i18 = i19 >>> 3;
+   if (i19 >>> 0 < 256) {
+    i2 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+    i11 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+    i14 = 14512 + (i18 << 1 << 2) | 0;
+    if ((i2 | 0) != (i14 | 0)) {
+     if (i2 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i2 + 12 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+    }
+    if ((i11 | 0) == (i2 | 0)) {
+     HEAP32[3618] = HEAP32[3618] & ~(1 << i18);
+     i2 = i13;
+     i11 = i12;
+     break;
+    }
+    if ((i11 | 0) != (i14 | 0)) {
+     if (i11 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i14 = i11 + 8 | 0;
+     if ((HEAP32[i14 >> 2] | 0) == (i13 | 0)) {
+      i17 = i14;
+     } else {
+      _abort();
+     }
+    } else {
+     i17 = i11 + 8 | 0;
+    }
+    HEAP32[i2 + 12 >> 2] = i11;
+    HEAP32[i17 >> 2] = i2;
+    i2 = i13;
+    i11 = i12;
+    break;
+   }
+   i17 = HEAP32[i7 + (i15 + 24) >> 2] | 0;
+   i18 = HEAP32[i7 + (i15 + 12) >> 2] | 0;
+   do {
+    if ((i18 | 0) == (i13 | 0)) {
+     i19 = i7 + (i15 + 20) | 0;
+     i18 = HEAP32[i19 >> 2] | 0;
+     if ((i18 | 0) == 0) {
+      i19 = i7 + (i15 + 16) | 0;
+      i18 = HEAP32[i19 >> 2] | 0;
+      if ((i18 | 0) == 0) {
+       i14 = 0;
+       break;
+      }
+     }
+     while (1) {
+      i21 = i18 + 20 | 0;
+      i20 = HEAP32[i21 >> 2] | 0;
+      if ((i20 | 0) != 0) {
+       i18 = i20;
+       i19 = i21;
+       continue;
+      }
+      i20 = i18 + 16 | 0;
+      i21 = HEAP32[i20 >> 2] | 0;
+      if ((i21 | 0) == 0) {
+       break;
+      } else {
+       i18 = i21;
+       i19 = i20;
+      }
+     }
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i19 >> 2] = 0;
+      i14 = i18;
+      break;
+     }
+    } else {
+     i19 = HEAP32[i7 + (i15 + 8) >> 2] | 0;
+     if (i19 >>> 0 < i16 >>> 0) {
+      _abort();
+     }
+     i16 = i19 + 12 | 0;
+     if ((HEAP32[i16 >> 2] | 0) != (i13 | 0)) {
+      _abort();
+     }
+     i20 = i18 + 8 | 0;
+     if ((HEAP32[i20 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i18;
+      HEAP32[i20 >> 2] = i19;
+      i14 = i18;
+      break;
+     } else {
+      _abort();
+     }
+    }
+   } while (0);
+   if ((i17 | 0) != 0) {
+    i18 = HEAP32[i7 + (i15 + 28) >> 2] | 0;
+    i16 = 14776 + (i18 << 2) | 0;
+    if ((i13 | 0) == (HEAP32[i16 >> 2] | 0)) {
+     HEAP32[i16 >> 2] = i14;
+     if ((i14 | 0) == 0) {
+      HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i18);
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     if (i17 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i16 = i17 + 16 | 0;
+     if ((HEAP32[i16 >> 2] | 0) == (i13 | 0)) {
+      HEAP32[i16 >> 2] = i14;
+     } else {
+      HEAP32[i17 + 20 >> 2] = i14;
+     }
+     if ((i14 | 0) == 0) {
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    }
+    if (i14 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+     _abort();
+    }
+    HEAP32[i14 + 24 >> 2] = i17;
+    i16 = HEAP32[i7 + (i15 + 16) >> 2] | 0;
+    do {
+     if ((i16 | 0) != 0) {
+      if (i16 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i14 + 16 >> 2] = i16;
+       HEAP32[i16 + 24 >> 2] = i14;
+       break;
+      }
+     }
+    } while (0);
+    i15 = HEAP32[i7 + (i15 + 20) >> 2] | 0;
+    if ((i15 | 0) != 0) {
+     if (i15 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i14 + 20 >> 2] = i15;
+      HEAP32[i15 + 24 >> 2] = i14;
+      i2 = i13;
+      i11 = i12;
+      break;
+     }
+    } else {
+     i2 = i13;
+     i11 = i12;
+    }
+   } else {
+    i2 = i13;
+    i11 = i12;
+   }
+  } else {
+   i2 = i15;
+   i11 = i8;
+  }
+ } while (0);
+ if (!(i2 >>> 0 < i6 >>> 0)) {
+  _abort();
+ }
+ i12 = i7 + (i8 + -4) | 0;
+ i13 = HEAP32[i12 >> 2] | 0;
+ if ((i13 & 1 | 0) == 0) {
+  _abort();
+ }
+ if ((i13 & 2 | 0) == 0) {
+  if ((i6 | 0) == (HEAP32[14496 >> 2] | 0)) {
+   i21 = (HEAP32[14484 >> 2] | 0) + i11 | 0;
+   HEAP32[14484 >> 2] = i21;
+   HEAP32[14496 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   if ((i2 | 0) != (HEAP32[14492 >> 2] | 0)) {
+    STACKTOP = i1;
+    return;
+   }
+   HEAP32[14492 >> 2] = 0;
+   HEAP32[14480 >> 2] = 0;
+   STACKTOP = i1;
+   return;
+  }
+  if ((i6 | 0) == (HEAP32[14492 >> 2] | 0)) {
+   i21 = (HEAP32[14480 >> 2] | 0) + i11 | 0;
+   HEAP32[14480 >> 2] = i21;
+   HEAP32[14492 >> 2] = i2;
+   HEAP32[i2 + 4 >> 2] = i21 | 1;
+   HEAP32[i2 + i21 >> 2] = i21;
+   STACKTOP = i1;
+   return;
+  }
+  i11 = (i13 & -8) + i11 | 0;
+  i12 = i13 >>> 3;
+  do {
+   if (!(i13 >>> 0 < 256)) {
+    i10 = HEAP32[i7 + (i8 + 16) >> 2] | 0;
+    i15 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    do {
+     if ((i15 | 0) == (i6 | 0)) {
+      i13 = i7 + (i8 + 12) | 0;
+      i12 = HEAP32[i13 >> 2] | 0;
+      if ((i12 | 0) == 0) {
+       i13 = i7 + (i8 + 8) | 0;
+       i12 = HEAP32[i13 >> 2] | 0;
+       if ((i12 | 0) == 0) {
+        i9 = 0;
+        break;
+       }
+      }
+      while (1) {
+       i14 = i12 + 20 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) != 0) {
+        i12 = i15;
+        i13 = i14;
+        continue;
+       }
+       i14 = i12 + 16 | 0;
+       i15 = HEAP32[i14 >> 2] | 0;
+       if ((i15 | 0) == 0) {
+        break;
+       } else {
+        i12 = i15;
+        i13 = i14;
+       }
+      }
+      if (i13 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i13 >> 2] = 0;
+       i9 = i12;
+       break;
+      }
+     } else {
+      i13 = HEAP32[i7 + i8 >> 2] | 0;
+      if (i13 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i14 = i13 + 12 | 0;
+      if ((HEAP32[i14 >> 2] | 0) != (i6 | 0)) {
+       _abort();
+      }
+      i12 = i15 + 8 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i14 >> 2] = i15;
+       HEAP32[i12 >> 2] = i13;
+       i9 = i15;
+       break;
+      } else {
+       _abort();
+      }
+     }
+    } while (0);
+    if ((i10 | 0) != 0) {
+     i12 = HEAP32[i7 + (i8 + 20) >> 2] | 0;
+     i13 = 14776 + (i12 << 2) | 0;
+     if ((i6 | 0) == (HEAP32[i13 >> 2] | 0)) {
+      HEAP32[i13 >> 2] = i9;
+      if ((i9 | 0) == 0) {
+       HEAP32[14476 >> 2] = HEAP32[14476 >> 2] & ~(1 << i12);
+       break;
+      }
+     } else {
+      if (i10 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      }
+      i12 = i10 + 16 | 0;
+      if ((HEAP32[i12 >> 2] | 0) == (i6 | 0)) {
+       HEAP32[i12 >> 2] = i9;
+      } else {
+       HEAP32[i10 + 20 >> 2] = i9;
+      }
+      if ((i9 | 0) == 0) {
+       break;
+      }
+     }
+     if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     HEAP32[i9 + 24 >> 2] = i10;
+     i6 = HEAP32[i7 + (i8 + 8) >> 2] | 0;
+     do {
+      if ((i6 | 0) != 0) {
+       if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+        _abort();
+       } else {
+        HEAP32[i9 + 16 >> 2] = i6;
+        HEAP32[i6 + 24 >> 2] = i9;
+        break;
+       }
+      }
+     } while (0);
+     i6 = HEAP32[i7 + (i8 + 12) >> 2] | 0;
+     if ((i6 | 0) != 0) {
+      if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+       _abort();
+      } else {
+       HEAP32[i9 + 20 >> 2] = i6;
+       HEAP32[i6 + 24 >> 2] = i9;
+       break;
+      }
+     }
+    }
+   } else {
+    i9 = HEAP32[i7 + i8 >> 2] | 0;
+    i7 = HEAP32[i7 + (i8 | 4) >> 2] | 0;
+    i8 = 14512 + (i12 << 1 << 2) | 0;
+    if ((i9 | 0) != (i8 | 0)) {
+     if (i9 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     if ((HEAP32[i9 + 12 >> 2] | 0) != (i6 | 0)) {
+      _abort();
+     }
+    }
+    if ((i7 | 0) == (i9 | 0)) {
+     HEAP32[3618] = HEAP32[3618] & ~(1 << i12);
+     break;
+    }
+    if ((i7 | 0) != (i8 | 0)) {
+     if (i7 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     }
+     i8 = i7 + 8 | 0;
+     if ((HEAP32[i8 >> 2] | 0) == (i6 | 0)) {
+      i10 = i8;
+     } else {
+      _abort();
+     }
+    } else {
+     i10 = i7 + 8 | 0;
+    }
+    HEAP32[i9 + 12 >> 2] = i7;
+    HEAP32[i10 >> 2] = i9;
+   }
+  } while (0);
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+  if ((i2 | 0) == (HEAP32[14492 >> 2] | 0)) {
+   HEAP32[14480 >> 2] = i11;
+   STACKTOP = i1;
+   return;
+  }
+ } else {
+  HEAP32[i12 >> 2] = i13 & -2;
+  HEAP32[i2 + 4 >> 2] = i11 | 1;
+  HEAP32[i2 + i11 >> 2] = i11;
+ }
+ i6 = i11 >>> 3;
+ if (i11 >>> 0 < 256) {
+  i7 = i6 << 1;
+  i3 = 14512 + (i7 << 2) | 0;
+  i8 = HEAP32[3618] | 0;
+  i6 = 1 << i6;
+  if ((i8 & i6 | 0) != 0) {
+   i6 = 14512 + (i7 + 2 << 2) | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   if (i7 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+    _abort();
+   } else {
+    i4 = i6;
+    i5 = i7;
+   }
+  } else {
+   HEAP32[3618] = i8 | i6;
+   i4 = 14512 + (i7 + 2 << 2) | 0;
+   i5 = i3;
+  }
+  HEAP32[i4 >> 2] = i2;
+  HEAP32[i5 + 12 >> 2] = i2;
+  HEAP32[i2 + 8 >> 2] = i5;
+  HEAP32[i2 + 12 >> 2] = i3;
+  STACKTOP = i1;
+  return;
+ }
+ i4 = i11 >>> 8;
+ if ((i4 | 0) != 0) {
+  if (i11 >>> 0 > 16777215) {
+   i4 = 31;
+  } else {
+   i20 = (i4 + 1048320 | 0) >>> 16 & 8;
+   i21 = i4 << i20;
+   i19 = (i21 + 520192 | 0) >>> 16 & 4;
+   i21 = i21 << i19;
+   i4 = (i21 + 245760 | 0) >>> 16 & 2;
+   i4 = 14 - (i19 | i20 | i4) + (i21 << i4 >>> 15) | 0;
+   i4 = i11 >>> (i4 + 7 | 0) & 1 | i4 << 1;
+  }
+ } else {
+  i4 = 0;
+ }
+ i5 = 14776 + (i4 << 2) | 0;
+ HEAP32[i2 + 28 >> 2] = i4;
+ HEAP32[i2 + 20 >> 2] = 0;
+ HEAP32[i2 + 16 >> 2] = 0;
+ i7 = HEAP32[14476 >> 2] | 0;
+ i6 = 1 << i4;
+ L199 : do {
+  if ((i7 & i6 | 0) != 0) {
+   i5 = HEAP32[i5 >> 2] | 0;
+   if ((i4 | 0) == 31) {
+    i4 = 0;
+   } else {
+    i4 = 25 - (i4 >>> 1) | 0;
+   }
+   L204 : do {
+    if ((HEAP32[i5 + 4 >> 2] & -8 | 0) != (i11 | 0)) {
+     i4 = i11 << i4;
+     i7 = i5;
+     while (1) {
+      i6 = i7 + (i4 >>> 31 << 2) + 16 | 0;
+      i5 = HEAP32[i6 >> 2] | 0;
+      if ((i5 | 0) == 0) {
+       break;
+      }
+      if ((HEAP32[i5 + 4 >> 2] & -8 | 0) == (i11 | 0)) {
+       i3 = i5;
+       break L204;
+      } else {
+       i4 = i4 << 1;
+       i7 = i5;
+      }
+     }
+     if (i6 >>> 0 < (HEAP32[14488 >> 2] | 0) >>> 0) {
+      _abort();
+     } else {
+      HEAP32[i6 >> 2] = i2;
+      HEAP32[i2 + 24 >> 2] = i7;
+      HEAP32[i2 + 12 >> 2] = i2;
+      HEAP32[i2 + 8 >> 2] = i2;
+      break L199;
+     }
+    } else {
+     i3 = i5;
+    }
+   } while (0);
+   i5 = i3 + 8 | 0;
+   i4 = HEAP32[i5 >> 2] | 0;
+   i6 = HEAP32[14488 >> 2] | 0;
+   if (i3 >>> 0 < i6 >>> 0) {
+    _abort();
+   }
+   if (i4 >>> 0 < i6 >>> 0) {
+    _abort();
+   } else {
+    HEAP32[i4 + 12 >> 2] = i2;
+    HEAP32[i5 >> 2] = i2;
+    HEAP32[i2 + 8 >> 2] = i4;
+    HEAP32[i2 + 12 >> 2] = i3;
+    HEAP32[i2 + 24 >> 2] = 0;
+    break;
+   }
+  } else {
+   HEAP32[14476 >> 2] = i7 | i6;
+   HEAP32[i5 >> 2] = i2;
+   HEAP32[i2 + 24 >> 2] = i5;
+   HEAP32[i2 + 12 >> 2] = i2;
+   HEAP32[i2 + 8 >> 2] = i2;
+  }
+ } while (0);
+ i21 = (HEAP32[14504 >> 2] | 0) + -1 | 0;
+ HEAP32[14504 >> 2] = i21;
+ if ((i21 | 0) == 0) {
+  i2 = 14928 | 0;
+ } else {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i2 = HEAP32[i2 >> 2] | 0;
+  if ((i2 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 8 | 0;
+  }
+ }
+ HEAP32[14504 >> 2] = -1;
+ STACKTOP = i1;
+ return;
+}
+function _build_tree(i4, i9) {
+ i4 = i4 | 0;
+ i9 = i9 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 32 | 0;
+ i1 = i2;
+ i3 = HEAP32[i9 >> 2] | 0;
+ i7 = i9 + 8 | 0;
+ i11 = HEAP32[i7 >> 2] | 0;
+ i12 = HEAP32[i11 >> 2] | 0;
+ i11 = HEAP32[i11 + 12 >> 2] | 0;
+ i8 = i4 + 5200 | 0;
+ HEAP32[i8 >> 2] = 0;
+ i6 = i4 + 5204 | 0;
+ HEAP32[i6 >> 2] = 573;
+ if ((i11 | 0) > 0) {
+  i5 = -1;
+  i13 = 0;
+  do {
+   if ((HEAP16[i3 + (i13 << 2) >> 1] | 0) == 0) {
+    HEAP16[i3 + (i13 << 2) + 2 >> 1] = 0;
+   } else {
+    i5 = (HEAP32[i8 >> 2] | 0) + 1 | 0;
+    HEAP32[i8 >> 2] = i5;
+    HEAP32[i4 + (i5 << 2) + 2908 >> 2] = i13;
+    HEAP8[i4 + i13 + 5208 | 0] = 0;
+    i5 = i13;
+   }
+   i13 = i13 + 1 | 0;
+  } while ((i13 | 0) != (i11 | 0));
+  i14 = HEAP32[i8 >> 2] | 0;
+  if ((i14 | 0) < 2) {
+   i10 = 3;
+  }
+ } else {
+  i14 = 0;
+  i5 = -1;
+  i10 = 3;
+ }
+ if ((i10 | 0) == 3) {
+  i10 = i4 + 5800 | 0;
+  i13 = i4 + 5804 | 0;
+  if ((i12 | 0) == 0) {
+   do {
+    i12 = (i5 | 0) < 2;
+    i13 = i5 + 1 | 0;
+    i5 = i12 ? i13 : i5;
+    i23 = i12 ? i13 : 0;
+    i14 = i14 + 1 | 0;
+    HEAP32[i8 >> 2] = i14;
+    HEAP32[i4 + (i14 << 2) + 2908 >> 2] = i23;
+    HEAP16[i3 + (i23 << 2) >> 1] = 1;
+    HEAP8[i4 + i23 + 5208 | 0] = 0;
+    HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -1;
+    i14 = HEAP32[i8 >> 2] | 0;
+   } while ((i14 | 0) < 2);
+  } else {
+   do {
+    i15 = (i5 | 0) < 2;
+    i16 = i5 + 1 | 0;
+    i5 = i15 ? i16 : i5;
+    i23 = i15 ? i16 : 0;
+    i14 = i14 + 1 | 0;
+    HEAP32[i8 >> 2] = i14;
+    HEAP32[i4 + (i14 << 2) + 2908 >> 2] = i23;
+    HEAP16[i3 + (i23 << 2) >> 1] = 1;
+    HEAP8[i4 + i23 + 5208 | 0] = 0;
+    HEAP32[i10 >> 2] = (HEAP32[i10 >> 2] | 0) + -1;
+    HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) - (HEAPU16[i12 + (i23 << 2) + 2 >> 1] | 0);
+    i14 = HEAP32[i8 >> 2] | 0;
+   } while ((i14 | 0) < 2);
+  }
+ }
+ i10 = i9 + 4 | 0;
+ HEAP32[i10 >> 2] = i5;
+ i12 = HEAP32[i8 >> 2] | 0;
+ if ((i12 | 0) > 1) {
+  i18 = i12;
+  i13 = (i12 | 0) / 2 | 0;
+  do {
+   i12 = HEAP32[i4 + (i13 << 2) + 2908 >> 2] | 0;
+   i14 = i4 + i12 + 5208 | 0;
+   i17 = i13 << 1;
+   L21 : do {
+    if ((i17 | 0) > (i18 | 0)) {
+     i15 = i13;
+    } else {
+     i16 = i3 + (i12 << 2) | 0;
+     i15 = i13;
+     while (1) {
+      do {
+       if ((i17 | 0) < (i18 | 0)) {
+        i18 = i17 | 1;
+        i19 = HEAP32[i4 + (i18 << 2) + 2908 >> 2] | 0;
+        i22 = HEAP16[i3 + (i19 << 2) >> 1] | 0;
+        i20 = HEAP32[i4 + (i17 << 2) + 2908 >> 2] | 0;
+        i21 = HEAP16[i3 + (i20 << 2) >> 1] | 0;
+        if (!((i22 & 65535) < (i21 & 65535))) {
+         if (!(i22 << 16 >> 16 == i21 << 16 >> 16)) {
+          break;
+         }
+         if ((HEAPU8[i4 + i19 + 5208 | 0] | 0) > (HEAPU8[i4 + i20 + 5208 | 0] | 0)) {
+          break;
+         }
+        }
+        i17 = i18;
+       }
+      } while (0);
+      i19 = HEAP16[i16 >> 1] | 0;
+      i18 = HEAP32[i4 + (i17 << 2) + 2908 >> 2] | 0;
+      i20 = HEAP16[i3 + (i18 << 2) >> 1] | 0;
+      if ((i19 & 65535) < (i20 & 65535)) {
+       break L21;
+      }
+      if (i19 << 16 >> 16 == i20 << 16 >> 16 ? (HEAPU8[i14] | 0) <= (HEAPU8[i4 + i18 + 5208 | 0] | 0) : 0) {
+       break L21;
+      }
+      HEAP32[i4 + (i15 << 2) + 2908 >> 2] = i18;
+      i19 = i17 << 1;
+      i18 = HEAP32[i8 >> 2] | 0;
+      if ((i19 | 0) > (i18 | 0)) {
+       i15 = i17;
+       break;
+      } else {
+       i15 = i17;
+       i17 = i19;
+      }
+     }
+    }
+   } while (0);
+   HEAP32[i4 + (i15 << 2) + 2908 >> 2] = i12;
+   i13 = i13 + -1 | 0;
+   i18 = HEAP32[i8 >> 2] | 0;
+  } while ((i13 | 0) > 0);
+ } else {
+  i18 = i12;
+ }
+ i12 = i4 + 2912 | 0;
+ while (1) {
+  i13 = HEAP32[i12 >> 2] | 0;
+  i20 = i18 + -1 | 0;
+  HEAP32[i8 >> 2] = i20;
+  i14 = HEAP32[i4 + (i18 << 2) + 2908 >> 2] | 0;
+  HEAP32[i12 >> 2] = i14;
+  i15 = i4 + i14 + 5208 | 0;
+  L40 : do {
+   if ((i18 | 0) < 3) {
+    i17 = 1;
+   } else {
+    i16 = i3 + (i14 << 2) | 0;
+    i17 = 1;
+    i18 = 2;
+    while (1) {
+     do {
+      if ((i18 | 0) < (i20 | 0)) {
+       i22 = i18 | 1;
+       i21 = HEAP32[i4 + (i22 << 2) + 2908 >> 2] | 0;
+       i23 = HEAP16[i3 + (i21 << 2) >> 1] | 0;
+       i20 = HEAP32[i4 + (i18 << 2) + 2908 >> 2] | 0;
+       i19 = HEAP16[i3 + (i20 << 2) >> 1] | 0;
+       if (!((i23 & 65535) < (i19 & 65535))) {
+        if (!(i23 << 16 >> 16 == i19 << 16 >> 16)) {
+         break;
+        }
+        if ((HEAPU8[i4 + i21 + 5208 | 0] | 0) > (HEAPU8[i4 + i20 + 5208 | 0] | 0)) {
+         break;
+        }
+       }
+       i18 = i22;
+      }
+     } while (0);
+     i21 = HEAP16[i16 >> 1] | 0;
+     i20 = HEAP32[i4 + (i18 << 2) + 2908 >> 2] | 0;
+     i19 = HEAP16[i3 + (i20 << 2) >> 1] | 0;
+     if ((i21 & 65535) < (i19 & 65535)) {
+      break L40;
+     }
+     if (i21 << 16 >> 16 == i19 << 16 >> 16 ? (HEAPU8[i15] | 0) <= (HEAPU8[i4 + i20 + 5208 | 0] | 0) : 0) {
+      break L40;
+     }
+     HEAP32[i4 + (i17 << 2) + 2908 >> 2] = i20;
+     i19 = i18 << 1;
+     i20 = HEAP32[i8 >> 2] | 0;
+     if ((i19 | 0) > (i20 | 0)) {
+      i17 = i18;
+      break;
+     } else {
+      i17 = i18;
+      i18 = i19;
+     }
+    }
+   }
+  } while (0);
+  HEAP32[i4 + (i17 << 2) + 2908 >> 2] = i14;
+  i17 = HEAP32[i12 >> 2] | 0;
+  i14 = (HEAP32[i6 >> 2] | 0) + -1 | 0;
+  HEAP32[i6 >> 2] = i14;
+  HEAP32[i4 + (i14 << 2) + 2908 >> 2] = i13;
+  i14 = (HEAP32[i6 >> 2] | 0) + -1 | 0;
+  HEAP32[i6 >> 2] = i14;
+  HEAP32[i4 + (i14 << 2) + 2908 >> 2] = i17;
+  i14 = i3 + (i11 << 2) | 0;
+  HEAP16[i14 >> 1] = (HEAPU16[i3 + (i17 << 2) >> 1] | 0) + (HEAPU16[i3 + (i13 << 2) >> 1] | 0);
+  i18 = HEAP8[i4 + i13 + 5208 | 0] | 0;
+  i16 = HEAP8[i4 + i17 + 5208 | 0] | 0;
+  i15 = i4 + i11 + 5208 | 0;
+  HEAP8[i15] = (((i18 & 255) < (i16 & 255) ? i16 : i18) & 255) + 1;
+  i19 = i11 & 65535;
+  HEAP16[i3 + (i17 << 2) + 2 >> 1] = i19;
+  HEAP16[i3 + (i13 << 2) + 2 >> 1] = i19;
+  i13 = i11 + 1 | 0;
+  HEAP32[i12 >> 2] = i11;
+  i19 = HEAP32[i8 >> 2] | 0;
+  L56 : do {
+   if ((i19 | 0) < 2) {
+    i16 = 1;
+   } else {
+    i16 = 1;
+    i17 = 2;
+    while (1) {
+     do {
+      if ((i17 | 0) < (i19 | 0)) {
+       i21 = i17 | 1;
+       i22 = HEAP32[i4 + (i21 << 2) + 2908 >> 2] | 0;
+       i19 = HEAP16[i3 + (i22 << 2) >> 1] | 0;
+       i18 = HEAP32[i4 + (i17 << 2) + 2908 >> 2] | 0;
+       i20 = HEAP16[i3 + (i18 << 2) >> 1] | 0;
+       if (!((i19 & 65535) < (i20 & 65535))) {
+        if (!(i19 << 16 >> 16 == i20 << 16 >> 16)) {
+         break;
+        }
+        if ((HEAPU8[i4 + i22 + 5208 | 0] | 0) > (HEAPU8[i4 + i18 + 5208 | 0] | 0)) {
+         break;
+        }
+       }
+       i17 = i21;
+      }
+     } while (0);
+     i19 = HEAP16[i14 >> 1] | 0;
+     i20 = HEAP32[i4 + (i17 << 2) + 2908 >> 2] | 0;
+     i18 = HEAP16[i3 + (i20 << 2) >> 1] | 0;
+     if ((i19 & 65535) < (i18 & 65535)) {
+      break L56;
+     }
+     if (i19 << 16 >> 16 == i18 << 16 >> 16 ? (HEAPU8[i15] | 0) <= (HEAPU8[i4 + i20 + 5208 | 0] | 0) : 0) {
+      break L56;
+     }
+     HEAP32[i4 + (i16 << 2) + 2908 >> 2] = i20;
+     i18 = i17 << 1;
+     i19 = HEAP32[i8 >> 2] | 0;
+     if ((i18 | 0) > (i19 | 0)) {
+      i16 = i17;
+      break;
+     } else {
+      i16 = i17;
+      i17 = i18;
+     }
+    }
+   }
+  } while (0);
+  HEAP32[i4 + (i16 << 2) + 2908 >> 2] = i11;
+  i18 = HEAP32[i8 >> 2] | 0;
+  if ((i18 | 0) > 1) {
+   i11 = i13;
+  } else {
+   break;
+  }
+ }
+ i12 = HEAP32[i12 >> 2] | 0;
+ i8 = (HEAP32[i6 >> 2] | 0) + -1 | 0;
+ HEAP32[i6 >> 2] = i8;
+ HEAP32[i4 + (i8 << 2) + 2908 >> 2] = i12;
+ i8 = HEAP32[i9 >> 2] | 0;
+ i9 = HEAP32[i10 >> 2] | 0;
+ i7 = HEAP32[i7 >> 2] | 0;
+ i12 = HEAP32[i7 >> 2] | 0;
+ i11 = HEAP32[i7 + 4 >> 2] | 0;
+ i10 = HEAP32[i7 + 8 >> 2] | 0;
+ i7 = HEAP32[i7 + 16 >> 2] | 0;
+ i13 = i4 + 2876 | 0;
+ i14 = i13 + 32 | 0;
+ do {
+  HEAP16[i13 >> 1] = 0;
+  i13 = i13 + 2 | 0;
+ } while ((i13 | 0) < (i14 | 0));
+ i14 = HEAP32[i6 >> 2] | 0;
+ HEAP16[i8 + (HEAP32[i4 + (i14 << 2) + 2908 >> 2] << 2) + 2 >> 1] = 0;
+ i14 = i14 + 1 | 0;
+ L72 : do {
+  if ((i14 | 0) < 573) {
+   i6 = i4 + 5800 | 0;
+   i13 = i4 + 5804 | 0;
+   if ((i12 | 0) == 0) {
+    i18 = 0;
+    do {
+     i12 = HEAP32[i4 + (i14 << 2) + 2908 >> 2] | 0;
+     i13 = i8 + (i12 << 2) + 2 | 0;
+     i15 = HEAPU16[i8 + (HEAPU16[i13 >> 1] << 2) + 2 >> 1] | 0;
+     i16 = (i15 | 0) < (i7 | 0);
+     i15 = i16 ? i15 + 1 | 0 : i7;
+     i18 = (i16 & 1 ^ 1) + i18 | 0;
+     HEAP16[i13 >> 1] = i15;
+     if ((i12 | 0) <= (i9 | 0)) {
+      i23 = i4 + (i15 << 1) + 2876 | 0;
+      HEAP16[i23 >> 1] = (HEAP16[i23 >> 1] | 0) + 1 << 16 >> 16;
+      if ((i12 | 0) < (i10 | 0)) {
+       i13 = 0;
+      } else {
+       i13 = HEAP32[i11 + (i12 - i10 << 2) >> 2] | 0;
+      }
+      i23 = Math_imul(HEAPU16[i8 + (i12 << 2) >> 1] | 0, i13 + i15 | 0) | 0;
+      HEAP32[i6 >> 2] = i23 + (HEAP32[i6 >> 2] | 0);
+     }
+     i14 = i14 + 1 | 0;
+    } while ((i14 | 0) != 573);
+   } else {
+    i18 = 0;
+    do {
+     i15 = HEAP32[i4 + (i14 << 2) + 2908 >> 2] | 0;
+     i16 = i8 + (i15 << 2) + 2 | 0;
+     i17 = HEAPU16[i8 + (HEAPU16[i16 >> 1] << 2) + 2 >> 1] | 0;
+     i19 = (i17 | 0) < (i7 | 0);
+     i17 = i19 ? i17 + 1 | 0 : i7;
+     i18 = (i19 & 1 ^ 1) + i18 | 0;
+     HEAP16[i16 >> 1] = i17;
+     if ((i15 | 0) <= (i9 | 0)) {
+      i23 = i4 + (i17 << 1) + 2876 | 0;
+      HEAP16[i23 >> 1] = (HEAP16[i23 >> 1] | 0) + 1 << 16 >> 16;
+      if ((i15 | 0) < (i10 | 0)) {
+       i16 = 0;
+      } else {
+       i16 = HEAP32[i11 + (i15 - i10 << 2) >> 2] | 0;
+      }
+      i23 = HEAPU16[i8 + (i15 << 2) >> 1] | 0;
+      i22 = Math_imul(i23, i16 + i17 | 0) | 0;
+      HEAP32[i6 >> 2] = i22 + (HEAP32[i6 >> 2] | 0);
+      i23 = Math_imul((HEAPU16[i12 + (i15 << 2) + 2 >> 1] | 0) + i16 | 0, i23) | 0;
+      HEAP32[i13 >> 2] = i23 + (HEAP32[i13 >> 2] | 0);
+     }
+     i14 = i14 + 1 | 0;
+    } while ((i14 | 0) != 573);
+   }
+   if ((i18 | 0) != 0) {
+    i10 = i4 + (i7 << 1) + 2876 | 0;
+    do {
+     i12 = i7;
+     while (1) {
+      i11 = i12 + -1 | 0;
+      i13 = i4 + (i11 << 1) + 2876 | 0;
+      i14 = HEAP16[i13 >> 1] | 0;
+      if (i14 << 16 >> 16 == 0) {
+       i12 = i11;
+      } else {
+       break;
+      }
+     }
+     HEAP16[i13 >> 1] = i14 + -1 << 16 >> 16;
+     i11 = i4 + (i12 << 1) + 2876 | 0;
+     HEAP16[i11 >> 1] = (HEAPU16[i11 >> 1] | 0) + 2;
+     i11 = (HEAP16[i10 >> 1] | 0) + -1 << 16 >> 16;
+     HEAP16[i10 >> 1] = i11;
+     i18 = i18 + -2 | 0;
+    } while ((i18 | 0) > 0);
+    if ((i7 | 0) != 0) {
+     i12 = 573;
+     while (1) {
+      i10 = i7 & 65535;
+      if (!(i11 << 16 >> 16 == 0)) {
+       i11 = i11 & 65535;
+       do {
+        do {
+         i12 = i12 + -1 | 0;
+         i15 = HEAP32[i4 + (i12 << 2) + 2908 >> 2] | 0;
+        } while ((i15 | 0) > (i9 | 0));
+        i13 = i8 + (i15 << 2) + 2 | 0;
+        i14 = HEAPU16[i13 >> 1] | 0;
+        if ((i14 | 0) != (i7 | 0)) {
+         i23 = Math_imul(HEAPU16[i8 + (i15 << 2) >> 1] | 0, i7 - i14 | 0) | 0;
+         HEAP32[i6 >> 2] = i23 + (HEAP32[i6 >> 2] | 0);
+         HEAP16[i13 >> 1] = i10;
+        }
+        i11 = i11 + -1 | 0;
+       } while ((i11 | 0) != 0);
+      }
+      i7 = i7 + -1 | 0;
+      if ((i7 | 0) == 0) {
+       break L72;
+      }
+      i11 = HEAP16[i4 + (i7 << 1) + 2876 >> 1] | 0;
+     }
+    }
+   }
+  }
+ } while (0);
+ i7 = 1;
+ i6 = 0;
+ do {
+  i6 = (HEAPU16[i4 + (i7 + -1 << 1) + 2876 >> 1] | 0) + (i6 & 65534) << 1;
+  HEAP16[i1 + (i7 << 1) >> 1] = i6;
+  i7 = i7 + 1 | 0;
+ } while ((i7 | 0) != 16);
+ if ((i5 | 0) < 0) {
+  STACKTOP = i2;
+  return;
+ } else {
+  i4 = 0;
+ }
+ while (1) {
+  i23 = HEAP16[i3 + (i4 << 2) + 2 >> 1] | 0;
+  i7 = i23 & 65535;
+  if (!(i23 << 16 >> 16 == 0)) {
+   i8 = i1 + (i7 << 1) | 0;
+   i6 = HEAP16[i8 >> 1] | 0;
+   HEAP16[i8 >> 1] = i6 + 1 << 16 >> 16;
+   i6 = i6 & 65535;
+   i8 = 0;
+   while (1) {
+    i8 = i8 | i6 & 1;
+    i7 = i7 + -1 | 0;
+    if ((i7 | 0) <= 0) {
+     break;
+    } else {
+     i6 = i6 >>> 1;
+     i8 = i8 << 1;
+    }
+   }
+   HEAP16[i3 + (i4 << 2) >> 1] = i8;
+  }
+  if ((i4 | 0) == (i5 | 0)) {
+   break;
+  } else {
+   i4 = i4 + 1 | 0;
+  }
+ }
+ STACKTOP = i2;
+ return;
+}
+function _deflate_slow(i2, i6) {
+ i2 = i2 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0;
+ i1 = STACKTOP;
+ i15 = i2 + 116 | 0;
+ i16 = (i6 | 0) == 0;
+ i17 = i2 + 72 | 0;
+ i18 = i2 + 88 | 0;
+ i5 = i2 + 108 | 0;
+ i7 = i2 + 56 | 0;
+ i19 = i2 + 84 | 0;
+ i20 = i2 + 68 | 0;
+ i22 = i2 + 52 | 0;
+ i21 = i2 + 64 | 0;
+ i9 = i2 + 96 | 0;
+ i10 = i2 + 120 | 0;
+ i11 = i2 + 112 | 0;
+ i12 = i2 + 100 | 0;
+ i26 = i2 + 5792 | 0;
+ i27 = i2 + 5796 | 0;
+ i29 = i2 + 5784 | 0;
+ i23 = i2 + 5788 | 0;
+ i8 = i2 + 104 | 0;
+ i4 = i2 + 92 | 0;
+ i24 = i2 + 128 | 0;
+ i14 = i2 + 44 | 0;
+ i13 = i2 + 136 | 0;
+ L1 : while (1) {
+  i30 = HEAP32[i15 >> 2] | 0;
+  while (1) {
+   if (i30 >>> 0 < 262) {
+    _fill_window(i2);
+    i30 = HEAP32[i15 >> 2] | 0;
+    if (i30 >>> 0 < 262 & i16) {
+     i2 = 0;
+     i30 = 50;
+     break L1;
+    }
+    if ((i30 | 0) == 0) {
+     i30 = 40;
+     break L1;
+    }
+    if (!(i30 >>> 0 > 2)) {
+     HEAP32[i10 >> 2] = HEAP32[i9 >> 2];
+     HEAP32[i12 >> 2] = HEAP32[i11 >> 2];
+     HEAP32[i9 >> 2] = 2;
+     i32 = 2;
+     i30 = 16;
+    } else {
+     i30 = 8;
+    }
+   } else {
+    i30 = 8;
+   }
+   do {
+    if ((i30 | 0) == 8) {
+     i30 = 0;
+     i34 = HEAP32[i5 >> 2] | 0;
+     i31 = ((HEAPU8[(HEAP32[i7 >> 2] | 0) + (i34 + 2) | 0] | 0) ^ HEAP32[i17 >> 2] << HEAP32[i18 >> 2]) & HEAP32[i19 >> 2];
+     HEAP32[i17 >> 2] = i31;
+     i31 = (HEAP32[i20 >> 2] | 0) + (i31 << 1) | 0;
+     i35 = HEAP16[i31 >> 1] | 0;
+     HEAP16[(HEAP32[i21 >> 2] | 0) + ((HEAP32[i22 >> 2] & i34) << 1) >> 1] = i35;
+     i32 = i35 & 65535;
+     HEAP16[i31 >> 1] = i34;
+     i31 = HEAP32[i9 >> 2] | 0;
+     HEAP32[i10 >> 2] = i31;
+     HEAP32[i12 >> 2] = HEAP32[i11 >> 2];
+     HEAP32[i9 >> 2] = 2;
+     if (!(i35 << 16 >> 16 == 0)) {
+      if (i31 >>> 0 < (HEAP32[i24 >> 2] | 0) >>> 0) {
+       if (!(((HEAP32[i5 >> 2] | 0) - i32 | 0) >>> 0 > ((HEAP32[i14 >> 2] | 0) + -262 | 0) >>> 0)) {
+        i32 = _longest_match(i2, i32) | 0;
+        HEAP32[i9 >> 2] = i32;
+        if (i32 >>> 0 < 6) {
+         if ((HEAP32[i13 >> 2] | 0) != 1) {
+          if ((i32 | 0) != 3) {
+           i30 = 16;
+           break;
+          }
+          if (!(((HEAP32[i5 >> 2] | 0) - (HEAP32[i11 >> 2] | 0) | 0) >>> 0 > 4096)) {
+           i32 = 3;
+           i30 = 16;
+           break;
+          }
+         }
+         HEAP32[i9 >> 2] = 2;
+         i32 = 2;
+         i30 = 16;
+        } else {
+         i30 = 16;
+        }
+       } else {
+        i32 = 2;
+        i30 = 16;
+       }
+      } else {
+       i32 = 2;
+      }
+     } else {
+      i32 = 2;
+      i30 = 16;
+     }
+    }
+   } while (0);
+   if ((i30 | 0) == 16) {
+    i31 = HEAP32[i10 >> 2] | 0;
+   }
+   if (!(i31 >>> 0 < 3 | i32 >>> 0 > i31 >>> 0)) {
+    break;
+   }
+   if ((HEAP32[i8 >> 2] | 0) == 0) {
+    HEAP32[i8 >> 2] = 1;
+    HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+    i30 = (HEAP32[i15 >> 2] | 0) + -1 | 0;
+    HEAP32[i15 >> 2] = i30;
+    continue;
+   }
+   i35 = HEAP8[(HEAP32[i7 >> 2] | 0) + ((HEAP32[i5 >> 2] | 0) + -1) | 0] | 0;
+   i34 = HEAP32[i26 >> 2] | 0;
+   HEAP16[(HEAP32[i27 >> 2] | 0) + (i34 << 1) >> 1] = 0;
+   HEAP32[i26 >> 2] = i34 + 1;
+   HEAP8[(HEAP32[i29 >> 2] | 0) + i34 | 0] = i35;
+   i35 = i2 + ((i35 & 255) << 2) + 148 | 0;
+   HEAP16[i35 >> 1] = (HEAP16[i35 >> 1] | 0) + 1 << 16 >> 16;
+   if ((HEAP32[i26 >> 2] | 0) == ((HEAP32[i23 >> 2] | 0) + -1 | 0)) {
+    i30 = HEAP32[i4 >> 2] | 0;
+    if ((i30 | 0) > -1) {
+     i31 = (HEAP32[i7 >> 2] | 0) + i30 | 0;
+    } else {
+     i31 = 0;
+    }
+    __tr_flush_block(i2, i31, (HEAP32[i5 >> 2] | 0) - i30 | 0, 0);
+    HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+    i33 = HEAP32[i2 >> 2] | 0;
+    i32 = i33 + 28 | 0;
+    i30 = HEAP32[i32 >> 2] | 0;
+    i35 = HEAP32[i30 + 20 >> 2] | 0;
+    i31 = i33 + 16 | 0;
+    i34 = HEAP32[i31 >> 2] | 0;
+    i34 = i35 >>> 0 > i34 >>> 0 ? i34 : i35;
+    if ((i34 | 0) != 0 ? (i28 = i33 + 12 | 0, _memcpy(HEAP32[i28 >> 2] | 0, HEAP32[i30 + 16 >> 2] | 0, i34 | 0) | 0, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) + i34, i28 = (HEAP32[i32 >> 2] | 0) + 16 | 0, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) + i34, i28 = i33 + 20 | 0, HEAP32[i28 >> 2] = (HEAP32[i28 >> 2] | 0) + i34, HEAP32[i31 >> 2] = (HEAP32[i31 >> 2] | 0) - i34, i28 = HEAP32[i32 >> 2] | 0, i33 = i28 + 20 | 0, i35 = HEAP32[i33 >> 2] | 0, HEAP32[i33 >> 2] = i35 - i34, (i35 | 0) == (i34 | 0)) : 0) {
+     HEAP32[i28 + 16 >> 2] = HEAP32[i28 + 8 >> 2];
+    }
+   }
+   HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + 1;
+   i30 = (HEAP32[i15 >> 2] | 0) + -1 | 0;
+   HEAP32[i15 >> 2] = i30;
+   if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+    i2 = 0;
+    i30 = 50;
+    break L1;
+   }
+  }
+  i34 = HEAP32[i5 >> 2] | 0;
+  i30 = i34 + -3 + (HEAP32[i15 >> 2] | 0) | 0;
+  i35 = i31 + 253 | 0;
+  i31 = i34 + 65535 - (HEAP32[i12 >> 2] | 0) | 0;
+  i34 = HEAP32[i26 >> 2] | 0;
+  HEAP16[(HEAP32[i27 >> 2] | 0) + (i34 << 1) >> 1] = i31;
+  HEAP32[i26 >> 2] = i34 + 1;
+  HEAP8[(HEAP32[i29 >> 2] | 0) + i34 | 0] = i35;
+  i35 = i2 + ((HEAPU8[808 + (i35 & 255) | 0] | 0 | 256) + 1 << 2) + 148 | 0;
+  HEAP16[i35 >> 1] = (HEAP16[i35 >> 1] | 0) + 1 << 16 >> 16;
+  i31 = i31 + 65535 & 65535;
+  if (!(i31 >>> 0 < 256)) {
+   i31 = (i31 >>> 7) + 256 | 0;
+  }
+  i32 = i2 + ((HEAPU8[296 + i31 | 0] | 0) << 2) + 2440 | 0;
+  HEAP16[i32 >> 1] = (HEAP16[i32 >> 1] | 0) + 1 << 16 >> 16;
+  i32 = HEAP32[i26 >> 2] | 0;
+  i31 = (HEAP32[i23 >> 2] | 0) + -1 | 0;
+  i34 = HEAP32[i10 >> 2] | 0;
+  HEAP32[i15 >> 2] = 1 - i34 + (HEAP32[i15 >> 2] | 0);
+  i34 = i34 + -2 | 0;
+  HEAP32[i10 >> 2] = i34;
+  i33 = HEAP32[i5 >> 2] | 0;
+  while (1) {
+   i35 = i33 + 1 | 0;
+   HEAP32[i5 >> 2] = i35;
+   if (!(i35 >>> 0 > i30 >>> 0)) {
+    i36 = ((HEAPU8[(HEAP32[i7 >> 2] | 0) + (i33 + 3) | 0] | 0) ^ HEAP32[i17 >> 2] << HEAP32[i18 >> 2]) & HEAP32[i19 >> 2];
+    HEAP32[i17 >> 2] = i36;
+    i36 = (HEAP32[i20 >> 2] | 0) + (i36 << 1) | 0;
+    HEAP16[(HEAP32[i21 >> 2] | 0) + ((HEAP32[i22 >> 2] & i35) << 1) >> 1] = HEAP16[i36 >> 1] | 0;
+    HEAP16[i36 >> 1] = i35;
+   }
+   i34 = i34 + -1 | 0;
+   HEAP32[i10 >> 2] = i34;
+   if ((i34 | 0) == 0) {
+    break;
+   } else {
+    i33 = i35;
+   }
+  }
+  HEAP32[i8 >> 2] = 0;
+  HEAP32[i9 >> 2] = 2;
+  i30 = i33 + 2 | 0;
+  HEAP32[i5 >> 2] = i30;
+  if ((i32 | 0) != (i31 | 0)) {
+   continue;
+  }
+  i32 = HEAP32[i4 >> 2] | 0;
+  if ((i32 | 0) > -1) {
+   i31 = (HEAP32[i7 >> 2] | 0) + i32 | 0;
+  } else {
+   i31 = 0;
+  }
+  __tr_flush_block(i2, i31, i30 - i32 | 0, 0);
+  HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+  i33 = HEAP32[i2 >> 2] | 0;
+  i31 = i33 + 28 | 0;
+  i32 = HEAP32[i31 >> 2] | 0;
+  i35 = HEAP32[i32 + 20 >> 2] | 0;
+  i30 = i33 + 16 | 0;
+  i34 = HEAP32[i30 >> 2] | 0;
+  i34 = i35 >>> 0 > i34 >>> 0 ? i34 : i35;
+  if ((i34 | 0) != 0 ? (i25 = i33 + 12 | 0, _memcpy(HEAP32[i25 >> 2] | 0, HEAP32[i32 + 16 >> 2] | 0, i34 | 0) | 0, HEAP32[i25 >> 2] = (HEAP32[i25 >> 2] | 0) + i34, i25 = (HEAP32[i31 >> 2] | 0) + 16 | 0, HEAP32[i25 >> 2] = (HEAP32[i25 >> 2] | 0) + i34, i25 = i33 + 20 | 0, HEAP32[i25 >> 2] = (HEAP32[i25 >> 2] | 0) + i34, HEAP32[i30 >> 2] = (HEAP32[i30 >> 2] | 0) - i34, i25 = HEAP32[i31 >> 2] | 0, i35 = i25 + 20 | 0, i36 = HEAP32[i35 >> 2] | 0, HEAP32[i35 >> 2] = i36 - i34, (i36 | 0) == (i34 | 0)) : 0) {
+   HEAP32[i25 + 16 >> 2] = HEAP32[i25 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i2 = 0;
+   i30 = 50;
+   break;
+  }
+ }
+ if ((i30 | 0) == 40) {
+  if ((HEAP32[i8 >> 2] | 0) != 0) {
+   i36 = HEAP8[(HEAP32[i7 >> 2] | 0) + ((HEAP32[i5 >> 2] | 0) + -1) | 0] | 0;
+   i35 = HEAP32[i26 >> 2] | 0;
+   HEAP16[(HEAP32[i27 >> 2] | 0) + (i35 << 1) >> 1] = 0;
+   HEAP32[i26 >> 2] = i35 + 1;
+   HEAP8[(HEAP32[i29 >> 2] | 0) + i35 | 0] = i36;
+   i36 = i2 + ((i36 & 255) << 2) + 148 | 0;
+   HEAP16[i36 >> 1] = (HEAP16[i36 >> 1] | 0) + 1 << 16 >> 16;
+   HEAP32[i8 >> 2] = 0;
+  }
+  i8 = HEAP32[i4 >> 2] | 0;
+  if ((i8 | 0) > -1) {
+   i7 = (HEAP32[i7 >> 2] | 0) + i8 | 0;
+  } else {
+   i7 = 0;
+  }
+  i6 = (i6 | 0) == 4;
+  __tr_flush_block(i2, i7, (HEAP32[i5 >> 2] | 0) - i8 | 0, i6 & 1);
+  HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+  i4 = HEAP32[i2 >> 2] | 0;
+  i7 = i4 + 28 | 0;
+  i5 = HEAP32[i7 >> 2] | 0;
+  i10 = HEAP32[i5 + 20 >> 2] | 0;
+  i8 = i4 + 16 | 0;
+  i9 = HEAP32[i8 >> 2] | 0;
+  i9 = i10 >>> 0 > i9 >>> 0 ? i9 : i10;
+  if ((i9 | 0) != 0 ? (i3 = i4 + 12 | 0, _memcpy(HEAP32[i3 >> 2] | 0, HEAP32[i5 + 16 >> 2] | 0, i9 | 0) | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, i3 = (HEAP32[i7 >> 2] | 0) + 16 | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, i3 = i4 + 20 | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) - i9, i3 = HEAP32[i7 >> 2] | 0, i35 = i3 + 20 | 0, i36 = HEAP32[i35 >> 2] | 0, HEAP32[i35 >> 2] = i36 - i9, (i36 | 0) == (i9 | 0)) : 0) {
+   HEAP32[i3 + 16 >> 2] = HEAP32[i3 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i36 = i6 ? 2 : 0;
+   STACKTOP = i1;
+   return i36 | 0;
+  } else {
+   i36 = i6 ? 3 : 1;
+   STACKTOP = i1;
+   return i36 | 0;
+  }
+ } else if ((i30 | 0) == 50) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ return 0;
+}
+function _inflate_fast(i7, i19) {
+ i7 = i7 | 0;
+ i19 = i19 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0;
+ i1 = STACKTOP;
+ i11 = HEAP32[i7 + 28 >> 2] | 0;
+ i29 = HEAP32[i7 >> 2] | 0;
+ i5 = i7 + 4 | 0;
+ i8 = i29 + ((HEAP32[i5 >> 2] | 0) + -6) | 0;
+ i9 = i7 + 12 | 0;
+ i28 = HEAP32[i9 >> 2] | 0;
+ i4 = i7 + 16 | 0;
+ i25 = HEAP32[i4 >> 2] | 0;
+ i6 = i28 + (i25 + -258) | 0;
+ i17 = HEAP32[i11 + 44 >> 2] | 0;
+ i12 = HEAP32[i11 + 48 >> 2] | 0;
+ i18 = HEAP32[i11 + 52 >> 2] | 0;
+ i3 = i11 + 56 | 0;
+ i2 = i11 + 60 | 0;
+ i16 = HEAP32[i11 + 76 >> 2] | 0;
+ i13 = HEAP32[i11 + 80 >> 2] | 0;
+ i14 = (1 << HEAP32[i11 + 84 >> 2]) + -1 | 0;
+ i15 = (1 << HEAP32[i11 + 88 >> 2]) + -1 | 0;
+ i19 = i28 + (i25 + ~i19) | 0;
+ i25 = i11 + 7104 | 0;
+ i20 = i18 + -1 | 0;
+ i27 = (i12 | 0) == 0;
+ i24 = (HEAP32[i11 + 40 >> 2] | 0) + -1 | 0;
+ i21 = i24 + i12 | 0;
+ i22 = i12 + -1 | 0;
+ i23 = i19 + -1 | 0;
+ i26 = i19 - i12 | 0;
+ i31 = HEAP32[i2 >> 2] | 0;
+ i30 = HEAP32[i3 >> 2] | 0;
+ i29 = i29 + -1 | 0;
+ i28 = i28 + -1 | 0;
+ L1 : do {
+  if (i31 >>> 0 < 15) {
+   i37 = i29 + 2 | 0;
+   i33 = i31 + 16 | 0;
+   i30 = ((HEAPU8[i29 + 1 | 0] | 0) << i31) + i30 + ((HEAPU8[i37] | 0) << i31 + 8) | 0;
+   i29 = i37;
+  } else {
+   i33 = i31;
+  }
+  i31 = i30 & i14;
+  i34 = HEAP8[i16 + (i31 << 2) | 0] | 0;
+  i32 = HEAP16[i16 + (i31 << 2) + 2 >> 1] | 0;
+  i31 = HEAPU8[i16 + (i31 << 2) + 1 | 0] | 0;
+  i30 = i30 >>> i31;
+  i31 = i33 - i31 | 0;
+  do {
+   if (!(i34 << 24 >> 24 == 0)) {
+    i33 = i34 & 255;
+    while (1) {
+     if ((i33 & 16 | 0) != 0) {
+      break;
+     }
+     if ((i33 & 64 | 0) != 0) {
+      i10 = 55;
+      break L1;
+     }
+     i37 = (i30 & (1 << i33) + -1) + (i32 & 65535) | 0;
+     i33 = HEAP8[i16 + (i37 << 2) | 0] | 0;
+     i32 = HEAP16[i16 + (i37 << 2) + 2 >> 1] | 0;
+     i37 = HEAPU8[i16 + (i37 << 2) + 1 | 0] | 0;
+     i30 = i30 >>> i37;
+     i31 = i31 - i37 | 0;
+     if (i33 << 24 >> 24 == 0) {
+      i10 = 6;
+      break;
+     } else {
+      i33 = i33 & 255;
+     }
+    }
+    if ((i10 | 0) == 6) {
+     i32 = i32 & 255;
+     i10 = 7;
+     break;
+    }
+    i32 = i32 & 65535;
+    i33 = i33 & 15;
+    if ((i33 | 0) != 0) {
+     if (i31 >>> 0 < i33 >>> 0) {
+      i29 = i29 + 1 | 0;
+      i35 = i31 + 8 | 0;
+      i34 = ((HEAPU8[i29] | 0) << i31) + i30 | 0;
+     } else {
+      i35 = i31;
+      i34 = i30;
+     }
+     i31 = i35 - i33 | 0;
+     i30 = i34 >>> i33;
+     i32 = (i34 & (1 << i33) + -1) + i32 | 0;
+    }
+    if (i31 >>> 0 < 15) {
+     i37 = i29 + 2 | 0;
+     i34 = i31 + 16 | 0;
+     i30 = ((HEAPU8[i29 + 1 | 0] | 0) << i31) + i30 + ((HEAPU8[i37] | 0) << i31 + 8) | 0;
+     i29 = i37;
+    } else {
+     i34 = i31;
+    }
+    i37 = i30 & i15;
+    i33 = HEAP16[i13 + (i37 << 2) + 2 >> 1] | 0;
+    i31 = HEAPU8[i13 + (i37 << 2) + 1 | 0] | 0;
+    i30 = i30 >>> i31;
+    i31 = i34 - i31 | 0;
+    i34 = HEAPU8[i13 + (i37 << 2) | 0] | 0;
+    if ((i34 & 16 | 0) == 0) {
+     do {
+      if ((i34 & 64 | 0) != 0) {
+       i10 = 52;
+       break L1;
+      }
+      i34 = (i30 & (1 << i34) + -1) + (i33 & 65535) | 0;
+      i33 = HEAP16[i13 + (i34 << 2) + 2 >> 1] | 0;
+      i37 = HEAPU8[i13 + (i34 << 2) + 1 | 0] | 0;
+      i30 = i30 >>> i37;
+      i31 = i31 - i37 | 0;
+      i34 = HEAPU8[i13 + (i34 << 2) | 0] | 0;
+     } while ((i34 & 16 | 0) == 0);
+    }
+    i33 = i33 & 65535;
+    i34 = i34 & 15;
+    if (i31 >>> 0 < i34 >>> 0) {
+     i35 = i29 + 1 | 0;
+     i30 = ((HEAPU8[i35] | 0) << i31) + i30 | 0;
+     i36 = i31 + 8 | 0;
+     if (i36 >>> 0 < i34 >>> 0) {
+      i29 = i29 + 2 | 0;
+      i31 = i31 + 16 | 0;
+      i30 = ((HEAPU8[i29] | 0) << i36) + i30 | 0;
+     } else {
+      i31 = i36;
+      i29 = i35;
+     }
+    }
+    i33 = (i30 & (1 << i34) + -1) + i33 | 0;
+    i30 = i30 >>> i34;
+    i31 = i31 - i34 | 0;
+    i35 = i28;
+    i34 = i35 - i19 | 0;
+    if (!(i33 >>> 0 > i34 >>> 0)) {
+     i34 = i28 + (0 - i33) | 0;
+     while (1) {
+      HEAP8[i28 + 1 | 0] = HEAP8[i34 + 1 | 0] | 0;
+      HEAP8[i28 + 2 | 0] = HEAP8[i34 + 2 | 0] | 0;
+      i35 = i34 + 3 | 0;
+      i33 = i28 + 3 | 0;
+      HEAP8[i33] = HEAP8[i35] | 0;
+      i32 = i32 + -3 | 0;
+      if (!(i32 >>> 0 > 2)) {
+       break;
+      } else {
+       i34 = i35;
+       i28 = i33;
+      }
+     }
+     if ((i32 | 0) == 0) {
+      i28 = i33;
+      break;
+     }
+     i33 = i28 + 4 | 0;
+     HEAP8[i33] = HEAP8[i34 + 4 | 0] | 0;
+     if (!(i32 >>> 0 > 1)) {
+      i28 = i33;
+      break;
+     }
+     i28 = i28 + 5 | 0;
+     HEAP8[i28] = HEAP8[i34 + 5 | 0] | 0;
+     break;
+    }
+    i34 = i33 - i34 | 0;
+    if (i34 >>> 0 > i17 >>> 0 ? (HEAP32[i25 >> 2] | 0) != 0 : 0) {
+     i10 = 22;
+     break L1;
+    }
+    do {
+     if (i27) {
+      i36 = i18 + (i24 - i34) | 0;
+      if (i34 >>> 0 < i32 >>> 0) {
+       i32 = i32 - i34 | 0;
+       i35 = i33 - i35 | 0;
+       i37 = i28;
+       do {
+        i36 = i36 + 1 | 0;
+        i37 = i37 + 1 | 0;
+        HEAP8[i37] = HEAP8[i36] | 0;
+        i34 = i34 + -1 | 0;
+       } while ((i34 | 0) != 0);
+       i33 = i28 + (i23 + i35 + (1 - i33)) | 0;
+       i28 = i28 + (i19 + i35) | 0;
+      } else {
+       i33 = i36;
+      }
+     } else {
+      if (!(i12 >>> 0 < i34 >>> 0)) {
+       i36 = i18 + (i22 - i34) | 0;
+       if (!(i34 >>> 0 < i32 >>> 0)) {
+        i33 = i36;
+        break;
+       }
+       i32 = i32 - i34 | 0;
+       i35 = i33 - i35 | 0;
+       i37 = i28;
+       do {
+        i36 = i36 + 1 | 0;
+        i37 = i37 + 1 | 0;
+        HEAP8[i37] = HEAP8[i36] | 0;
+        i34 = i34 + -1 | 0;
+       } while ((i34 | 0) != 0);
+       i33 = i28 + (i23 + i35 + (1 - i33)) | 0;
+       i28 = i28 + (i19 + i35) | 0;
+       break;
+      }
+      i37 = i18 + (i21 - i34) | 0;
+      i36 = i34 - i12 | 0;
+      if (i36 >>> 0 < i32 >>> 0) {
+       i32 = i32 - i36 | 0;
+       i34 = i33 - i35 | 0;
+       i35 = i28;
+       do {
+        i37 = i37 + 1 | 0;
+        i35 = i35 + 1 | 0;
+        HEAP8[i35] = HEAP8[i37] | 0;
+        i36 = i36 + -1 | 0;
+       } while ((i36 | 0) != 0);
+       i35 = i28 + (i26 + i34) | 0;
+       if (i12 >>> 0 < i32 >>> 0) {
+        i32 = i32 - i12 | 0;
+        i37 = i20;
+        i36 = i12;
+        do {
+         i37 = i37 + 1 | 0;
+         i35 = i35 + 1 | 0;
+         HEAP8[i35] = HEAP8[i37] | 0;
+         i36 = i36 + -1 | 0;
+        } while ((i36 | 0) != 0);
+        i33 = i28 + (i23 + i34 + (1 - i33)) | 0;
+        i28 = i28 + (i19 + i34) | 0;
+       } else {
+        i33 = i20;
+        i28 = i35;
+       }
+      } else {
+       i33 = i37;
+      }
+     }
+    } while (0);
+    if (i32 >>> 0 > 2) {
+     do {
+      HEAP8[i28 + 1 | 0] = HEAP8[i33 + 1 | 0] | 0;
+      HEAP8[i28 + 2 | 0] = HEAP8[i33 + 2 | 0] | 0;
+      i33 = i33 + 3 | 0;
+      i28 = i28 + 3 | 0;
+      HEAP8[i28] = HEAP8[i33] | 0;
+      i32 = i32 + -3 | 0;
+     } while (i32 >>> 0 > 2);
+    }
+    if ((i32 | 0) != 0) {
+     i34 = i28 + 1 | 0;
+     HEAP8[i34] = HEAP8[i33 + 1 | 0] | 0;
+     if (i32 >>> 0 > 1) {
+      i28 = i28 + 2 | 0;
+      HEAP8[i28] = HEAP8[i33 + 2 | 0] | 0;
+     } else {
+      i28 = i34;
+     }
+    }
+   } else {
+    i32 = i32 & 255;
+    i10 = 7;
+   }
+  } while (0);
+  if ((i10 | 0) == 7) {
+   i10 = 0;
+   i28 = i28 + 1 | 0;
+   HEAP8[i28] = i32;
+  }
+ } while (i29 >>> 0 < i8 >>> 0 & i28 >>> 0 < i6 >>> 0);
+ do {
+  if ((i10 | 0) == 22) {
+   HEAP32[i7 + 24 >> 2] = 14384;
+   HEAP32[i11 >> 2] = 29;
+  } else if ((i10 | 0) == 52) {
+   HEAP32[i7 + 24 >> 2] = 14416;
+   HEAP32[i11 >> 2] = 29;
+  } else if ((i10 | 0) == 55) {
+   if ((i33 & 32 | 0) == 0) {
+    HEAP32[i7 + 24 >> 2] = 14440;
+    HEAP32[i11 >> 2] = 29;
+    break;
+   } else {
+    HEAP32[i11 >> 2] = 11;
+    break;
+   }
+  }
+ } while (0);
+ i37 = i31 >>> 3;
+ i11 = i29 + (0 - i37) | 0;
+ i10 = i31 - (i37 << 3) | 0;
+ i12 = (1 << i10) + -1 & i30;
+ HEAP32[i7 >> 2] = i29 + (1 - i37);
+ HEAP32[i9 >> 2] = i28 + 1;
+ if (i11 >>> 0 < i8 >>> 0) {
+  i7 = i8 - i11 | 0;
+ } else {
+  i7 = i8 - i11 | 0;
+ }
+ HEAP32[i5 >> 2] = i7 + 5;
+ if (i28 >>> 0 < i6 >>> 0) {
+  i37 = i6 - i28 | 0;
+  i37 = i37 + 257 | 0;
+  HEAP32[i4 >> 2] = i37;
+  HEAP32[i3 >> 2] = i12;
+  HEAP32[i2 >> 2] = i10;
+  STACKTOP = i1;
+  return;
+ } else {
+  i37 = i6 - i28 | 0;
+  i37 = i37 + 257 | 0;
+  HEAP32[i4 >> 2] = i37;
+  HEAP32[i3 >> 2] = i12;
+  HEAP32[i2 >> 2] = i10;
+  STACKTOP = i1;
+  return;
+ }
+}
+function _send_tree(i2, i13, i12) {
+ i2 = i2 | 0;
+ i13 = i13 | 0;
+ i12 = i12 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0;
+ i11 = STACKTOP;
+ i15 = HEAP16[i13 + 2 >> 1] | 0;
+ i16 = i15 << 16 >> 16 == 0;
+ i7 = i2 + 2754 | 0;
+ i4 = i2 + 5820 | 0;
+ i8 = i2 + 2752 | 0;
+ i3 = i2 + 5816 | 0;
+ i14 = i2 + 20 | 0;
+ i10 = i2 + 8 | 0;
+ i9 = i2 + 2758 | 0;
+ i1 = i2 + 2756 | 0;
+ i5 = i2 + 2750 | 0;
+ i6 = i2 + 2748 | 0;
+ i21 = i16 ? 138 : 7;
+ i23 = i16 ? 3 : 4;
+ i18 = 0;
+ i15 = i15 & 65535;
+ i24 = -1;
+ L1 : while (1) {
+  i20 = 0;
+  while (1) {
+   if ((i18 | 0) > (i12 | 0)) {
+    break L1;
+   }
+   i18 = i18 + 1 | 0;
+   i19 = HEAP16[i13 + (i18 << 2) + 2 >> 1] | 0;
+   i16 = i19 & 65535;
+   i22 = i20 + 1 | 0;
+   i17 = (i15 | 0) == (i16 | 0);
+   if (!((i22 | 0) < (i21 | 0) & i17)) {
+    break;
+   } else {
+    i20 = i22;
+   }
+  }
+  do {
+   if ((i22 | 0) >= (i23 | 0)) {
+    if ((i15 | 0) != 0) {
+     if ((i15 | 0) == (i24 | 0)) {
+      i23 = HEAP16[i3 >> 1] | 0;
+      i21 = HEAP32[i4 >> 2] | 0;
+      i20 = i22;
+     } else {
+      i22 = HEAPU16[i2 + (i15 << 2) + 2686 >> 1] | 0;
+      i21 = HEAP32[i4 >> 2] | 0;
+      i24 = HEAPU16[i2 + (i15 << 2) + 2684 >> 1] | 0;
+      i25 = HEAPU16[i3 >> 1] | 0 | i24 << i21;
+      i23 = i25 & 65535;
+      HEAP16[i3 >> 1] = i23;
+      if ((i21 | 0) > (16 - i22 | 0)) {
+       i23 = HEAP32[i14 >> 2] | 0;
+       HEAP32[i14 >> 2] = i23 + 1;
+       HEAP8[(HEAP32[i10 >> 2] | 0) + i23 | 0] = i25;
+       i23 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+       i21 = HEAP32[i14 >> 2] | 0;
+       HEAP32[i14 >> 2] = i21 + 1;
+       HEAP8[(HEAP32[i10 >> 2] | 0) + i21 | 0] = i23;
+       i21 = HEAP32[i4 >> 2] | 0;
+       i23 = i24 >>> (16 - i21 | 0) & 65535;
+       HEAP16[i3 >> 1] = i23;
+       i21 = i22 + -16 + i21 | 0;
+      } else {
+       i21 = i21 + i22 | 0;
+      }
+      HEAP32[i4 >> 2] = i21;
+     }
+     i22 = HEAPU16[i5 >> 1] | 0;
+     i24 = HEAPU16[i6 >> 1] | 0;
+     i23 = i23 & 65535 | i24 << i21;
+     HEAP16[i3 >> 1] = i23;
+     if ((i21 | 0) > (16 - i22 | 0)) {
+      i21 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i21 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i21 | 0] = i23;
+      i23 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i21 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i21 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i21 | 0] = i23;
+      i21 = HEAP32[i4 >> 2] | 0;
+      i23 = i24 >>> (16 - i21 | 0);
+      HEAP16[i3 >> 1] = i23;
+      i21 = i22 + -16 + i21 | 0;
+     } else {
+      i21 = i21 + i22 | 0;
+     }
+     HEAP32[i4 >> 2] = i21;
+     i20 = i20 + 65533 & 65535;
+     i22 = i23 & 65535 | i20 << i21;
+     HEAP16[i3 >> 1] = i22;
+     if ((i21 | 0) > 14) {
+      i26 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i26 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i26 | 0] = i22;
+      i26 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i26;
+      i27 = HEAP32[i4 >> 2] | 0;
+      HEAP16[i3 >> 1] = i20 >>> (16 - i27 | 0);
+      HEAP32[i4 >> 2] = i27 + -14;
+      break;
+     } else {
+      HEAP32[i4 >> 2] = i21 + 2;
+      break;
+     }
+    }
+    if ((i22 | 0) < 11) {
+     i24 = HEAPU16[i7 >> 1] | 0;
+     i23 = HEAP32[i4 >> 2] | 0;
+     i21 = HEAPU16[i8 >> 1] | 0;
+     i22 = HEAPU16[i3 >> 1] | 0 | i21 << i23;
+     HEAP16[i3 >> 1] = i22;
+     if ((i23 | 0) > (16 - i24 | 0)) {
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i22;
+      i22 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i22;
+      i27 = HEAP32[i4 >> 2] | 0;
+      i22 = i21 >>> (16 - i27 | 0);
+      HEAP16[i3 >> 1] = i22;
+      i21 = i24 + -16 + i27 | 0;
+     } else {
+      i21 = i23 + i24 | 0;
+     }
+     HEAP32[i4 >> 2] = i21;
+     i20 = i20 + 65534 & 65535;
+     i22 = i22 & 65535 | i20 << i21;
+     HEAP16[i3 >> 1] = i22;
+     if ((i21 | 0) > 13) {
+      i26 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i26 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i26 | 0] = i22;
+      i26 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i26;
+      i27 = HEAP32[i4 >> 2] | 0;
+      HEAP16[i3 >> 1] = i20 >>> (16 - i27 | 0);
+      HEAP32[i4 >> 2] = i27 + -13;
+      break;
+     } else {
+      HEAP32[i4 >> 2] = i21 + 3;
+      break;
+     }
+    } else {
+     i21 = HEAPU16[i9 >> 1] | 0;
+     i24 = HEAP32[i4 >> 2] | 0;
+     i23 = HEAPU16[i1 >> 1] | 0;
+     i22 = HEAPU16[i3 >> 1] | 0 | i23 << i24;
+     HEAP16[i3 >> 1] = i22;
+     if ((i24 | 0) > (16 - i21 | 0)) {
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i22;
+      i22 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i22;
+      i27 = HEAP32[i4 >> 2] | 0;
+      i22 = i23 >>> (16 - i27 | 0);
+      HEAP16[i3 >> 1] = i22;
+      i21 = i21 + -16 + i27 | 0;
+     } else {
+      i21 = i24 + i21 | 0;
+     }
+     HEAP32[i4 >> 2] = i21;
+     i20 = i20 + 65526 & 65535;
+     i22 = i22 & 65535 | i20 << i21;
+     HEAP16[i3 >> 1] = i22;
+     if ((i21 | 0) > 9) {
+      i26 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i26 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i26 | 0] = i22;
+      i26 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i27 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i27 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i27 | 0] = i26;
+      i27 = HEAP32[i4 >> 2] | 0;
+      HEAP16[i3 >> 1] = i20 >>> (16 - i27 | 0);
+      HEAP32[i4 >> 2] = i27 + -9;
+      break;
+     } else {
+      HEAP32[i4 >> 2] = i21 + 7;
+      break;
+     }
+    }
+   } else {
+    i20 = i2 + (i15 << 2) + 2686 | 0;
+    i21 = i2 + (i15 << 2) + 2684 | 0;
+    i23 = HEAP32[i4 >> 2] | 0;
+    i26 = HEAP16[i3 >> 1] | 0;
+    do {
+     i24 = HEAPU16[i20 >> 1] | 0;
+     i25 = HEAPU16[i21 >> 1] | 0;
+     i27 = i26 & 65535 | i25 << i23;
+     i26 = i27 & 65535;
+     HEAP16[i3 >> 1] = i26;
+     if ((i23 | 0) > (16 - i24 | 0)) {
+      i26 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i26 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i26 | 0] = i27;
+      i26 = (HEAPU16[i3 >> 1] | 0) >>> 8 & 255;
+      i23 = HEAP32[i14 >> 2] | 0;
+      HEAP32[i14 >> 2] = i23 + 1;
+      HEAP8[(HEAP32[i10 >> 2] | 0) + i23 | 0] = i26;
+      i23 = HEAP32[i4 >> 2] | 0;
+      i26 = i25 >>> (16 - i23 | 0) & 65535;
+      HEAP16[i3 >> 1] = i26;
+      i23 = i24 + -16 + i23 | 0;
+     } else {
+      i23 = i23 + i24 | 0;
+     }
+     HEAP32[i4 >> 2] = i23;
+     i22 = i22 + -1 | 0;
+    } while ((i22 | 0) != 0);
+   }
+  } while (0);
+  if (i19 << 16 >> 16 == 0) {
+   i24 = i15;
+   i21 = 138;
+   i23 = 3;
+   i15 = i16;
+   continue;
+  }
+  i24 = i15;
+  i21 = i17 ? 6 : 7;
+  i23 = i17 ? 3 : 4;
+  i15 = i16;
+ }
+ STACKTOP = i11;
+ return;
+}
+function __tr_flush_block(i2, i4, i6, i3) {
+ i2 = i2 | 0;
+ i4 = i4 | 0;
+ i6 = i6 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i1 = STACKTOP;
+ if ((HEAP32[i2 + 132 >> 2] | 0) > 0) {
+  i5 = (HEAP32[i2 >> 2] | 0) + 44 | 0;
+  if ((HEAP32[i5 >> 2] | 0) == 2) {
+   i8 = -201342849;
+   i9 = 0;
+   while (1) {
+    if ((i8 & 1 | 0) != 0 ? (HEAP16[i2 + (i9 << 2) + 148 >> 1] | 0) != 0 : 0) {
+     i8 = 0;
+     break;
+    }
+    i9 = i9 + 1 | 0;
+    if ((i9 | 0) < 32) {
+     i8 = i8 >>> 1;
+    } else {
+     i7 = 6;
+     break;
+    }
+   }
+   L9 : do {
+    if ((i7 | 0) == 6) {
+     if (((HEAP16[i2 + 184 >> 1] | 0) == 0 ? (HEAP16[i2 + 188 >> 1] | 0) == 0 : 0) ? (HEAP16[i2 + 200 >> 1] | 0) == 0 : 0) {
+      i8 = 32;
+      while (1) {
+       i7 = i8 + 1 | 0;
+       if ((HEAP16[i2 + (i8 << 2) + 148 >> 1] | 0) != 0) {
+        i8 = 1;
+        break L9;
+       }
+       if ((i7 | 0) < 256) {
+        i8 = i7;
+       } else {
+        i8 = 0;
+        break;
+       }
+      }
+     } else {
+      i8 = 1;
+     }
+    }
+   } while (0);
+   HEAP32[i5 >> 2] = i8;
+  }
+  _build_tree(i2, i2 + 2840 | 0);
+  _build_tree(i2, i2 + 2852 | 0);
+  _scan_tree(i2, i2 + 148 | 0, HEAP32[i2 + 2844 >> 2] | 0);
+  _scan_tree(i2, i2 + 2440 | 0, HEAP32[i2 + 2856 >> 2] | 0);
+  _build_tree(i2, i2 + 2864 | 0);
+  i5 = 18;
+  while (1) {
+   i7 = i5 + -1 | 0;
+   if ((HEAP16[i2 + (HEAPU8[2888 + i5 | 0] << 2) + 2686 >> 1] | 0) != 0) {
+    break;
+   }
+   if ((i7 | 0) > 2) {
+    i5 = i7;
+   } else {
+    i5 = i7;
+    break;
+   }
+  }
+  i10 = i2 + 5800 | 0;
+  i7 = (i5 * 3 | 0) + 17 + (HEAP32[i10 >> 2] | 0) | 0;
+  HEAP32[i10 >> 2] = i7;
+  i7 = (i7 + 10 | 0) >>> 3;
+  i10 = ((HEAP32[i2 + 5804 >> 2] | 0) + 10 | 0) >>> 3;
+  i9 = i10 >>> 0 > i7 >>> 0 ? i7 : i10;
+ } else {
+  i10 = i6 + 5 | 0;
+  i5 = 0;
+  i9 = i10;
+ }
+ do {
+  if ((i6 + 4 | 0) >>> 0 > i9 >>> 0 | (i4 | 0) == 0) {
+   i4 = i2 + 5820 | 0;
+   i7 = HEAP32[i4 >> 2] | 0;
+   i8 = (i7 | 0) > 13;
+   if ((HEAP32[i2 + 136 >> 2] | 0) == 4 | (i10 | 0) == (i9 | 0)) {
+    i9 = i3 + 2 & 65535;
+    i6 = i2 + 5816 | 0;
+    i5 = HEAPU16[i6 >> 1] | i9 << i7;
+    HEAP16[i6 >> 1] = i5;
+    if (i8) {
+     i12 = i2 + 20 | 0;
+     i13 = HEAP32[i12 >> 2] | 0;
+     HEAP32[i12 >> 2] = i13 + 1;
+     i14 = i2 + 8 | 0;
+     HEAP8[(HEAP32[i14 >> 2] | 0) + i13 | 0] = i5;
+     i13 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+     i5 = HEAP32[i12 >> 2] | 0;
+     HEAP32[i12 >> 2] = i5 + 1;
+     HEAP8[(HEAP32[i14 >> 2] | 0) + i5 | 0] = i13;
+     i5 = HEAP32[i4 >> 2] | 0;
+     HEAP16[i6 >> 1] = i9 >>> (16 - i5 | 0);
+     i5 = i5 + -13 | 0;
+    } else {
+     i5 = i7 + 3 | 0;
+    }
+    HEAP32[i4 >> 2] = i5;
+    _compress_block(i2, 1136, 2288);
+    break;
+   }
+   i10 = i3 + 4 & 65535;
+   i6 = i2 + 5816 | 0;
+   i9 = HEAPU16[i6 >> 1] | i10 << i7;
+   HEAP16[i6 >> 1] = i9;
+   if (i8) {
+    i13 = i2 + 20 | 0;
+    i12 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i12 + 1;
+    i14 = i2 + 8 | 0;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i12 | 0] = i9;
+    i9 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+    i12 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i12 + 1;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i12 | 0] = i9;
+    i12 = HEAP32[i4 >> 2] | 0;
+    i9 = i10 >>> (16 - i12 | 0);
+    HEAP16[i6 >> 1] = i9;
+    i12 = i12 + -13 | 0;
+   } else {
+    i12 = i7 + 3 | 0;
+   }
+   HEAP32[i4 >> 2] = i12;
+   i7 = HEAP32[i2 + 2844 >> 2] | 0;
+   i8 = HEAP32[i2 + 2856 >> 2] | 0;
+   i10 = i7 + 65280 & 65535;
+   i11 = i9 & 65535 | i10 << i12;
+   HEAP16[i6 >> 1] = i11;
+   if ((i12 | 0) > 11) {
+    i13 = i2 + 20 | 0;
+    i9 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i9 + 1;
+    i14 = i2 + 8 | 0;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i9 | 0] = i11;
+    i11 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+    i9 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i9 + 1;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i9 | 0] = i11;
+    i9 = HEAP32[i4 >> 2] | 0;
+    i11 = i10 >>> (16 - i9 | 0);
+    HEAP16[i6 >> 1] = i11;
+    i9 = i9 + -11 | 0;
+   } else {
+    i9 = i12 + 5 | 0;
+   }
+   HEAP32[i4 >> 2] = i9;
+   i10 = i8 & 65535;
+   i11 = i10 << i9 | i11 & 65535;
+   HEAP16[i6 >> 1] = i11;
+   if ((i9 | 0) > 11) {
+    i13 = i2 + 20 | 0;
+    i9 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i9 + 1;
+    i14 = i2 + 8 | 0;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i9 | 0] = i11;
+    i11 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+    i9 = HEAP32[i13 >> 2] | 0;
+    HEAP32[i13 >> 2] = i9 + 1;
+    HEAP8[(HEAP32[i14 >> 2] | 0) + i9 | 0] = i11;
+    i9 = HEAP32[i4 >> 2] | 0;
+    i11 = i10 >>> (16 - i9 | 0);
+    HEAP16[i6 >> 1] = i11;
+    i9 = i9 + -11 | 0;
+   } else {
+    i9 = i9 + 5 | 0;
+   }
+   HEAP32[i4 >> 2] = i9;
+   i10 = i5 + 65533 & 65535;
+   i14 = i10 << i9 | i11 & 65535;
+   HEAP16[i6 >> 1] = i14;
+   if ((i9 | 0) > 12) {
+    i12 = i2 + 20 | 0;
+    i11 = HEAP32[i12 >> 2] | 0;
+    HEAP32[i12 >> 2] = i11 + 1;
+    i13 = i2 + 8 | 0;
+    HEAP8[(HEAP32[i13 >> 2] | 0) + i11 | 0] = i14;
+    i14 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+    i11 = HEAP32[i12 >> 2] | 0;
+    HEAP32[i12 >> 2] = i11 + 1;
+    HEAP8[(HEAP32[i13 >> 2] | 0) + i11 | 0] = i14;
+    i11 = HEAP32[i4 >> 2] | 0;
+    i14 = i10 >>> (16 - i11 | 0);
+    HEAP16[i6 >> 1] = i14;
+    i11 = i11 + -12 | 0;
+   } else {
+    i11 = i9 + 4 | 0;
+   }
+   HEAP32[i4 >> 2] = i11;
+   if ((i5 | 0) > -1) {
+    i10 = i2 + 20 | 0;
+    i9 = i2 + 8 | 0;
+    i12 = 0;
+    while (1) {
+     i13 = HEAPU16[i2 + (HEAPU8[2888 + i12 | 0] << 2) + 2686 >> 1] | 0;
+     i14 = i13 << i11 | i14 & 65535;
+     HEAP16[i6 >> 1] = i14;
+     if ((i11 | 0) > 13) {
+      i11 = HEAP32[i10 >> 2] | 0;
+      HEAP32[i10 >> 2] = i11 + 1;
+      HEAP8[(HEAP32[i9 >> 2] | 0) + i11 | 0] = i14;
+      i14 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+      i11 = HEAP32[i10 >> 2] | 0;
+      HEAP32[i10 >> 2] = i11 + 1;
+      HEAP8[(HEAP32[i9 >> 2] | 0) + i11 | 0] = i14;
+      i11 = HEAP32[i4 >> 2] | 0;
+      i14 = i13 >>> (16 - i11 | 0);
+      HEAP16[i6 >> 1] = i14;
+      i11 = i11 + -13 | 0;
+     } else {
+      i11 = i11 + 3 | 0;
+     }
+     HEAP32[i4 >> 2] = i11;
+     if ((i12 | 0) == (i5 | 0)) {
+      break;
+     } else {
+      i12 = i12 + 1 | 0;
+     }
+    }
+   }
+   i13 = i2 + 148 | 0;
+   _send_tree(i2, i13, i7);
+   i14 = i2 + 2440 | 0;
+   _send_tree(i2, i14, i8);
+   _compress_block(i2, i13, i14);
+  } else {
+   __tr_stored_block(i2, i4, i6, i3);
+  }
+ } while (0);
+ _init_block(i2);
+ if ((i3 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ i3 = i2 + 5820 | 0;
+ i4 = HEAP32[i3 >> 2] | 0;
+ if ((i4 | 0) <= 8) {
+  i5 = i2 + 5816 | 0;
+  if ((i4 | 0) > 0) {
+   i13 = HEAP16[i5 >> 1] & 255;
+   i12 = i2 + 20 | 0;
+   i14 = HEAP32[i12 >> 2] | 0;
+   HEAP32[i12 >> 2] = i14 + 1;
+   HEAP8[(HEAP32[i2 + 8 >> 2] | 0) + i14 | 0] = i13;
+  }
+ } else {
+  i5 = i2 + 5816 | 0;
+  i14 = HEAP16[i5 >> 1] & 255;
+  i11 = i2 + 20 | 0;
+  i12 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i12 + 1;
+  i13 = i2 + 8 | 0;
+  HEAP8[(HEAP32[i13 >> 2] | 0) + i12 | 0] = i14;
+  i12 = (HEAPU16[i5 >> 1] | 0) >>> 8 & 255;
+  i14 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i14 + 1;
+  HEAP8[(HEAP32[i13 >> 2] | 0) + i14 | 0] = i12;
+ }
+ HEAP16[i5 >> 1] = 0;
+ HEAP32[i3 >> 2] = 0;
+ STACKTOP = i1;
+ return;
+}
+function _deflate_fast(i3, i6) {
+ i3 = i3 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i2 = 0, i4 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0;
+ i1 = STACKTOP;
+ i20 = i3 + 116 | 0;
+ i22 = (i6 | 0) == 0;
+ i23 = i3 + 72 | 0;
+ i24 = i3 + 88 | 0;
+ i5 = i3 + 108 | 0;
+ i7 = i3 + 56 | 0;
+ i9 = i3 + 84 | 0;
+ i10 = i3 + 68 | 0;
+ i11 = i3 + 52 | 0;
+ i12 = i3 + 64 | 0;
+ i19 = i3 + 44 | 0;
+ i21 = i3 + 96 | 0;
+ i16 = i3 + 112 | 0;
+ i13 = i3 + 5792 | 0;
+ i17 = i3 + 5796 | 0;
+ i18 = i3 + 5784 | 0;
+ i14 = i3 + 5788 | 0;
+ i15 = i3 + 128 | 0;
+ i4 = i3 + 92 | 0;
+ while (1) {
+  if ((HEAP32[i20 >> 2] | 0) >>> 0 < 262) {
+   _fill_window(i3);
+   i25 = HEAP32[i20 >> 2] | 0;
+   if (i25 >>> 0 < 262 & i22) {
+    i2 = 0;
+    i25 = 34;
+    break;
+   }
+   if ((i25 | 0) == 0) {
+    i25 = 26;
+    break;
+   }
+   if (!(i25 >>> 0 > 2)) {
+    i25 = 9;
+   } else {
+    i25 = 6;
+   }
+  } else {
+   i25 = 6;
+  }
+  if ((i25 | 0) == 6) {
+   i25 = 0;
+   i26 = HEAP32[i5 >> 2] | 0;
+   i34 = ((HEAPU8[(HEAP32[i7 >> 2] | 0) + (i26 + 2) | 0] | 0) ^ HEAP32[i23 >> 2] << HEAP32[i24 >> 2]) & HEAP32[i9 >> 2];
+   HEAP32[i23 >> 2] = i34;
+   i34 = (HEAP32[i10 >> 2] | 0) + (i34 << 1) | 0;
+   i35 = HEAP16[i34 >> 1] | 0;
+   HEAP16[(HEAP32[i12 >> 2] | 0) + ((HEAP32[i11 >> 2] & i26) << 1) >> 1] = i35;
+   i27 = i35 & 65535;
+   HEAP16[i34 >> 1] = i26;
+   if (!(i35 << 16 >> 16 == 0) ? !((i26 - i27 | 0) >>> 0 > ((HEAP32[i19 >> 2] | 0) + -262 | 0) >>> 0) : 0) {
+    i26 = _longest_match(i3, i27) | 0;
+    HEAP32[i21 >> 2] = i26;
+   } else {
+    i25 = 9;
+   }
+  }
+  if ((i25 | 0) == 9) {
+   i26 = HEAP32[i21 >> 2] | 0;
+  }
+  do {
+   if (i26 >>> 0 > 2) {
+    i35 = i26 + 253 | 0;
+    i25 = (HEAP32[i5 >> 2] | 0) - (HEAP32[i16 >> 2] | 0) | 0;
+    i34 = HEAP32[i13 >> 2] | 0;
+    HEAP16[(HEAP32[i17 >> 2] | 0) + (i34 << 1) >> 1] = i25;
+    HEAP32[i13 >> 2] = i34 + 1;
+    HEAP8[(HEAP32[i18 >> 2] | 0) + i34 | 0] = i35;
+    i35 = i3 + ((HEAPU8[808 + (i35 & 255) | 0] | 0 | 256) + 1 << 2) + 148 | 0;
+    HEAP16[i35 >> 1] = (HEAP16[i35 >> 1] | 0) + 1 << 16 >> 16;
+    i25 = i25 + 65535 & 65535;
+    if (!(i25 >>> 0 < 256)) {
+     i25 = (i25 >>> 7) + 256 | 0;
+    }
+    i25 = i3 + ((HEAPU8[296 + i25 | 0] | 0) << 2) + 2440 | 0;
+    HEAP16[i25 >> 1] = (HEAP16[i25 >> 1] | 0) + 1 << 16 >> 16;
+    i25 = (HEAP32[i13 >> 2] | 0) == ((HEAP32[i14 >> 2] | 0) + -1 | 0) | 0;
+    i26 = HEAP32[i21 >> 2] | 0;
+    i35 = (HEAP32[i20 >> 2] | 0) - i26 | 0;
+    HEAP32[i20 >> 2] = i35;
+    if (!(i26 >>> 0 <= (HEAP32[i15 >> 2] | 0) >>> 0 & i35 >>> 0 > 2)) {
+     i26 = (HEAP32[i5 >> 2] | 0) + i26 | 0;
+     HEAP32[i5 >> 2] = i26;
+     HEAP32[i21 >> 2] = 0;
+     i34 = HEAP32[i7 >> 2] | 0;
+     i35 = HEAPU8[i34 + i26 | 0] | 0;
+     HEAP32[i23 >> 2] = i35;
+     HEAP32[i23 >> 2] = ((HEAPU8[i34 + (i26 + 1) | 0] | 0) ^ i35 << HEAP32[i24 >> 2]) & HEAP32[i9 >> 2];
+     break;
+    }
+    i30 = i26 + -1 | 0;
+    HEAP32[i21 >> 2] = i30;
+    i34 = HEAP32[i24 >> 2] | 0;
+    i33 = HEAP32[i7 >> 2] | 0;
+    i35 = HEAP32[i9 >> 2] | 0;
+    i32 = HEAP32[i10 >> 2] | 0;
+    i27 = HEAP32[i11 >> 2] | 0;
+    i29 = HEAP32[i12 >> 2] | 0;
+    i26 = HEAP32[i5 >> 2] | 0;
+    i31 = HEAP32[i23 >> 2] | 0;
+    while (1) {
+     i28 = i26 + 1 | 0;
+     HEAP32[i5 >> 2] = i28;
+     i31 = ((HEAPU8[i33 + (i26 + 3) | 0] | 0) ^ i31 << i34) & i35;
+     HEAP32[i23 >> 2] = i31;
+     i36 = i32 + (i31 << 1) | 0;
+     HEAP16[i29 + ((i27 & i28) << 1) >> 1] = HEAP16[i36 >> 1] | 0;
+     HEAP16[i36 >> 1] = i28;
+     i30 = i30 + -1 | 0;
+     HEAP32[i21 >> 2] = i30;
+     if ((i30 | 0) == 0) {
+      break;
+     } else {
+      i26 = i28;
+     }
+    }
+    i26 = i26 + 2 | 0;
+    HEAP32[i5 >> 2] = i26;
+   } else {
+    i25 = HEAP8[(HEAP32[i7 >> 2] | 0) + (HEAP32[i5 >> 2] | 0) | 0] | 0;
+    i26 = HEAP32[i13 >> 2] | 0;
+    HEAP16[(HEAP32[i17 >> 2] | 0) + (i26 << 1) >> 1] = 0;
+    HEAP32[i13 >> 2] = i26 + 1;
+    HEAP8[(HEAP32[i18 >> 2] | 0) + i26 | 0] = i25;
+    i25 = i3 + ((i25 & 255) << 2) + 148 | 0;
+    HEAP16[i25 >> 1] = (HEAP16[i25 >> 1] | 0) + 1 << 16 >> 16;
+    i25 = (HEAP32[i13 >> 2] | 0) == ((HEAP32[i14 >> 2] | 0) + -1 | 0) | 0;
+    HEAP32[i20 >> 2] = (HEAP32[i20 >> 2] | 0) + -1;
+    i26 = (HEAP32[i5 >> 2] | 0) + 1 | 0;
+    HEAP32[i5 >> 2] = i26;
+   }
+  } while (0);
+  if ((i25 | 0) == 0) {
+   continue;
+  }
+  i25 = HEAP32[i4 >> 2] | 0;
+  if ((i25 | 0) > -1) {
+   i27 = (HEAP32[i7 >> 2] | 0) + i25 | 0;
+  } else {
+   i27 = 0;
+  }
+  __tr_flush_block(i3, i27, i26 - i25 | 0, 0);
+  HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+  i27 = HEAP32[i3 >> 2] | 0;
+  i28 = i27 + 28 | 0;
+  i25 = HEAP32[i28 >> 2] | 0;
+  i30 = HEAP32[i25 + 20 >> 2] | 0;
+  i26 = i27 + 16 | 0;
+  i29 = HEAP32[i26 >> 2] | 0;
+  i29 = i30 >>> 0 > i29 >>> 0 ? i29 : i30;
+  if ((i29 | 0) != 0 ? (i8 = i27 + 12 | 0, _memcpy(HEAP32[i8 >> 2] | 0, HEAP32[i25 + 16 >> 2] | 0, i29 | 0) | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i29, i8 = (HEAP32[i28 >> 2] | 0) + 16 | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i29, i8 = i27 + 20 | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i29, HEAP32[i26 >> 2] = (HEAP32[i26 >> 2] | 0) - i29, i8 = HEAP32[i28 >> 2] | 0, i35 = i8 + 20 | 0, i36 = HEAP32[i35 >> 2] | 0, HEAP32[i35 >> 2] = i36 - i29, (i36 | 0) == (i29 | 0)) : 0) {
+   HEAP32[i8 + 16 >> 2] = HEAP32[i8 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i3 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i2 = 0;
+   i25 = 34;
+   break;
+  }
+ }
+ if ((i25 | 0) == 26) {
+  i8 = HEAP32[i4 >> 2] | 0;
+  if ((i8 | 0) > -1) {
+   i7 = (HEAP32[i7 >> 2] | 0) + i8 | 0;
+  } else {
+   i7 = 0;
+  }
+  i6 = (i6 | 0) == 4;
+  __tr_flush_block(i3, i7, (HEAP32[i5 >> 2] | 0) - i8 | 0, i6 & 1);
+  HEAP32[i4 >> 2] = HEAP32[i5 >> 2];
+  i5 = HEAP32[i3 >> 2] | 0;
+  i7 = i5 + 28 | 0;
+  i4 = HEAP32[i7 >> 2] | 0;
+  i10 = HEAP32[i4 + 20 >> 2] | 0;
+  i8 = i5 + 16 | 0;
+  i9 = HEAP32[i8 >> 2] | 0;
+  i9 = i10 >>> 0 > i9 >>> 0 ? i9 : i10;
+  if ((i9 | 0) != 0 ? (i2 = i5 + 12 | 0, _memcpy(HEAP32[i2 >> 2] | 0, HEAP32[i4 + 16 >> 2] | 0, i9 | 0) | 0, HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + i9, i2 = (HEAP32[i7 >> 2] | 0) + 16 | 0, HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + i9, i2 = i5 + 20 | 0, HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + i9, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) - i9, i2 = HEAP32[i7 >> 2] | 0, i35 = i2 + 20 | 0, i36 = HEAP32[i35 >> 2] | 0, HEAP32[i35 >> 2] = i36 - i9, (i36 | 0) == (i9 | 0)) : 0) {
+   HEAP32[i2 + 16 >> 2] = HEAP32[i2 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i3 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i36 = i6 ? 2 : 0;
+   STACKTOP = i1;
+   return i36 | 0;
+  } else {
+   i36 = i6 ? 3 : 1;
+   STACKTOP = i1;
+   return i36 | 0;
+  }
+ } else if ((i25 | 0) == 34) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ return 0;
+}
+function _inflate_table(i11, i5, i13, i2, i1, i10) {
+ i11 = i11 | 0;
+ i5 = i5 | 0;
+ i13 = i13 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i10 = i10 | 0;
+ var i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i12 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0;
+ i3 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i7 = i3 + 32 | 0;
+ i12 = i3;
+ i4 = i7 + 0 | 0;
+ i9 = i4 + 32 | 0;
+ do {
+  HEAP16[i4 >> 1] = 0;
+  i4 = i4 + 2 | 0;
+ } while ((i4 | 0) < (i9 | 0));
+ i14 = (i13 | 0) == 0;
+ if (!i14) {
+  i4 = 0;
+  do {
+   i32 = i7 + (HEAPU16[i5 + (i4 << 1) >> 1] << 1) | 0;
+   HEAP16[i32 >> 1] = (HEAP16[i32 >> 1] | 0) + 1 << 16 >> 16;
+   i4 = i4 + 1 | 0;
+  } while ((i4 | 0) != (i13 | 0));
+ }
+ i4 = HEAP32[i1 >> 2] | 0;
+ i9 = 15;
+ while (1) {
+  i15 = i9 + -1 | 0;
+  if ((HEAP16[i7 + (i9 << 1) >> 1] | 0) != 0) {
+   break;
+  }
+  if ((i15 | 0) == 0) {
+   i6 = 7;
+   break;
+  } else {
+   i9 = i15;
+  }
+ }
+ if ((i6 | 0) == 7) {
+  i32 = HEAP32[i2 >> 2] | 0;
+  HEAP32[i2 >> 2] = i32 + 4;
+  HEAP8[i32] = 64;
+  HEAP8[i32 + 1 | 0] = 1;
+  HEAP16[i32 + 2 >> 1] = 0;
+  i32 = HEAP32[i2 >> 2] | 0;
+  HEAP32[i2 >> 2] = i32 + 4;
+  HEAP8[i32] = 64;
+  HEAP8[i32 + 1 | 0] = 1;
+  HEAP16[i32 + 2 >> 1] = 0;
+  HEAP32[i1 >> 2] = 1;
+  i32 = 0;
+  STACKTOP = i3;
+  return i32 | 0;
+ }
+ i4 = i4 >>> 0 > i9 >>> 0 ? i9 : i4;
+ L12 : do {
+  if (i9 >>> 0 > 1) {
+   i27 = 1;
+   while (1) {
+    i15 = i27 + 1 | 0;
+    if ((HEAP16[i7 + (i27 << 1) >> 1] | 0) != 0) {
+     break L12;
+    }
+    if (i15 >>> 0 < i9 >>> 0) {
+     i27 = i15;
+    } else {
+     i27 = i15;
+     break;
+    }
+   }
+  } else {
+   i27 = 1;
+  }
+ } while (0);
+ i4 = i4 >>> 0 < i27 >>> 0 ? i27 : i4;
+ i16 = 1;
+ i15 = 1;
+ do {
+  i16 = (i16 << 1) - (HEAPU16[i7 + (i15 << 1) >> 1] | 0) | 0;
+  i15 = i15 + 1 | 0;
+  if ((i16 | 0) < 0) {
+   i8 = -1;
+   i6 = 56;
+   break;
+  }
+ } while (i15 >>> 0 < 16);
+ if ((i6 | 0) == 56) {
+  STACKTOP = i3;
+  return i8 | 0;
+ }
+ if ((i16 | 0) > 0 ? !((i11 | 0) != 0 & (i9 | 0) == 1) : 0) {
+  i32 = -1;
+  STACKTOP = i3;
+  return i32 | 0;
+ }
+ HEAP16[i12 + 2 >> 1] = 0;
+ i16 = 0;
+ i15 = 1;
+ do {
+  i16 = (HEAPU16[i7 + (i15 << 1) >> 1] | 0) + (i16 & 65535) | 0;
+  i15 = i15 + 1 | 0;
+  HEAP16[i12 + (i15 << 1) >> 1] = i16;
+ } while ((i15 | 0) != 15);
+ if (!i14) {
+  i15 = 0;
+  do {
+   i14 = HEAP16[i5 + (i15 << 1) >> 1] | 0;
+   if (!(i14 << 16 >> 16 == 0)) {
+    i31 = i12 + ((i14 & 65535) << 1) | 0;
+    i32 = HEAP16[i31 >> 1] | 0;
+    HEAP16[i31 >> 1] = i32 + 1 << 16 >> 16;
+    HEAP16[i10 + ((i32 & 65535) << 1) >> 1] = i15;
+   }
+   i15 = i15 + 1 | 0;
+  } while ((i15 | 0) != (i13 | 0));
+ }
+ if ((i11 | 0) == 1) {
+  i14 = 1 << i4;
+  if (i14 >>> 0 > 851) {
+   i32 = 1;
+   STACKTOP = i3;
+   return i32 | 0;
+  } else {
+   i16 = 0;
+   i20 = 1;
+   i17 = 14128 + -514 | 0;
+   i19 = 256;
+   i18 = 14192 + -514 | 0;
+  }
+ } else if ((i11 | 0) != 0) {
+  i14 = 1 << i4;
+  i16 = (i11 | 0) == 2;
+  if (i16 & i14 >>> 0 > 591) {
+   i32 = 1;
+   STACKTOP = i3;
+   return i32 | 0;
+  } else {
+   i20 = 0;
+   i17 = 14256;
+   i19 = -1;
+   i18 = 14320;
+  }
+ } else {
+  i16 = 0;
+  i14 = 1 << i4;
+  i20 = 0;
+  i17 = i10;
+  i19 = 19;
+  i18 = i10;
+ }
+ i11 = i14 + -1 | 0;
+ i12 = i4 & 255;
+ i22 = i4;
+ i21 = 0;
+ i25 = 0;
+ i13 = -1;
+ i15 = HEAP32[i2 >> 2] | 0;
+ i24 = 0;
+ L44 : while (1) {
+  i23 = 1 << i22;
+  while (1) {
+   i29 = i27 - i21 | 0;
+   i22 = i29 & 255;
+   i28 = HEAP16[i10 + (i24 << 1) >> 1] | 0;
+   i30 = i28 & 65535;
+   if ((i30 | 0) >= (i19 | 0)) {
+    if ((i30 | 0) > (i19 | 0)) {
+     i26 = HEAP16[i18 + (i30 << 1) >> 1] & 255;
+     i28 = HEAP16[i17 + (i30 << 1) >> 1] | 0;
+    } else {
+     i26 = 96;
+     i28 = 0;
+    }
+   } else {
+    i26 = 0;
+   }
+   i31 = 1 << i29;
+   i30 = i25 >>> i21;
+   i32 = i23;
+   while (1) {
+    i29 = i32 - i31 | 0;
+    i33 = i29 + i30 | 0;
+    HEAP8[i15 + (i33 << 2) | 0] = i26;
+    HEAP8[i15 + (i33 << 2) + 1 | 0] = i22;
+    HEAP16[i15 + (i33 << 2) + 2 >> 1] = i28;
+    if ((i32 | 0) == (i31 | 0)) {
+     break;
+    } else {
+     i32 = i29;
+    }
+   }
+   i26 = 1 << i27 + -1;
+   while (1) {
+    if ((i26 & i25 | 0) == 0) {
+     break;
+    } else {
+     i26 = i26 >>> 1;
+    }
+   }
+   if ((i26 | 0) == 0) {
+    i25 = 0;
+   } else {
+    i25 = (i26 + -1 & i25) + i26 | 0;
+   }
+   i24 = i24 + 1 | 0;
+   i32 = i7 + (i27 << 1) | 0;
+   i33 = (HEAP16[i32 >> 1] | 0) + -1 << 16 >> 16;
+   HEAP16[i32 >> 1] = i33;
+   if (i33 << 16 >> 16 == 0) {
+    if ((i27 | 0) == (i9 | 0)) {
+     break L44;
+    }
+    i27 = HEAPU16[i5 + (HEAPU16[i10 + (i24 << 1) >> 1] << 1) >> 1] | 0;
+   }
+   if (!(i27 >>> 0 > i4 >>> 0)) {
+    continue;
+   }
+   i26 = i25 & i11;
+   if ((i26 | 0) != (i13 | 0)) {
+    break;
+   }
+  }
+  i28 = (i21 | 0) == 0 ? i4 : i21;
+  i23 = i15 + (i23 << 2) | 0;
+  i31 = i27 - i28 | 0;
+  L67 : do {
+   if (i27 >>> 0 < i9 >>> 0) {
+    i29 = i27;
+    i30 = i31;
+    i31 = 1 << i31;
+    while (1) {
+     i31 = i31 - (HEAPU16[i7 + (i29 << 1) >> 1] | 0) | 0;
+     if ((i31 | 0) < 1) {
+      break L67;
+     }
+     i30 = i30 + 1 | 0;
+     i29 = i30 + i28 | 0;
+     if (i29 >>> 0 < i9 >>> 0) {
+      i31 = i31 << 1;
+     } else {
+      break;
+     }
+    }
+   } else {
+    i30 = i31;
+   }
+  } while (0);
+  i29 = (1 << i30) + i14 | 0;
+  if (i20 & i29 >>> 0 > 851 | i16 & i29 >>> 0 > 591) {
+   i8 = 1;
+   i6 = 56;
+   break;
+  }
+  HEAP8[(HEAP32[i2 >> 2] | 0) + (i26 << 2) | 0] = i30;
+  HEAP8[(HEAP32[i2 >> 2] | 0) + (i26 << 2) + 1 | 0] = i12;
+  i22 = HEAP32[i2 >> 2] | 0;
+  HEAP16[i22 + (i26 << 2) + 2 >> 1] = (i23 - i22 | 0) >>> 2;
+  i22 = i30;
+  i21 = i28;
+  i13 = i26;
+  i15 = i23;
+  i14 = i29;
+ }
+ if ((i6 | 0) == 56) {
+  STACKTOP = i3;
+  return i8 | 0;
+ }
+ L77 : do {
+  if ((i25 | 0) != 0) {
+   do {
+    if ((i21 | 0) != 0) {
+     if ((i25 & i11 | 0) != (i13 | 0)) {
+      i21 = 0;
+      i22 = i12;
+      i9 = i4;
+      i15 = HEAP32[i2 >> 2] | 0;
+     }
+    } else {
+     i21 = 0;
+    }
+    i5 = i25 >>> i21;
+    HEAP8[i15 + (i5 << 2) | 0] = 64;
+    HEAP8[i15 + (i5 << 2) + 1 | 0] = i22;
+    HEAP16[i15 + (i5 << 2) + 2 >> 1] = 0;
+    i5 = 1 << i9 + -1;
+    while (1) {
+     if ((i5 & i25 | 0) == 0) {
+      break;
+     } else {
+      i5 = i5 >>> 1;
+     }
+    }
+    if ((i5 | 0) == 0) {
+     break L77;
+    }
+    i25 = (i5 + -1 & i25) + i5 | 0;
+   } while ((i25 | 0) != 0);
+  }
+ } while (0);
+ HEAP32[i2 >> 2] = (HEAP32[i2 >> 2] | 0) + (i14 << 2);
+ HEAP32[i1 >> 2] = i4;
+ i33 = 0;
+ STACKTOP = i3;
+ return i33 | 0;
+}
+function _compress_block(i1, i3, i7) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i4 = 0, i5 = 0, i6 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0;
+ i2 = STACKTOP;
+ i11 = i1 + 5792 | 0;
+ if ((HEAP32[i11 >> 2] | 0) == 0) {
+  i14 = HEAP32[i1 + 5820 >> 2] | 0;
+  i17 = HEAP16[i1 + 5816 >> 1] | 0;
+ } else {
+  i9 = i1 + 5796 | 0;
+  i10 = i1 + 5784 | 0;
+  i8 = i1 + 5820 | 0;
+  i12 = i1 + 5816 | 0;
+  i5 = i1 + 20 | 0;
+  i6 = i1 + 8 | 0;
+  i14 = 0;
+  while (1) {
+   i20 = HEAP16[(HEAP32[i9 >> 2] | 0) + (i14 << 1) >> 1] | 0;
+   i13 = i20 & 65535;
+   i4 = i14 + 1 | 0;
+   i14 = HEAPU8[(HEAP32[i10 >> 2] | 0) + i14 | 0] | 0;
+   do {
+    if (i20 << 16 >> 16 == 0) {
+     i15 = HEAPU16[i3 + (i14 << 2) + 2 >> 1] | 0;
+     i13 = HEAP32[i8 >> 2] | 0;
+     i14 = HEAPU16[i3 + (i14 << 2) >> 1] | 0;
+     i16 = HEAPU16[i12 >> 1] | 0 | i14 << i13;
+     i17 = i16 & 65535;
+     HEAP16[i12 >> 1] = i17;
+     if ((i13 | 0) > (16 - i15 | 0)) {
+      i17 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i17 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i17 | 0] = i16;
+      i17 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+      i20 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i20 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i20 | 0] = i17;
+      i20 = HEAP32[i8 >> 2] | 0;
+      i17 = i14 >>> (16 - i20 | 0) & 65535;
+      HEAP16[i12 >> 1] = i17;
+      i14 = i15 + -16 + i20 | 0;
+      HEAP32[i8 >> 2] = i14;
+      break;
+     } else {
+      i14 = i13 + i15 | 0;
+      HEAP32[i8 >> 2] = i14;
+      break;
+     }
+    } else {
+     i15 = HEAPU8[808 + i14 | 0] | 0;
+     i19 = (i15 | 256) + 1 | 0;
+     i18 = HEAPU16[i3 + (i19 << 2) + 2 >> 1] | 0;
+     i17 = HEAP32[i8 >> 2] | 0;
+     i19 = HEAPU16[i3 + (i19 << 2) >> 1] | 0;
+     i20 = HEAPU16[i12 >> 1] | 0 | i19 << i17;
+     i16 = i20 & 65535;
+     HEAP16[i12 >> 1] = i16;
+     if ((i17 | 0) > (16 - i18 | 0)) {
+      i16 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i16 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i16 | 0] = i20;
+      i16 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+      i20 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i20 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i20 | 0] = i16;
+      i20 = HEAP32[i8 >> 2] | 0;
+      i16 = i19 >>> (16 - i20 | 0) & 65535;
+      HEAP16[i12 >> 1] = i16;
+      i18 = i18 + -16 + i20 | 0;
+     } else {
+      i18 = i17 + i18 | 0;
+     }
+     HEAP32[i8 >> 2] = i18;
+     i17 = HEAP32[2408 + (i15 << 2) >> 2] | 0;
+     do {
+      if ((i15 + -8 | 0) >>> 0 < 20) {
+       i14 = i14 - (HEAP32[2528 + (i15 << 2) >> 2] | 0) & 65535;
+       i15 = i14 << i18 | i16 & 65535;
+       i16 = i15 & 65535;
+       HEAP16[i12 >> 1] = i16;
+       if ((i18 | 0) > (16 - i17 | 0)) {
+        i16 = HEAP32[i5 >> 2] | 0;
+        HEAP32[i5 >> 2] = i16 + 1;
+        HEAP8[(HEAP32[i6 >> 2] | 0) + i16 | 0] = i15;
+        i16 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+        i20 = HEAP32[i5 >> 2] | 0;
+        HEAP32[i5 >> 2] = i20 + 1;
+        HEAP8[(HEAP32[i6 >> 2] | 0) + i20 | 0] = i16;
+        i20 = HEAP32[i8 >> 2] | 0;
+        i16 = i14 >>> (16 - i20 | 0) & 65535;
+        HEAP16[i12 >> 1] = i16;
+        i14 = i17 + -16 + i20 | 0;
+        HEAP32[i8 >> 2] = i14;
+        break;
+       } else {
+        i14 = i18 + i17 | 0;
+        HEAP32[i8 >> 2] = i14;
+        break;
+       }
+      } else {
+       i14 = i18;
+      }
+     } while (0);
+     i13 = i13 + -1 | 0;
+     if (i13 >>> 0 < 256) {
+      i15 = i13;
+     } else {
+      i15 = (i13 >>> 7) + 256 | 0;
+     }
+     i15 = HEAPU8[296 + i15 | 0] | 0;
+     i17 = HEAPU16[i7 + (i15 << 2) + 2 >> 1] | 0;
+     i18 = HEAPU16[i7 + (i15 << 2) >> 1] | 0;
+     i19 = i16 & 65535 | i18 << i14;
+     i16 = i19 & 65535;
+     HEAP16[i12 >> 1] = i16;
+     if ((i14 | 0) > (16 - i17 | 0)) {
+      i20 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i20 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i20 | 0] = i19;
+      i20 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+      i14 = HEAP32[i5 >> 2] | 0;
+      HEAP32[i5 >> 2] = i14 + 1;
+      HEAP8[(HEAP32[i6 >> 2] | 0) + i14 | 0] = i20;
+      i14 = HEAP32[i8 >> 2] | 0;
+      i20 = i18 >>> (16 - i14 | 0) & 65535;
+      HEAP16[i12 >> 1] = i20;
+      i14 = i17 + -16 + i14 | 0;
+      i17 = i20;
+     } else {
+      i14 = i14 + i17 | 0;
+      i17 = i16;
+     }
+     HEAP32[i8 >> 2] = i14;
+     i16 = HEAP32[2648 + (i15 << 2) >> 2] | 0;
+     if ((i15 + -4 | 0) >>> 0 < 26) {
+      i13 = i13 - (HEAP32[2768 + (i15 << 2) >> 2] | 0) & 65535;
+      i15 = i13 << i14 | i17 & 65535;
+      i17 = i15 & 65535;
+      HEAP16[i12 >> 1] = i17;
+      if ((i14 | 0) > (16 - i16 | 0)) {
+       i17 = HEAP32[i5 >> 2] | 0;
+       HEAP32[i5 >> 2] = i17 + 1;
+       HEAP8[(HEAP32[i6 >> 2] | 0) + i17 | 0] = i15;
+       i17 = (HEAPU16[i12 >> 1] | 0) >>> 8 & 255;
+       i14 = HEAP32[i5 >> 2] | 0;
+       HEAP32[i5 >> 2] = i14 + 1;
+       HEAP8[(HEAP32[i6 >> 2] | 0) + i14 | 0] = i17;
+       i14 = HEAP32[i8 >> 2] | 0;
+       i17 = i13 >>> (16 - i14 | 0) & 65535;
+       HEAP16[i12 >> 1] = i17;
+       i14 = i16 + -16 + i14 | 0;
+       HEAP32[i8 >> 2] = i14;
+       break;
+      } else {
+       i14 = i14 + i16 | 0;
+       HEAP32[i8 >> 2] = i14;
+       break;
+      }
+     }
+    }
+   } while (0);
+   if (i4 >>> 0 < (HEAP32[i11 >> 2] | 0) >>> 0) {
+    i14 = i4;
+   } else {
+    break;
+   }
+  }
+ }
+ i5 = i3 + 1026 | 0;
+ i6 = HEAPU16[i5 >> 1] | 0;
+ i4 = i1 + 5820 | 0;
+ i3 = HEAPU16[i3 + 1024 >> 1] | 0;
+ i7 = i1 + 5816 | 0;
+ i8 = i17 & 65535 | i3 << i14;
+ HEAP16[i7 >> 1] = i8;
+ if ((i14 | 0) > (16 - i6 | 0)) {
+  i17 = i1 + 20 | 0;
+  i18 = HEAP32[i17 >> 2] | 0;
+  HEAP32[i17 >> 2] = i18 + 1;
+  i20 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i20 >> 2] | 0) + i18 | 0] = i8;
+  i18 = (HEAPU16[i7 >> 1] | 0) >>> 8 & 255;
+  i19 = HEAP32[i17 >> 2] | 0;
+  HEAP32[i17 >> 2] = i19 + 1;
+  HEAP8[(HEAP32[i20 >> 2] | 0) + i19 | 0] = i18;
+  i19 = HEAP32[i4 >> 2] | 0;
+  HEAP16[i7 >> 1] = i3 >>> (16 - i19 | 0);
+  i19 = i6 + -16 + i19 | 0;
+  HEAP32[i4 >> 2] = i19;
+  i19 = HEAP16[i5 >> 1] | 0;
+  i19 = i19 & 65535;
+  i20 = i1 + 5812 | 0;
+  HEAP32[i20 >> 2] = i19;
+  STACKTOP = i2;
+  return;
+ } else {
+  i19 = i14 + i6 | 0;
+  HEAP32[i4 >> 2] = i19;
+  i19 = HEAP16[i5 >> 1] | 0;
+  i19 = i19 & 65535;
+  i20 = i1 + 5812 | 0;
+  HEAP32[i20 >> 2] = i19;
+  STACKTOP = i2;
+  return;
+ }
+}
+function _deflate_stored(i2, i5) {
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i3 = 0, i4 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0;
+ i1 = STACKTOP;
+ i4 = (HEAP32[i2 + 12 >> 2] | 0) + -5 | 0;
+ i11 = i4 >>> 0 < 65535 ? i4 : 65535;
+ i12 = i2 + 116 | 0;
+ i4 = i2 + 108 | 0;
+ i6 = i2 + 92 | 0;
+ i10 = i2 + 44 | 0;
+ i7 = i2 + 56 | 0;
+ while (1) {
+  i13 = HEAP32[i12 >> 2] | 0;
+  if (i13 >>> 0 < 2) {
+   _fill_window(i2);
+   i13 = HEAP32[i12 >> 2] | 0;
+   if ((i13 | i5 | 0) == 0) {
+    i2 = 0;
+    i8 = 28;
+    break;
+   }
+   if ((i13 | 0) == 0) {
+    i8 = 20;
+    break;
+   }
+  }
+  i13 = (HEAP32[i4 >> 2] | 0) + i13 | 0;
+  HEAP32[i4 >> 2] = i13;
+  HEAP32[i12 >> 2] = 0;
+  i14 = HEAP32[i6 >> 2] | 0;
+  i15 = i14 + i11 | 0;
+  if (!((i13 | 0) != 0 & i13 >>> 0 < i15 >>> 0)) {
+   HEAP32[i12 >> 2] = i13 - i15;
+   HEAP32[i4 >> 2] = i15;
+   if ((i14 | 0) > -1) {
+    i13 = (HEAP32[i7 >> 2] | 0) + i14 | 0;
+   } else {
+    i13 = 0;
+   }
+   __tr_flush_block(i2, i13, i11, 0);
+   HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+   i16 = HEAP32[i2 >> 2] | 0;
+   i14 = i16 + 28 | 0;
+   i15 = HEAP32[i14 >> 2] | 0;
+   i17 = HEAP32[i15 + 20 >> 2] | 0;
+   i13 = i16 + 16 | 0;
+   i18 = HEAP32[i13 >> 2] | 0;
+   i17 = i17 >>> 0 > i18 >>> 0 ? i18 : i17;
+   if ((i17 | 0) != 0 ? (i8 = i16 + 12 | 0, _memcpy(HEAP32[i8 >> 2] | 0, HEAP32[i15 + 16 >> 2] | 0, i17 | 0) | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i17, i8 = (HEAP32[i14 >> 2] | 0) + 16 | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i17, i8 = i16 + 20 | 0, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i17, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) - i17, i8 = HEAP32[i14 >> 2] | 0, i16 = i8 + 20 | 0, i18 = HEAP32[i16 >> 2] | 0, HEAP32[i16 >> 2] = i18 - i17, (i18 | 0) == (i17 | 0)) : 0) {
+    HEAP32[i8 + 16 >> 2] = HEAP32[i8 + 8 >> 2];
+   }
+   if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+    i2 = 0;
+    i8 = 28;
+    break;
+   }
+   i14 = HEAP32[i6 >> 2] | 0;
+   i13 = HEAP32[i4 >> 2] | 0;
+  }
+  i13 = i13 - i14 | 0;
+  if (i13 >>> 0 < ((HEAP32[i10 >> 2] | 0) + -262 | 0) >>> 0) {
+   continue;
+  }
+  if ((i14 | 0) > -1) {
+   i14 = (HEAP32[i7 >> 2] | 0) + i14 | 0;
+  } else {
+   i14 = 0;
+  }
+  __tr_flush_block(i2, i14, i13, 0);
+  HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+  i16 = HEAP32[i2 >> 2] | 0;
+  i14 = i16 + 28 | 0;
+  i15 = HEAP32[i14 >> 2] | 0;
+  i17 = HEAP32[i15 + 20 >> 2] | 0;
+  i13 = i16 + 16 | 0;
+  i18 = HEAP32[i13 >> 2] | 0;
+  i17 = i17 >>> 0 > i18 >>> 0 ? i18 : i17;
+  if ((i17 | 0) != 0 ? (i9 = i16 + 12 | 0, _memcpy(HEAP32[i9 >> 2] | 0, HEAP32[i15 + 16 >> 2] | 0, i17 | 0) | 0, HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + i17, i9 = (HEAP32[i14 >> 2] | 0) + 16 | 0, HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + i17, i9 = i16 + 20 | 0, HEAP32[i9 >> 2] = (HEAP32[i9 >> 2] | 0) + i17, HEAP32[i13 >> 2] = (HEAP32[i13 >> 2] | 0) - i17, i9 = HEAP32[i14 >> 2] | 0, i16 = i9 + 20 | 0, i18 = HEAP32[i16 >> 2] | 0, HEAP32[i16 >> 2] = i18 - i17, (i18 | 0) == (i17 | 0)) : 0) {
+   HEAP32[i9 + 16 >> 2] = HEAP32[i9 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i2 = 0;
+   i8 = 28;
+   break;
+  }
+ }
+ if ((i8 | 0) == 20) {
+  i8 = HEAP32[i6 >> 2] | 0;
+  if ((i8 | 0) > -1) {
+   i7 = (HEAP32[i7 >> 2] | 0) + i8 | 0;
+  } else {
+   i7 = 0;
+  }
+  i5 = (i5 | 0) == 4;
+  __tr_flush_block(i2, i7, (HEAP32[i4 >> 2] | 0) - i8 | 0, i5 & 1);
+  HEAP32[i6 >> 2] = HEAP32[i4 >> 2];
+  i4 = HEAP32[i2 >> 2] | 0;
+  i7 = i4 + 28 | 0;
+  i6 = HEAP32[i7 >> 2] | 0;
+  i9 = HEAP32[i6 + 20 >> 2] | 0;
+  i8 = i4 + 16 | 0;
+  i10 = HEAP32[i8 >> 2] | 0;
+  i9 = i9 >>> 0 > i10 >>> 0 ? i10 : i9;
+  if ((i9 | 0) != 0 ? (i3 = i4 + 12 | 0, _memcpy(HEAP32[i3 >> 2] | 0, HEAP32[i6 + 16 >> 2] | 0, i9 | 0) | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, i3 = (HEAP32[i7 >> 2] | 0) + 16 | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, i3 = i4 + 20 | 0, HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + i9, HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) - i9, i3 = HEAP32[i7 >> 2] | 0, i17 = i3 + 20 | 0, i18 = HEAP32[i17 >> 2] | 0, HEAP32[i17 >> 2] = i18 - i9, (i18 | 0) == (i9 | 0)) : 0) {
+   HEAP32[i3 + 16 >> 2] = HEAP32[i3 + 8 >> 2];
+  }
+  if ((HEAP32[(HEAP32[i2 >> 2] | 0) + 16 >> 2] | 0) == 0) {
+   i18 = i5 ? 2 : 0;
+   STACKTOP = i1;
+   return i18 | 0;
+  } else {
+   i18 = i5 ? 3 : 1;
+   STACKTOP = i1;
+   return i18 | 0;
+  }
+ } else if ((i8 | 0) == 28) {
+  STACKTOP = i1;
+  return i2 | 0;
+ }
+ return 0;
+}
+function _fill_window(i15) {
+ i15 = i15 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0;
+ i2 = STACKTOP;
+ i16 = i15 + 44 | 0;
+ i9 = HEAP32[i16 >> 2] | 0;
+ i4 = i15 + 60 | 0;
+ i8 = i15 + 116 | 0;
+ i3 = i15 + 108 | 0;
+ i5 = i9 + -262 | 0;
+ i1 = i15 + 56 | 0;
+ i17 = i15 + 72 | 0;
+ i6 = i15 + 88 | 0;
+ i7 = i15 + 84 | 0;
+ i11 = i15 + 112 | 0;
+ i12 = i15 + 92 | 0;
+ i13 = i15 + 76 | 0;
+ i14 = i15 + 68 | 0;
+ i10 = i15 + 64 | 0;
+ i19 = HEAP32[i8 >> 2] | 0;
+ i21 = i9;
+ while (1) {
+  i20 = HEAP32[i3 >> 2] | 0;
+  i19 = (HEAP32[i4 >> 2] | 0) - i19 - i20 | 0;
+  if (!(i20 >>> 0 < (i5 + i21 | 0) >>> 0)) {
+   i20 = HEAP32[i1 >> 2] | 0;
+   _memcpy(i20 | 0, i20 + i9 | 0, i9 | 0) | 0;
+   HEAP32[i11 >> 2] = (HEAP32[i11 >> 2] | 0) - i9;
+   i20 = (HEAP32[i3 >> 2] | 0) - i9 | 0;
+   HEAP32[i3 >> 2] = i20;
+   HEAP32[i12 >> 2] = (HEAP32[i12 >> 2] | 0) - i9;
+   i22 = HEAP32[i13 >> 2] | 0;
+   i21 = i22;
+   i22 = (HEAP32[i14 >> 2] | 0) + (i22 << 1) | 0;
+   do {
+    i22 = i22 + -2 | 0;
+    i23 = HEAPU16[i22 >> 1] | 0;
+    if (i23 >>> 0 < i9 >>> 0) {
+     i23 = 0;
+    } else {
+     i23 = i23 - i9 & 65535;
+    }
+    HEAP16[i22 >> 1] = i23;
+    i21 = i21 + -1 | 0;
+   } while ((i21 | 0) != 0);
+   i22 = i9;
+   i21 = (HEAP32[i10 >> 2] | 0) + (i9 << 1) | 0;
+   do {
+    i21 = i21 + -2 | 0;
+    i23 = HEAPU16[i21 >> 1] | 0;
+    if (i23 >>> 0 < i9 >>> 0) {
+     i23 = 0;
+    } else {
+     i23 = i23 - i9 & 65535;
+    }
+    HEAP16[i21 >> 1] = i23;
+    i22 = i22 + -1 | 0;
+   } while ((i22 | 0) != 0);
+   i19 = i19 + i9 | 0;
+  }
+  i21 = HEAP32[i15 >> 2] | 0;
+  i24 = i21 + 4 | 0;
+  i23 = HEAP32[i24 >> 2] | 0;
+  if ((i23 | 0) == 0) {
+   i18 = 28;
+   break;
+  }
+  i22 = HEAP32[i8 >> 2] | 0;
+  i20 = (HEAP32[i1 >> 2] | 0) + (i22 + i20) | 0;
+  i19 = i23 >>> 0 > i19 >>> 0 ? i19 : i23;
+  if ((i19 | 0) == 0) {
+   i19 = 0;
+  } else {
+   HEAP32[i24 >> 2] = i23 - i19;
+   i22 = HEAP32[(HEAP32[i21 + 28 >> 2] | 0) + 24 >> 2] | 0;
+   if ((i22 | 0) == 1) {
+    i22 = i21 + 48 | 0;
+    HEAP32[i22 >> 2] = _adler32(HEAP32[i22 >> 2] | 0, HEAP32[i21 >> 2] | 0, i19) | 0;
+    i22 = i21;
+   } else if ((i22 | 0) == 2) {
+    i22 = i21 + 48 | 0;
+    HEAP32[i22 >> 2] = _crc32(HEAP32[i22 >> 2] | 0, HEAP32[i21 >> 2] | 0, i19) | 0;
+    i22 = i21;
+   } else {
+    i22 = i21;
+   }
+   _memcpy(i20 | 0, HEAP32[i22 >> 2] | 0, i19 | 0) | 0;
+   HEAP32[i22 >> 2] = (HEAP32[i22 >> 2] | 0) + i19;
+   i22 = i21 + 8 | 0;
+   HEAP32[i22 >> 2] = (HEAP32[i22 >> 2] | 0) + i19;
+   i22 = HEAP32[i8 >> 2] | 0;
+  }
+  i19 = i22 + i19 | 0;
+  HEAP32[i8 >> 2] = i19;
+  if (i19 >>> 0 > 2 ? (i23 = HEAP32[i3 >> 2] | 0, i22 = HEAP32[i1 >> 2] | 0, i24 = HEAPU8[i22 + i23 | 0] | 0, HEAP32[i17 >> 2] = i24, HEAP32[i17 >> 2] = ((HEAPU8[i22 + (i23 + 1) | 0] | 0) ^ i24 << HEAP32[i6 >> 2]) & HEAP32[i7 >> 2], !(i19 >>> 0 < 262)) : 0) {
+   break;
+  }
+  if ((HEAP32[(HEAP32[i15 >> 2] | 0) + 4 >> 2] | 0) == 0) {
+   break;
+  }
+  i21 = HEAP32[i16 >> 2] | 0;
+ }
+ if ((i18 | 0) == 28) {
+  STACKTOP = i2;
+  return;
+ }
+ i5 = i15 + 5824 | 0;
+ i6 = HEAP32[i5 >> 2] | 0;
+ i4 = HEAP32[i4 >> 2] | 0;
+ if (!(i6 >>> 0 < i4 >>> 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i19 + (HEAP32[i3 >> 2] | 0) | 0;
+ if (i6 >>> 0 < i3 >>> 0) {
+  i4 = i4 - i3 | 0;
+  i24 = i4 >>> 0 > 258 ? 258 : i4;
+  _memset((HEAP32[i1 >> 2] | 0) + i3 | 0, 0, i24 | 0) | 0;
+  HEAP32[i5 >> 2] = i24 + i3;
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i3 + 258 | 0;
+ if (!(i6 >>> 0 < i3 >>> 0)) {
+  STACKTOP = i2;
+  return;
+ }
+ i3 = i3 - i6 | 0;
+ i4 = i4 - i6 | 0;
+ i24 = i3 >>> 0 > i4 >>> 0 ? i4 : i3;
+ _memset((HEAP32[i1 >> 2] | 0) + i6 | 0, 0, i24 | 0) | 0;
+ HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i24;
+ STACKTOP = i2;
+ return;
+}
+function __tr_align(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
+ i2 = STACKTOP;
+ i3 = i1 + 5820 | 0;
+ i6 = HEAP32[i3 >> 2] | 0;
+ i4 = i1 + 5816 | 0;
+ i7 = HEAPU16[i4 >> 1] | 0 | 2 << i6;
+ i5 = i7 & 65535;
+ HEAP16[i4 >> 1] = i5;
+ if ((i6 | 0) > 13) {
+  i8 = i1 + 20 | 0;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  i5 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i5 >> 2] | 0) + i6 | 0] = i7;
+  i7 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  HEAP8[(HEAP32[i5 >> 2] | 0) + i6 | 0] = i7;
+  i6 = HEAP32[i3 >> 2] | 0;
+  i5 = 2 >>> (16 - i6 | 0) & 65535;
+  HEAP16[i4 >> 1] = i5;
+  i6 = i6 + -13 | 0;
+ } else {
+  i6 = i6 + 3 | 0;
+ }
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) > 9) {
+  i7 = i1 + 20 | 0;
+  i6 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i6 + 1;
+  i8 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i6 | 0] = i5;
+  i5 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i6 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i6 + 1;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i6 | 0] = i5;
+  HEAP16[i4 >> 1] = 0;
+  i6 = (HEAP32[i3 >> 2] | 0) + -9 | 0;
+  i5 = 0;
+ } else {
+  i6 = i6 + 7 | 0;
+ }
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) != 16) {
+  if ((i6 | 0) > 7) {
+   i6 = i1 + 20 | 0;
+   i7 = HEAP32[i6 >> 2] | 0;
+   HEAP32[i6 >> 2] = i7 + 1;
+   HEAP8[(HEAP32[i1 + 8 >> 2] | 0) + i7 | 0] = i5;
+   i7 = (HEAPU16[i4 >> 1] | 0) >>> 8;
+   HEAP16[i4 >> 1] = i7;
+   i6 = (HEAP32[i3 >> 2] | 0) + -8 | 0;
+   HEAP32[i3 >> 2] = i6;
+  } else {
+   i7 = i5;
+  }
+ } else {
+  i9 = i1 + 20 | 0;
+  i8 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i9 >> 2] = i8 + 1;
+  i7 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i7 >> 2] | 0) + i8 | 0] = i5;
+  i8 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i6 = HEAP32[i9 >> 2] | 0;
+  HEAP32[i9 >> 2] = i6 + 1;
+  HEAP8[(HEAP32[i7 >> 2] | 0) + i6 | 0] = i8;
+  HEAP16[i4 >> 1] = 0;
+  HEAP32[i3 >> 2] = 0;
+  i6 = 0;
+  i7 = 0;
+ }
+ i5 = i1 + 5812 | 0;
+ if ((11 - i6 + (HEAP32[i5 >> 2] | 0) | 0) >= 9) {
+  HEAP32[i5 >> 2] = 7;
+  STACKTOP = i2;
+  return;
+ }
+ i7 = i7 & 65535 | 2 << i6;
+ HEAP16[i4 >> 1] = i7;
+ if ((i6 | 0) > 13) {
+  i8 = i1 + 20 | 0;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  i9 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i9 >> 2] | 0) + i6 | 0] = i7;
+  i7 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i6 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i6 + 1;
+  HEAP8[(HEAP32[i9 >> 2] | 0) + i6 | 0] = i7;
+  i6 = HEAP32[i3 >> 2] | 0;
+  i7 = 2 >>> (16 - i6 | 0);
+  HEAP16[i4 >> 1] = i7;
+  i6 = i6 + -13 | 0;
+ } else {
+  i6 = i6 + 3 | 0;
+ }
+ i7 = i7 & 255;
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) > 9) {
+  i8 = i1 + 20 | 0;
+  i9 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i9 + 1;
+  i6 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i6 >> 2] | 0) + i9 | 0] = i7;
+  i9 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i7 = HEAP32[i8 >> 2] | 0;
+  HEAP32[i8 >> 2] = i7 + 1;
+  HEAP8[(HEAP32[i6 >> 2] | 0) + i7 | 0] = i9;
+  HEAP16[i4 >> 1] = 0;
+  i7 = 0;
+  i6 = (HEAP32[i3 >> 2] | 0) + -9 | 0;
+ } else {
+  i6 = i6 + 7 | 0;
+ }
+ HEAP32[i3 >> 2] = i6;
+ if ((i6 | 0) == 16) {
+  i6 = i1 + 20 | 0;
+  i9 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i9 + 1;
+  i8 = i1 + 8 | 0;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i9 | 0] = i7;
+  i7 = (HEAPU16[i4 >> 1] | 0) >>> 8 & 255;
+  i9 = HEAP32[i6 >> 2] | 0;
+  HEAP32[i6 >> 2] = i9 + 1;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i9 | 0] = i7;
+  HEAP16[i4 >> 1] = 0;
+  HEAP32[i3 >> 2] = 0;
+  HEAP32[i5 >> 2] = 7;
+  STACKTOP = i2;
+  return;
+ }
+ if ((i6 | 0) <= 7) {
+  HEAP32[i5 >> 2] = 7;
+  STACKTOP = i2;
+  return;
+ }
+ i8 = i1 + 20 | 0;
+ i9 = HEAP32[i8 >> 2] | 0;
+ HEAP32[i8 >> 2] = i9 + 1;
+ HEAP8[(HEAP32[i1 + 8 >> 2] | 0) + i9 | 0] = i7;
+ HEAP16[i4 >> 1] = (HEAPU16[i4 >> 1] | 0) >>> 8;
+ HEAP32[i3 >> 2] = (HEAP32[i3 >> 2] | 0) + -8;
+ HEAP32[i5 >> 2] = 7;
+ STACKTOP = i2;
+ return;
+}
+function _adler32(i6, i4, i5) {
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0;
+ i1 = STACKTOP;
+ i3 = i6 >>> 16;
+ i6 = i6 & 65535;
+ if ((i5 | 0) == 1) {
+  i2 = (HEAPU8[i4] | 0) + i6 | 0;
+  i2 = i2 >>> 0 > 65520 ? i2 + -65521 | 0 : i2;
+  i3 = i2 + i3 | 0;
+  i8 = (i3 >>> 0 > 65520 ? i3 + 15 | 0 : i3) << 16 | i2;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ if ((i4 | 0) == 0) {
+  i8 = 1;
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ if (i5 >>> 0 < 16) {
+  if ((i5 | 0) != 0) {
+   while (1) {
+    i5 = i5 + -1 | 0;
+    i6 = (HEAPU8[i4] | 0) + i6 | 0;
+    i3 = i6 + i3 | 0;
+    if ((i5 | 0) == 0) {
+     break;
+    } else {
+     i4 = i4 + 1 | 0;
+    }
+   }
+  }
+  i8 = ((i3 >>> 0) % 65521 | 0) << 16 | (i6 >>> 0 > 65520 ? i6 + -65521 | 0 : i6);
+  STACKTOP = i1;
+  return i8 | 0;
+ }
+ if (i5 >>> 0 > 5551) {
+  do {
+   i5 = i5 + -5552 | 0;
+   i7 = i4;
+   i8 = 347;
+   while (1) {
+    i23 = (HEAPU8[i7] | 0) + i6 | 0;
+    i22 = i23 + (HEAPU8[i7 + 1 | 0] | 0) | 0;
+    i21 = i22 + (HEAPU8[i7 + 2 | 0] | 0) | 0;
+    i20 = i21 + (HEAPU8[i7 + 3 | 0] | 0) | 0;
+    i19 = i20 + (HEAPU8[i7 + 4 | 0] | 0) | 0;
+    i18 = i19 + (HEAPU8[i7 + 5 | 0] | 0) | 0;
+    i17 = i18 + (HEAPU8[i7 + 6 | 0] | 0) | 0;
+    i16 = i17 + (HEAPU8[i7 + 7 | 0] | 0) | 0;
+    i15 = i16 + (HEAPU8[i7 + 8 | 0] | 0) | 0;
+    i14 = i15 + (HEAPU8[i7 + 9 | 0] | 0) | 0;
+    i13 = i14 + (HEAPU8[i7 + 10 | 0] | 0) | 0;
+    i12 = i13 + (HEAPU8[i7 + 11 | 0] | 0) | 0;
+    i11 = i12 + (HEAPU8[i7 + 12 | 0] | 0) | 0;
+    i10 = i11 + (HEAPU8[i7 + 13 | 0] | 0) | 0;
+    i9 = i10 + (HEAPU8[i7 + 14 | 0] | 0) | 0;
+    i6 = i9 + (HEAPU8[i7 + 15 | 0] | 0) | 0;
+    i3 = i23 + i3 + i22 + i21 + i20 + i19 + i18 + i17 + i16 + i15 + i14 + i13 + i12 + i11 + i10 + i9 + i6 | 0;
+    i8 = i8 + -1 | 0;
+    if ((i8 | 0) == 0) {
+     break;
+    } else {
+     i7 = i7 + 16 | 0;
+    }
+   }
+   i4 = i4 + 5552 | 0;
+   i6 = (i6 >>> 0) % 65521 | 0;
+   i3 = (i3 >>> 0) % 65521 | 0;
+  } while (i5 >>> 0 > 5551);
+  if ((i5 | 0) != 0) {
+   if (i5 >>> 0 > 15) {
+    i2 = 15;
+   } else {
+    i2 = 16;
+   }
+  }
+ } else {
+  i2 = 15;
+ }
+ if ((i2 | 0) == 15) {
+  while (1) {
+   i5 = i5 + -16 | 0;
+   i9 = (HEAPU8[i4] | 0) + i6 | 0;
+   i10 = i9 + (HEAPU8[i4 + 1 | 0] | 0) | 0;
+   i11 = i10 + (HEAPU8[i4 + 2 | 0] | 0) | 0;
+   i12 = i11 + (HEAPU8[i4 + 3 | 0] | 0) | 0;
+   i13 = i12 + (HEAPU8[i4 + 4 | 0] | 0) | 0;
+   i14 = i13 + (HEAPU8[i4 + 5 | 0] | 0) | 0;
+   i15 = i14 + (HEAPU8[i4 + 6 | 0] | 0) | 0;
+   i16 = i15 + (HEAPU8[i4 + 7 | 0] | 0) | 0;
+   i17 = i16 + (HEAPU8[i4 + 8 | 0] | 0) | 0;
+   i18 = i17 + (HEAPU8[i4 + 9 | 0] | 0) | 0;
+   i19 = i18 + (HEAPU8[i4 + 10 | 0] | 0) | 0;
+   i20 = i19 + (HEAPU8[i4 + 11 | 0] | 0) | 0;
+   i21 = i20 + (HEAPU8[i4 + 12 | 0] | 0) | 0;
+   i22 = i21 + (HEAPU8[i4 + 13 | 0] | 0) | 0;
+   i23 = i22 + (HEAPU8[i4 + 14 | 0] | 0) | 0;
+   i6 = i23 + (HEAPU8[i4 + 15 | 0] | 0) | 0;
+   i3 = i9 + i3 + i10 + i11 + i12 + i13 + i14 + i15 + i16 + i17 + i18 + i19 + i20 + i21 + i22 + i23 + i6 | 0;
+   i4 = i4 + 16 | 0;
+   if (!(i5 >>> 0 > 15)) {
+    break;
+   } else {
+    i2 = 15;
+   }
+  }
+  if ((i5 | 0) == 0) {
+   i2 = 17;
+  } else {
+   i2 = 16;
+  }
+ }
+ if ((i2 | 0) == 16) {
+  while (1) {
+   i5 = i5 + -1 | 0;
+   i6 = (HEAPU8[i4] | 0) + i6 | 0;
+   i3 = i6 + i3 | 0;
+   if ((i5 | 0) == 0) {
+    i2 = 17;
+    break;
+   } else {
+    i4 = i4 + 1 | 0;
+    i2 = 16;
+   }
+  }
+ }
+ if ((i2 | 0) == 17) {
+  i6 = (i6 >>> 0) % 65521 | 0;
+  i3 = (i3 >>> 0) % 65521 | 0;
+ }
+ i23 = i3 << 16 | i6;
+ STACKTOP = i1;
+ return i23 | 0;
+}
+function _crc32(i4, i2, i3) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ var i1 = 0, i5 = 0;
+ i1 = STACKTOP;
+ if ((i2 | 0) == 0) {
+  i5 = 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ i4 = ~i4;
+ L4 : do {
+  if ((i3 | 0) != 0) {
+   while (1) {
+    if ((i2 & 3 | 0) == 0) {
+     break;
+    }
+    i4 = HEAP32[3192 + (((HEAPU8[i2] | 0) ^ i4 & 255) << 2) >> 2] ^ i4 >>> 8;
+    i3 = i3 + -1 | 0;
+    if ((i3 | 0) == 0) {
+     break L4;
+    } else {
+     i2 = i2 + 1 | 0;
+    }
+   }
+   if (i3 >>> 0 > 31) {
+    while (1) {
+     i4 = HEAP32[i2 >> 2] ^ i4;
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 4 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 8 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 12 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 16 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 20 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 24 >> 2];
+     i5 = i2 + 32 | 0;
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2] ^ HEAP32[i2 + 28 >> 2];
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2];
+     i3 = i3 + -32 | 0;
+     if (i3 >>> 0 > 31) {
+      i2 = i5;
+     } else {
+      i2 = i5;
+      break;
+     }
+    }
+   }
+   if (i3 >>> 0 > 3) {
+    while (1) {
+     i5 = i2 + 4 | 0;
+     i4 = HEAP32[i2 >> 2] ^ i4;
+     i4 = HEAP32[5240 + ((i4 >>> 8 & 255) << 2) >> 2] ^ HEAP32[6264 + ((i4 & 255) << 2) >> 2] ^ HEAP32[4216 + ((i4 >>> 16 & 255) << 2) >> 2] ^ HEAP32[3192 + (i4 >>> 24 << 2) >> 2];
+     i3 = i3 + -4 | 0;
+     if (i3 >>> 0 > 3) {
+      i2 = i5;
+     } else {
+      i2 = i5;
+      break;
+     }
+    }
+   }
+   if ((i3 | 0) != 0) {
+    while (1) {
+     i4 = HEAP32[3192 + (((HEAPU8[i2] | 0) ^ i4 & 255) << 2) >> 2] ^ i4 >>> 8;
+     i3 = i3 + -1 | 0;
+     if ((i3 | 0) == 0) {
+      break;
+     } else {
+      i2 = i2 + 1 | 0;
+     }
+    }
+   }
+  }
+ } while (0);
+ i5 = ~i4;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _deflateInit2_(i3, i7, i8, i10, i4, i1, i5, i6) {
+ i3 = i3 | 0;
+ i7 = i7 | 0;
+ i8 = i8 | 0;
+ i10 = i10 | 0;
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i9 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0;
+ i2 = STACKTOP;
+ if ((i5 | 0) == 0) {
+  i12 = -6;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ if (!((HEAP8[i5] | 0) == 49 & (i6 | 0) == 56)) {
+  i12 = -6;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ if ((i3 | 0) == 0) {
+  i12 = -2;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ i5 = i3 + 24 | 0;
+ HEAP32[i5 >> 2] = 0;
+ i6 = i3 + 32 | 0;
+ i9 = HEAP32[i6 >> 2] | 0;
+ if ((i9 | 0) == 0) {
+  HEAP32[i6 >> 2] = 1;
+  HEAP32[i3 + 40 >> 2] = 0;
+  i9 = 1;
+ }
+ i11 = i3 + 36 | 0;
+ if ((HEAP32[i11 >> 2] | 0) == 0) {
+  HEAP32[i11 >> 2] = 1;
+ }
+ i7 = (i7 | 0) == -1 ? 6 : i7;
+ if ((i10 | 0) < 0) {
+  i10 = 0 - i10 | 0;
+  i11 = 0;
+ } else {
+  i11 = (i10 | 0) > 15;
+  i10 = i11 ? i10 + -16 | 0 : i10;
+  i11 = i11 ? 2 : 1;
+ }
+ if (!((i4 + -1 | 0) >>> 0 < 9 & (i8 | 0) == 8)) {
+  i12 = -2;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ if ((i10 + -8 | 0) >>> 0 > 7 | i7 >>> 0 > 9 | i1 >>> 0 > 4) {
+  i12 = -2;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ i12 = (i10 | 0) == 8 ? 9 : i10;
+ i10 = i3 + 40 | 0;
+ i8 = FUNCTION_TABLE_iiii[i9 & 1](HEAP32[i10 >> 2] | 0, 1, 5828) | 0;
+ if ((i8 | 0) == 0) {
+  i12 = -4;
+  STACKTOP = i2;
+  return i12 | 0;
+ }
+ HEAP32[i3 + 28 >> 2] = i8;
+ HEAP32[i8 >> 2] = i3;
+ HEAP32[i8 + 24 >> 2] = i11;
+ HEAP32[i8 + 28 >> 2] = 0;
+ HEAP32[i8 + 48 >> 2] = i12;
+ i14 = 1 << i12;
+ i11 = i8 + 44 | 0;
+ HEAP32[i11 >> 2] = i14;
+ HEAP32[i8 + 52 >> 2] = i14 + -1;
+ i12 = i4 + 7 | 0;
+ HEAP32[i8 + 80 >> 2] = i12;
+ i12 = 1 << i12;
+ i13 = i8 + 76 | 0;
+ HEAP32[i13 >> 2] = i12;
+ HEAP32[i8 + 84 >> 2] = i12 + -1;
+ HEAP32[i8 + 88 >> 2] = ((i4 + 9 | 0) >>> 0) / 3 | 0;
+ i12 = i8 + 56 | 0;
+ HEAP32[i12 >> 2] = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 1](HEAP32[i10 >> 2] | 0, i14, 2) | 0;
+ i14 = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 1](HEAP32[i10 >> 2] | 0, HEAP32[i11 >> 2] | 0, 2) | 0;
+ i9 = i8 + 64 | 0;
+ HEAP32[i9 >> 2] = i14;
+ _memset(i14 | 0, 0, HEAP32[i11 >> 2] << 1 | 0) | 0;
+ i11 = i8 + 68 | 0;
+ HEAP32[i11 >> 2] = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 1](HEAP32[i10 >> 2] | 0, HEAP32[i13 >> 2] | 0, 2) | 0;
+ HEAP32[i8 + 5824 >> 2] = 0;
+ i4 = 1 << i4 + 6;
+ i13 = i8 + 5788 | 0;
+ HEAP32[i13 >> 2] = i4;
+ i4 = FUNCTION_TABLE_iiii[HEAP32[i6 >> 2] & 1](HEAP32[i10 >> 2] | 0, i4, 4) | 0;
+ HEAP32[i8 + 8 >> 2] = i4;
+ i6 = HEAP32[i13 >> 2] | 0;
+ HEAP32[i8 + 12 >> 2] = i6 << 2;
+ if (((HEAP32[i12 >> 2] | 0) != 0 ? (HEAP32[i9 >> 2] | 0) != 0 : 0) ? !((HEAP32[i11 >> 2] | 0) == 0 | (i4 | 0) == 0) : 0) {
+  HEAP32[i8 + 5796 >> 2] = i4 + (i6 >>> 1 << 1);
+  HEAP32[i8 + 5784 >> 2] = i4 + (i6 * 3 | 0);
+  HEAP32[i8 + 132 >> 2] = i7;
+  HEAP32[i8 + 136 >> 2] = i1;
+  HEAP8[i8 + 36 | 0] = 8;
+  i14 = _deflateReset(i3) | 0;
+  STACKTOP = i2;
+  return i14 | 0;
+ }
+ HEAP32[i8 + 4 >> 2] = 666;
+ HEAP32[i5 >> 2] = HEAP32[3176 >> 2];
+ _deflateEnd(i3) | 0;
+ i14 = -4;
+ STACKTOP = i2;
+ return i14 | 0;
+}
+function _longest_match(i19, i16) {
+ i19 = i19 | 0;
+ i16 = i16 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i17 = 0, i18 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0;
+ i1 = STACKTOP;
+ i18 = HEAP32[i19 + 124 >> 2] | 0;
+ i3 = HEAP32[i19 + 56 >> 2] | 0;
+ i5 = HEAP32[i19 + 108 >> 2] | 0;
+ i4 = i3 + i5 | 0;
+ i20 = HEAP32[i19 + 120 >> 2] | 0;
+ i10 = HEAP32[i19 + 144 >> 2] | 0;
+ i2 = (HEAP32[i19 + 44 >> 2] | 0) + -262 | 0;
+ i8 = i5 >>> 0 > i2 >>> 0 ? i5 - i2 | 0 : 0;
+ i6 = HEAP32[i19 + 64 >> 2] | 0;
+ i7 = HEAP32[i19 + 52 >> 2] | 0;
+ i9 = i3 + (i5 + 258) | 0;
+ i2 = HEAP32[i19 + 116 >> 2] | 0;
+ i12 = i10 >>> 0 > i2 >>> 0 ? i2 : i10;
+ i11 = i19 + 112 | 0;
+ i15 = i3 + (i5 + 1) | 0;
+ i14 = i3 + (i5 + 2) | 0;
+ i13 = i9;
+ i10 = i5 + 257 | 0;
+ i17 = i20;
+ i18 = i20 >>> 0 < (HEAP32[i19 + 140 >> 2] | 0) >>> 0 ? i18 : i18 >>> 2;
+ i19 = HEAP8[i3 + (i20 + i5) | 0] | 0;
+ i20 = HEAP8[i3 + (i5 + -1 + i20) | 0] | 0;
+ while (1) {
+  i21 = i3 + i16 | 0;
+  if ((((HEAP8[i3 + (i16 + i17) | 0] | 0) == i19 << 24 >> 24 ? (HEAP8[i3 + (i17 + -1 + i16) | 0] | 0) == i20 << 24 >> 24 : 0) ? (HEAP8[i21] | 0) == (HEAP8[i4] | 0) : 0) ? (HEAP8[i3 + (i16 + 1) | 0] | 0) == (HEAP8[i15] | 0) : 0) {
+   i21 = i3 + (i16 + 2) | 0;
+   i22 = i14;
+   do {
+    i23 = i22 + 1 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 1 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 2 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 2 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 3 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 3 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 4 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 4 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 5 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 5 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 6 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 6 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i23 = i22 + 7 | 0;
+    if ((HEAP8[i23] | 0) != (HEAP8[i21 + 7 | 0] | 0)) {
+     i22 = i23;
+     break;
+    }
+    i22 = i22 + 8 | 0;
+    i21 = i21 + 8 | 0;
+   } while ((HEAP8[i22] | 0) == (HEAP8[i21] | 0) & i22 >>> 0 < i9 >>> 0);
+   i21 = i22 - i13 | 0;
+   i22 = i21 + 258 | 0;
+   if ((i22 | 0) > (i17 | 0)) {
+    HEAP32[i11 >> 2] = i16;
+    if ((i22 | 0) >= (i12 | 0)) {
+     i17 = i22;
+     i3 = 20;
+     break;
+    }
+    i17 = i22;
+    i19 = HEAP8[i3 + (i22 + i5) | 0] | 0;
+    i20 = HEAP8[i3 + (i10 + i21) | 0] | 0;
+   }
+  }
+  i16 = HEAPU16[i6 + ((i16 & i7) << 1) >> 1] | 0;
+  if (!(i16 >>> 0 > i8 >>> 0)) {
+   i3 = 20;
+   break;
+  }
+  i18 = i18 + -1 | 0;
+  if ((i18 | 0) == 0) {
+   i3 = 20;
+   break;
+  }
+ }
+ if ((i3 | 0) == 20) {
+  STACKTOP = i1;
+  return (i17 >>> 0 > i2 >>> 0 ? i2 : i17) | 0;
+ }
+ return 0;
+}
+function __tr_stored_block(i3, i2, i5, i6) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i1 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i1 = STACKTOP;
+ i4 = i3 + 5820 | 0;
+ i7 = HEAP32[i4 >> 2] | 0;
+ i9 = i6 & 65535;
+ i6 = i3 + 5816 | 0;
+ i8 = HEAPU16[i6 >> 1] | 0 | i9 << i7;
+ HEAP16[i6 >> 1] = i8;
+ if ((i7 | 0) > 13) {
+  i11 = i3 + 20 | 0;
+  i7 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i7 + 1;
+  i10 = i3 + 8 | 0;
+  HEAP8[(HEAP32[i10 >> 2] | 0) + i7 | 0] = i8;
+  i8 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+  i7 = HEAP32[i11 >> 2] | 0;
+  HEAP32[i11 >> 2] = i7 + 1;
+  HEAP8[(HEAP32[i10 >> 2] | 0) + i7 | 0] = i8;
+  i7 = HEAP32[i4 >> 2] | 0;
+  i8 = i9 >>> (16 - i7 | 0);
+  HEAP16[i6 >> 1] = i8;
+  i7 = i7 + -13 | 0;
+ } else {
+  i7 = i7 + 3 | 0;
+ }
+ i8 = i8 & 255;
+ HEAP32[i4 >> 2] = i7;
+ do {
+  if ((i7 | 0) <= 8) {
+   i9 = i3 + 20 | 0;
+   if ((i7 | 0) > 0) {
+    i7 = HEAP32[i9 >> 2] | 0;
+    HEAP32[i9 >> 2] = i7 + 1;
+    i11 = i3 + 8 | 0;
+    HEAP8[(HEAP32[i11 >> 2] | 0) + i7 | 0] = i8;
+    i7 = i9;
+    i8 = i11;
+    break;
+   } else {
+    i7 = i9;
+    i8 = i3 + 8 | 0;
+    break;
+   }
+  } else {
+   i7 = i3 + 20 | 0;
+   i10 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i10 + 1;
+   i11 = i3 + 8 | 0;
+   HEAP8[(HEAP32[i11 >> 2] | 0) + i10 | 0] = i8;
+   i10 = (HEAPU16[i6 >> 1] | 0) >>> 8 & 255;
+   i8 = HEAP32[i7 >> 2] | 0;
+   HEAP32[i7 >> 2] = i8 + 1;
+   HEAP8[(HEAP32[i11 >> 2] | 0) + i8 | 0] = i10;
+   i8 = i11;
+  }
+ } while (0);
+ HEAP16[i6 >> 1] = 0;
+ HEAP32[i4 >> 2] = 0;
+ HEAP32[i3 + 5812 >> 2] = 8;
+ i10 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i10 + 1;
+ HEAP8[(HEAP32[i8 >> 2] | 0) + i10 | 0] = i5;
+ i10 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i10 + 1;
+ HEAP8[(HEAP32[i8 >> 2] | 0) + i10 | 0] = i5 >>> 8;
+ i10 = i5 & 65535 ^ 65535;
+ i11 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i11 + 1;
+ HEAP8[(HEAP32[i8 >> 2] | 0) + i11 | 0] = i10;
+ i11 = HEAP32[i7 >> 2] | 0;
+ HEAP32[i7 >> 2] = i11 + 1;
+ HEAP8[(HEAP32[i8 >> 2] | 0) + i11 | 0] = i10 >>> 8;
+ if ((i5 | 0) == 0) {
+  STACKTOP = i1;
+  return;
+ }
+ while (1) {
+  i5 = i5 + -1 | 0;
+  i10 = HEAP8[i2] | 0;
+  i11 = HEAP32[i7 >> 2] | 0;
+  HEAP32[i7 >> 2] = i11 + 1;
+  HEAP8[(HEAP32[i8 >> 2] | 0) + i11 | 0] = i10;
+  if ((i5 | 0) == 0) {
+   break;
+  } else {
+   i2 = i2 + 1 | 0;
+  }
+ }
+ STACKTOP = i1;
+ return;
+}
+function _inflateInit_(i1, i3, i4) {
+ i1 = i1 | 0;
+ i3 = i3 | 0;
+ i4 = i4 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
+ i2 = STACKTOP;
+ if ((i3 | 0) == 0) {
+  i11 = -6;
+  STACKTOP = i2;
+  return i11 | 0;
+ }
+ if (!((HEAP8[i3] | 0) == 49 & (i4 | 0) == 56)) {
+  i11 = -6;
+  STACKTOP = i2;
+  return i11 | 0;
+ }
+ if ((i1 | 0) == 0) {
+  i11 = -2;
+  STACKTOP = i2;
+  return i11 | 0;
+ }
+ i3 = i1 + 24 | 0;
+ HEAP32[i3 >> 2] = 0;
+ i4 = i1 + 32 | 0;
+ i6 = HEAP32[i4 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  HEAP32[i4 >> 2] = 1;
+  HEAP32[i1 + 40 >> 2] = 0;
+  i6 = 1;
+ }
+ i4 = i1 + 36 | 0;
+ if ((HEAP32[i4 >> 2] | 0) == 0) {
+  HEAP32[i4 >> 2] = 1;
+ }
+ i5 = i1 + 40 | 0;
+ i8 = FUNCTION_TABLE_iiii[i6 & 1](HEAP32[i5 >> 2] | 0, 1, 7116) | 0;
+ if ((i8 | 0) == 0) {
+  i11 = -4;
+  STACKTOP = i2;
+  return i11 | 0;
+ }
+ i6 = i1 + 28 | 0;
+ HEAP32[i6 >> 2] = i8;
+ HEAP32[i8 + 52 >> 2] = 0;
+ i9 = HEAP32[i6 >> 2] | 0;
+ do {
+  if ((i9 | 0) != 0) {
+   i10 = i9 + 52 | 0;
+   i11 = HEAP32[i10 >> 2] | 0;
+   i7 = i9 + 36 | 0;
+   if ((i11 | 0) != 0) {
+    if ((HEAP32[i7 >> 2] | 0) == 15) {
+     i10 = i9;
+    } else {
+     FUNCTION_TABLE_vii[HEAP32[i4 >> 2] & 1](HEAP32[i5 >> 2] | 0, i11);
+     HEAP32[i10 >> 2] = 0;
+     i10 = HEAP32[i6 >> 2] | 0;
+    }
+    HEAP32[i9 + 8 >> 2] = 1;
+    HEAP32[i7 >> 2] = 15;
+    if ((i10 | 0) == 0) {
+     break;
+    } else {
+     i9 = i10;
+    }
+   } else {
+    HEAP32[i9 + 8 >> 2] = 1;
+    HEAP32[i7 >> 2] = 15;
+   }
+   HEAP32[i9 + 28 >> 2] = 0;
+   HEAP32[i1 + 20 >> 2] = 0;
+   HEAP32[i1 + 8 >> 2] = 0;
+   HEAP32[i3 >> 2] = 0;
+   HEAP32[i1 + 48 >> 2] = 1;
+   HEAP32[i9 >> 2] = 0;
+   HEAP32[i9 + 4 >> 2] = 0;
+   HEAP32[i9 + 12 >> 2] = 0;
+   HEAP32[i9 + 20 >> 2] = 32768;
+   HEAP32[i9 + 32 >> 2] = 0;
+   HEAP32[i9 + 40 >> 2] = 0;
+   HEAP32[i9 + 44 >> 2] = 0;
+   HEAP32[i9 + 48 >> 2] = 0;
+   HEAP32[i9 + 56 >> 2] = 0;
+   HEAP32[i9 + 60 >> 2] = 0;
+   i11 = i9 + 1328 | 0;
+   HEAP32[i9 + 108 >> 2] = i11;
+   HEAP32[i9 + 80 >> 2] = i11;
+   HEAP32[i9 + 76 >> 2] = i11;
+   HEAP32[i9 + 7104 >> 2] = 1;
+   HEAP32[i9 + 7108 >> 2] = -1;
+   i11 = 0;
+   STACKTOP = i2;
+   return i11 | 0;
+  }
+ } while (0);
+ FUNCTION_TABLE_vii[HEAP32[i4 >> 2] & 1](HEAP32[i5 >> 2] | 0, i8);
+ HEAP32[i6 >> 2] = 0;
+ i11 = -2;
+ STACKTOP = i2;
+ return i11 | 0;
+}
+function _init_block(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ i3 = 0;
+ do {
+  HEAP16[i1 + (i3 << 2) + 148 >> 1] = 0;
+  i3 = i3 + 1 | 0;
+ } while ((i3 | 0) != 286);
+ HEAP16[i1 + 2440 >> 1] = 0;
+ HEAP16[i1 + 2444 >> 1] = 0;
+ HEAP16[i1 + 2448 >> 1] = 0;
+ HEAP16[i1 + 2452 >> 1] = 0;
+ HEAP16[i1 + 2456 >> 1] = 0;
+ HEAP16[i1 + 2460 >> 1] = 0;
+ HEAP16[i1 + 2464 >> 1] = 0;
+ HEAP16[i1 + 2468 >> 1] = 0;
+ HEAP16[i1 + 2472 >> 1] = 0;
+ HEAP16[i1 + 2476 >> 1] = 0;
+ HEAP16[i1 + 2480 >> 1] = 0;
+ HEAP16[i1 + 2484 >> 1] = 0;
+ HEAP16[i1 + 2488 >> 1] = 0;
+ HEAP16[i1 + 2492 >> 1] = 0;
+ HEAP16[i1 + 2496 >> 1] = 0;
+ HEAP16[i1 + 2500 >> 1] = 0;
+ HEAP16[i1 + 2504 >> 1] = 0;
+ HEAP16[i1 + 2508 >> 1] = 0;
+ HEAP16[i1 + 2512 >> 1] = 0;
+ HEAP16[i1 + 2516 >> 1] = 0;
+ HEAP16[i1 + 2520 >> 1] = 0;
+ HEAP16[i1 + 2524 >> 1] = 0;
+ HEAP16[i1 + 2528 >> 1] = 0;
+ HEAP16[i1 + 2532 >> 1] = 0;
+ HEAP16[i1 + 2536 >> 1] = 0;
+ HEAP16[i1 + 2540 >> 1] = 0;
+ HEAP16[i1 + 2544 >> 1] = 0;
+ HEAP16[i1 + 2548 >> 1] = 0;
+ HEAP16[i1 + 2552 >> 1] = 0;
+ HEAP16[i1 + 2556 >> 1] = 0;
+ HEAP16[i1 + 2684 >> 1] = 0;
+ HEAP16[i1 + 2688 >> 1] = 0;
+ HEAP16[i1 + 2692 >> 1] = 0;
+ HEAP16[i1 + 2696 >> 1] = 0;
+ HEAP16[i1 + 2700 >> 1] = 0;
+ HEAP16[i1 + 2704 >> 1] = 0;
+ HEAP16[i1 + 2708 >> 1] = 0;
+ HEAP16[i1 + 2712 >> 1] = 0;
+ HEAP16[i1 + 2716 >> 1] = 0;
+ HEAP16[i1 + 2720 >> 1] = 0;
+ HEAP16[i1 + 2724 >> 1] = 0;
+ HEAP16[i1 + 2728 >> 1] = 0;
+ HEAP16[i1 + 2732 >> 1] = 0;
+ HEAP16[i1 + 2736 >> 1] = 0;
+ HEAP16[i1 + 2740 >> 1] = 0;
+ HEAP16[i1 + 2744 >> 1] = 0;
+ HEAP16[i1 + 2748 >> 1] = 0;
+ HEAP16[i1 + 2752 >> 1] = 0;
+ HEAP16[i1 + 2756 >> 1] = 0;
+ HEAP16[i1 + 1172 >> 1] = 1;
+ HEAP32[i1 + 5804 >> 2] = 0;
+ HEAP32[i1 + 5800 >> 2] = 0;
+ HEAP32[i1 + 5808 >> 2] = 0;
+ HEAP32[i1 + 5792 >> 2] = 0;
+ STACKTOP = i2;
+ return;
+}
+function _deflateReset(i1) {
+ i1 = i1 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0;
+ i2 = STACKTOP;
+ if ((i1 | 0) == 0) {
+  i5 = -2;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ i3 = HEAP32[i1 + 28 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  i5 = -2;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ if ((HEAP32[i1 + 32 >> 2] | 0) == 0) {
+  i5 = -2;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ if ((HEAP32[i1 + 36 >> 2] | 0) == 0) {
+  i5 = -2;
+  STACKTOP = i2;
+  return i5 | 0;
+ }
+ HEAP32[i1 + 20 >> 2] = 0;
+ HEAP32[i1 + 8 >> 2] = 0;
+ HEAP32[i1 + 24 >> 2] = 0;
+ HEAP32[i1 + 44 >> 2] = 2;
+ HEAP32[i3 + 20 >> 2] = 0;
+ HEAP32[i3 + 16 >> 2] = HEAP32[i3 + 8 >> 2];
+ i4 = i3 + 24 | 0;
+ i5 = HEAP32[i4 >> 2] | 0;
+ if ((i5 | 0) < 0) {
+  i5 = 0 - i5 | 0;
+  HEAP32[i4 >> 2] = i5;
+ }
+ HEAP32[i3 + 4 >> 2] = (i5 | 0) != 0 ? 42 : 113;
+ if ((i5 | 0) == 2) {
+  i4 = _crc32(0, 0, 0) | 0;
+ } else {
+  i4 = _adler32(0, 0, 0) | 0;
+ }
+ HEAP32[i1 + 48 >> 2] = i4;
+ HEAP32[i3 + 40 >> 2] = 0;
+ __tr_init(i3);
+ HEAP32[i3 + 60 >> 2] = HEAP32[i3 + 44 >> 2] << 1;
+ i5 = HEAP32[i3 + 76 >> 2] | 0;
+ i4 = HEAP32[i3 + 68 >> 2] | 0;
+ HEAP16[i4 + (i5 + -1 << 1) >> 1] = 0;
+ _memset(i4 | 0, 0, (i5 << 1) + -2 | 0) | 0;
+ i5 = HEAP32[i3 + 132 >> 2] | 0;
+ HEAP32[i3 + 128 >> 2] = HEAPU16[178 + (i5 * 12 | 0) >> 1] | 0;
+ HEAP32[i3 + 140 >> 2] = HEAPU16[176 + (i5 * 12 | 0) >> 1] | 0;
+ HEAP32[i3 + 144 >> 2] = HEAPU16[180 + (i5 * 12 | 0) >> 1] | 0;
+ HEAP32[i3 + 124 >> 2] = HEAPU16[182 + (i5 * 12 | 0) >> 1] | 0;
+ HEAP32[i3 + 108 >> 2] = 0;
+ HEAP32[i3 + 92 >> 2] = 0;
+ HEAP32[i3 + 116 >> 2] = 0;
+ HEAP32[i3 + 120 >> 2] = 2;
+ HEAP32[i3 + 96 >> 2] = 2;
+ HEAP32[i3 + 112 >> 2] = 0;
+ HEAP32[i3 + 104 >> 2] = 0;
+ HEAP32[i3 + 72 >> 2] = 0;
+ i5 = 0;
+ STACKTOP = i2;
+ return i5 | 0;
+}
+function _updatewindow(i6, i4) {
+ i6 = i6 | 0;
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0;
+ i1 = STACKTOP;
+ i2 = HEAP32[i6 + 28 >> 2] | 0;
+ i3 = i2 + 52 | 0;
+ i8 = HEAP32[i3 >> 2] | 0;
+ if ((i8 | 0) == 0) {
+  i8 = FUNCTION_TABLE_iiii[HEAP32[i6 + 32 >> 2] & 1](HEAP32[i6 + 40 >> 2] | 0, 1 << HEAP32[i2 + 36 >> 2], 1) | 0;
+  HEAP32[i3 >> 2] = i8;
+  if ((i8 | 0) == 0) {
+   i10 = 1;
+   STACKTOP = i1;
+   return i10 | 0;
+  }
+ }
+ i5 = i2 + 40 | 0;
+ i10 = HEAP32[i5 >> 2] | 0;
+ if ((i10 | 0) == 0) {
+  i10 = 1 << HEAP32[i2 + 36 >> 2];
+  HEAP32[i5 >> 2] = i10;
+  HEAP32[i2 + 48 >> 2] = 0;
+  HEAP32[i2 + 44 >> 2] = 0;
+ }
+ i4 = i4 - (HEAP32[i6 + 16 >> 2] | 0) | 0;
+ if (!(i4 >>> 0 < i10 >>> 0)) {
+  _memcpy(i8 | 0, (HEAP32[i6 + 12 >> 2] | 0) + (0 - i10) | 0, i10 | 0) | 0;
+  HEAP32[i2 + 48 >> 2] = 0;
+  HEAP32[i2 + 44 >> 2] = HEAP32[i5 >> 2];
+  i10 = 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i7 = i2 + 48 | 0;
+ i9 = HEAP32[i7 >> 2] | 0;
+ i10 = i10 - i9 | 0;
+ i10 = i10 >>> 0 > i4 >>> 0 ? i4 : i10;
+ i6 = i6 + 12 | 0;
+ _memcpy(i8 + i9 | 0, (HEAP32[i6 >> 2] | 0) + (0 - i4) | 0, i10 | 0) | 0;
+ i8 = i4 - i10 | 0;
+ if ((i4 | 0) != (i10 | 0)) {
+  _memcpy(HEAP32[i3 >> 2] | 0, (HEAP32[i6 >> 2] | 0) + (0 - i8) | 0, i8 | 0) | 0;
+  HEAP32[i7 >> 2] = i8;
+  HEAP32[i2 + 44 >> 2] = HEAP32[i5 >> 2];
+  i10 = 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ i6 = (HEAP32[i7 >> 2] | 0) + i4 | 0;
+ i3 = HEAP32[i5 >> 2] | 0;
+ HEAP32[i7 >> 2] = (i6 | 0) == (i3 | 0) ? 0 : i6;
+ i5 = i2 + 44 | 0;
+ i2 = HEAP32[i5 >> 2] | 0;
+ if (!(i2 >>> 0 < i3 >>> 0)) {
+  i10 = 0;
+  STACKTOP = i1;
+  return i10 | 0;
+ }
+ HEAP32[i5 >> 2] = i2 + i4;
+ i10 = 0;
+ STACKTOP = i1;
+ return i10 | 0;
+}
+function _scan_tree(i1, i5, i6) {
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i6 = i6 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0;
+ i8 = STACKTOP;
+ i10 = HEAP16[i5 + 2 >> 1] | 0;
+ i9 = i10 << 16 >> 16 == 0;
+ HEAP16[i5 + (i6 + 1 << 2) + 2 >> 1] = -1;
+ i2 = i1 + 2752 | 0;
+ i3 = i1 + 2756 | 0;
+ i4 = i1 + 2748 | 0;
+ i7 = i9 ? 138 : 7;
+ i9 = i9 ? 3 : 4;
+ i13 = 0;
+ i11 = i10 & 65535;
+ i12 = -1;
+ L1 : while (1) {
+  i14 = 0;
+  do {
+   if ((i13 | 0) > (i6 | 0)) {
+    break L1;
+   }
+   i13 = i13 + 1 | 0;
+   i16 = HEAP16[i5 + (i13 << 2) + 2 >> 1] | 0;
+   i10 = i16 & 65535;
+   i14 = i14 + 1 | 0;
+   i15 = (i11 | 0) == (i10 | 0);
+  } while ((i14 | 0) < (i7 | 0) & i15);
+  do {
+   if ((i14 | 0) >= (i9 | 0)) {
+    if ((i11 | 0) == 0) {
+     if ((i14 | 0) < 11) {
+      HEAP16[i2 >> 1] = (HEAP16[i2 >> 1] | 0) + 1 << 16 >> 16;
+      break;
+     } else {
+      HEAP16[i3 >> 1] = (HEAP16[i3 >> 1] | 0) + 1 << 16 >> 16;
+      break;
+     }
+    } else {
+     if ((i11 | 0) != (i12 | 0)) {
+      i14 = i1 + (i11 << 2) + 2684 | 0;
+      HEAP16[i14 >> 1] = (HEAP16[i14 >> 1] | 0) + 1 << 16 >> 16;
+     }
+     HEAP16[i4 >> 1] = (HEAP16[i4 >> 1] | 0) + 1 << 16 >> 16;
+     break;
+    }
+   } else {
+    i12 = i1 + (i11 << 2) + 2684 | 0;
+    HEAP16[i12 >> 1] = (HEAPU16[i12 >> 1] | 0) + i14;
+   }
+  } while (0);
+  if (i16 << 16 >> 16 == 0) {
+   i12 = i11;
+   i7 = 138;
+   i9 = 3;
+   i11 = i10;
+   continue;
+  }
+  i12 = i11;
+  i7 = i15 ? 6 : 7;
+  i9 = i15 ? 3 : 4;
+  i11 = i10;
+ }
+ STACKTOP = i8;
+ return;
+}
+function _deflateEnd(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i3 = STACKTOP;
+ if ((i4 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i3;
+  return i7 | 0;
+ }
+ i1 = i4 + 28 | 0;
+ i6 = HEAP32[i1 >> 2] | 0;
+ if ((i6 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i3;
+  return i7 | 0;
+ }
+ i2 = HEAP32[i6 + 4 >> 2] | 0;
+ switch (i2 | 0) {
+ case 42:
+ case 69:
+ case 73:
+ case 91:
+ case 103:
+ case 113:
+ case 666:
+  {
+   break;
+  }
+ default:
+  {
+   i7 = -2;
+   STACKTOP = i3;
+   return i7 | 0;
+  }
+ }
+ i5 = HEAP32[i6 + 8 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  FUNCTION_TABLE_vii[HEAP32[i4 + 36 >> 2] & 1](HEAP32[i4 + 40 >> 2] | 0, i5);
+  i6 = HEAP32[i1 >> 2] | 0;
+ }
+ i5 = HEAP32[i6 + 68 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  FUNCTION_TABLE_vii[HEAP32[i4 + 36 >> 2] & 1](HEAP32[i4 + 40 >> 2] | 0, i5);
+  i6 = HEAP32[i1 >> 2] | 0;
+ }
+ i5 = HEAP32[i6 + 64 >> 2] | 0;
+ if ((i5 | 0) != 0) {
+  FUNCTION_TABLE_vii[HEAP32[i4 + 36 >> 2] & 1](HEAP32[i4 + 40 >> 2] | 0, i5);
+  i6 = HEAP32[i1 >> 2] | 0;
+ }
+ i7 = HEAP32[i6 + 56 >> 2] | 0;
+ i5 = i4 + 36 | 0;
+ if ((i7 | 0) == 0) {
+  i4 = i4 + 40 | 0;
+ } else {
+  i4 = i4 + 40 | 0;
+  FUNCTION_TABLE_vii[HEAP32[i5 >> 2] & 1](HEAP32[i4 >> 2] | 0, i7);
+  i6 = HEAP32[i1 >> 2] | 0;
+ }
+ FUNCTION_TABLE_vii[HEAP32[i5 >> 2] & 1](HEAP32[i4 >> 2] | 0, i6);
+ HEAP32[i1 >> 2] = 0;
+ i7 = (i2 | 0) == 113 ? -3 : 0;
+ STACKTOP = i3;
+ return i7 | 0;
+}
+function _main(i4, i5) {
+ i4 = i4 | 0;
+ i5 = i5 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i6 = 0;
+ i1 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i2 = i1;
+ L1 : do {
+  if ((i4 | 0) > 1) {
+   i4 = HEAP8[HEAP32[i5 + 4 >> 2] | 0] | 0;
+   switch (i4 | 0) {
+   case 50:
+    {
+     i2 = 250;
+     break L1;
+    }
+   case 51:
+    {
+     i3 = 4;
+     break L1;
+    }
+   case 52:
+    {
+     i2 = 2500;
+     break L1;
+    }
+   case 53:
+    {
+     i2 = 5e3;
+     break L1;
+    }
+   case 48:
+    {
+     i6 = 0;
+     STACKTOP = i1;
+     return i6 | 0;
+    }
+   case 49:
+    {
+     i2 = 60;
+     break L1;
+    }
+   default:
+    {
+     HEAP32[i2 >> 2] = i4 + -48;
+     _printf(144, i2 | 0) | 0;
+     i6 = -1;
+     STACKTOP = i1;
+     return i6 | 0;
+    }
+   }
+  } else {
+   i3 = 4;
+  }
+ } while (0);
+ if ((i3 | 0) == 4) {
+  i2 = 500;
+ }
+ i3 = _malloc(1e5) | 0;
+ i4 = 0;
+ i6 = 0;
+ i5 = 17;
+ while (1) {
+  do {
+   if ((i6 | 0) <= 0) {
+    if ((i4 & 7 | 0) == 0) {
+     i6 = i4 & 31;
+     i5 = 0;
+     break;
+    } else {
+     i5 = (((Math_imul(i4, i4) | 0) >>> 0) % 6714 | 0) & 255;
+     break;
+    }
+   } else {
+    i6 = i6 + -1 | 0;
+   }
+  } while (0);
+  HEAP8[i3 + i4 | 0] = i5;
+  i4 = i4 + 1 | 0;
+  if ((i4 | 0) == 1e5) {
+   i4 = 0;
+   break;
+  }
+ }
+ do {
+  _doit(i3, 1e5, i4);
+  i4 = i4 + 1 | 0;
+ } while ((i4 | 0) < (i2 | 0));
+ _puts(160) | 0;
+ i6 = 0;
+ STACKTOP = i1;
+ return i6 | 0;
+}
+function _doit(i6, i1, i7) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i8 = 0, i9 = 0;
+ i5 = STACKTOP;
+ STACKTOP = STACKTOP + 16 | 0;
+ i4 = i5;
+ i3 = i5 + 12 | 0;
+ i2 = i5 + 8 | 0;
+ i8 = _compressBound(i1) | 0;
+ i9 = HEAP32[2] | 0;
+ if ((i9 | 0) == 0) {
+  i9 = _malloc(i8) | 0;
+  HEAP32[2] = i9;
+ }
+ if ((HEAP32[4] | 0) == 0) {
+  HEAP32[4] = _malloc(i1) | 0;
+ }
+ HEAP32[i3 >> 2] = i8;
+ _compress(i9, i3, i6, i1) | 0;
+ i7 = (i7 | 0) == 0;
+ if (i7) {
+  i9 = HEAP32[i3 >> 2] | 0;
+  HEAP32[i4 >> 2] = i1;
+  HEAP32[i4 + 4 >> 2] = i9;
+  _printf(24, i4 | 0) | 0;
+ }
+ HEAP32[i2 >> 2] = i1;
+ _uncompress(HEAP32[4] | 0, i2, HEAP32[2] | 0, HEAP32[i3 >> 2] | 0) | 0;
+ if ((HEAP32[i2 >> 2] | 0) != (i1 | 0)) {
+  ___assert_fail(40, 72, 24, 104);
+ }
+ if (!i7) {
+  STACKTOP = i5;
+  return;
+ }
+ if ((_strcmp(i6, HEAP32[4] | 0) | 0) == 0) {
+  STACKTOP = i5;
+  return;
+ } else {
+  ___assert_fail(112, 72, 25, 104);
+ }
+}
+function _uncompress(i6, i1, i5, i7) {
+ i6 = i6 | 0;
+ i1 = i1 | 0;
+ i5 = i5 | 0;
+ i7 = i7 | 0;
+ var i2 = 0, i3 = 0, i4 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i3 = i2;
+ HEAP32[i3 >> 2] = i5;
+ i5 = i3 + 4 | 0;
+ HEAP32[i5 >> 2] = i7;
+ HEAP32[i3 + 12 >> 2] = i6;
+ HEAP32[i3 + 16 >> 2] = HEAP32[i1 >> 2];
+ HEAP32[i3 + 32 >> 2] = 0;
+ HEAP32[i3 + 36 >> 2] = 0;
+ i6 = _inflateInit_(i3, 2992, 56) | 0;
+ if ((i6 | 0) != 0) {
+  i7 = i6;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i6 = _inflate(i3, 4) | 0;
+ if ((i6 | 0) == 1) {
+  HEAP32[i1 >> 2] = HEAP32[i3 + 20 >> 2];
+  i7 = _inflateEnd(i3) | 0;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ _inflateEnd(i3) | 0;
+ if ((i6 | 0) == 2) {
+  i7 = -3;
+  STACKTOP = i2;
+  return i7 | 0;
+ } else if ((i6 | 0) == -5) {
+  i4 = 4;
+ }
+ if ((i4 | 0) == 4 ? (HEAP32[i5 >> 2] | 0) == 0 : 0) {
+  i7 = -3;
+  STACKTOP = i2;
+  return i7 | 0;
+ }
+ i7 = i6;
+ STACKTOP = i2;
+ return i7 | 0;
+}
+function _compress(i4, i1, i6, i5) {
+ i4 = i4 | 0;
+ i1 = i1 | 0;
+ i6 = i6 | 0;
+ i5 = i5 | 0;
+ var i2 = 0, i3 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + 64 | 0;
+ i3 = i2;
+ HEAP32[i3 >> 2] = i6;
+ HEAP32[i3 + 4 >> 2] = i5;
+ HEAP32[i3 + 12 >> 2] = i4;
+ HEAP32[i3 + 16 >> 2] = HEAP32[i1 >> 2];
+ HEAP32[i3 + 32 >> 2] = 0;
+ HEAP32[i3 + 36 >> 2] = 0;
+ HEAP32[i3 + 40 >> 2] = 0;
+ i4 = _deflateInit_(i3, -1, 168, 56) | 0;
+ if ((i4 | 0) != 0) {
+  i6 = i4;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ i4 = _deflate(i3, 4) | 0;
+ if ((i4 | 0) == 1) {
+  HEAP32[i1 >> 2] = HEAP32[i3 + 20 >> 2];
+  i6 = _deflateEnd(i3) | 0;
+  STACKTOP = i2;
+  return i6 | 0;
+ } else {
+  _deflateEnd(i3) | 0;
+  i6 = (i4 | 0) == 0 ? -5 : i4;
+  STACKTOP = i2;
+  return i6 | 0;
+ }
+ return 0;
+}
+function _inflateEnd(i4) {
+ i4 = i4 | 0;
+ var i1 = 0, i2 = 0, i3 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i1 = STACKTOP;
+ if ((i4 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i2 = i4 + 28 | 0;
+ i3 = HEAP32[i2 >> 2] | 0;
+ if ((i3 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i6 = i4 + 36 | 0;
+ i5 = HEAP32[i6 >> 2] | 0;
+ if ((i5 | 0) == 0) {
+  i7 = -2;
+  STACKTOP = i1;
+  return i7 | 0;
+ }
+ i7 = HEAP32[i3 + 52 >> 2] | 0;
+ i4 = i4 + 40 | 0;
+ if ((i7 | 0) != 0) {
+  FUNCTION_TABLE_vii[i5 & 1](HEAP32[i4 >> 2] | 0, i7);
+  i5 = HEAP32[i6 >> 2] | 0;
+  i3 = HEAP32[i2 >> 2] | 0;
+ }
+ FUNCTION_TABLE_vii[i5 & 1](HEAP32[i4 >> 2] | 0, i3);
+ HEAP32[i2 >> 2] = 0;
+ i7 = 0;
+ STACKTOP = i1;
+ return i7 | 0;
+}
+function _memcpy(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i4 = 0;
+ if ((i1 | 0) >= 4096) return _emscripten_memcpy_big(i3 | 0, i2 | 0, i1 | 0) | 0;
+ i4 = i3 | 0;
+ if ((i3 & 3) == (i2 & 3)) {
+  while (i3 & 3) {
+   if ((i1 | 0) == 0) return i4 | 0;
+   HEAP8[i3] = HEAP8[i2] | 0;
+   i3 = i3 + 1 | 0;
+   i2 = i2 + 1 | 0;
+   i1 = i1 - 1 | 0;
+  }
+  while ((i1 | 0) >= 4) {
+   HEAP32[i3 >> 2] = HEAP32[i2 >> 2];
+   i3 = i3 + 4 | 0;
+   i2 = i2 + 4 | 0;
+   i1 = i1 - 4 | 0;
+  }
+ }
+ while ((i1 | 0) > 0) {
+  HEAP8[i3] = HEAP8[i2] | 0;
+  i3 = i3 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i1 = i1 - 1 | 0;
+ }
+ return i4 | 0;
+}
+function _strcmp(i4, i2) {
+ i4 = i4 | 0;
+ i2 = i2 | 0;
+ var i1 = 0, i3 = 0, i5 = 0;
+ i1 = STACKTOP;
+ i5 = HEAP8[i4] | 0;
+ i3 = HEAP8[i2] | 0;
+ if (i5 << 24 >> 24 != i3 << 24 >> 24 | i5 << 24 >> 24 == 0 | i3 << 24 >> 24 == 0) {
+  i4 = i5;
+  i5 = i3;
+  i4 = i4 & 255;
+  i5 = i5 & 255;
+  i5 = i4 - i5 | 0;
+  STACKTOP = i1;
+  return i5 | 0;
+ }
+ do {
+  i4 = i4 + 1 | 0;
+  i2 = i2 + 1 | 0;
+  i5 = HEAP8[i4] | 0;
+  i3 = HEAP8[i2] | 0;
+ } while (!(i5 << 24 >> 24 != i3 << 24 >> 24 | i5 << 24 >> 24 == 0 | i3 << 24 >> 24 == 0));
+ i4 = i5 & 255;
+ i5 = i3 & 255;
+ i5 = i4 - i5 | 0;
+ STACKTOP = i1;
+ return i5 | 0;
+}
+function _memset(i1, i4, i3) {
+ i1 = i1 | 0;
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ var i2 = 0, i5 = 0, i6 = 0, i7 = 0;
+ i2 = i1 + i3 | 0;
+ if ((i3 | 0) >= 20) {
+  i4 = i4 & 255;
+  i7 = i1 & 3;
+  i6 = i4 | i4 << 8 | i4 << 16 | i4 << 24;
+  i5 = i2 & ~3;
+  if (i7) {
+   i7 = i1 + 4 - i7 | 0;
+   while ((i1 | 0) < (i7 | 0)) {
+    HEAP8[i1] = i4;
+    i1 = i1 + 1 | 0;
+   }
+  }
+  while ((i1 | 0) < (i5 | 0)) {
+   HEAP32[i1 >> 2] = i6;
+   i1 = i1 + 4 | 0;
+  }
+ }
+ while ((i1 | 0) < (i2 | 0)) {
+  HEAP8[i1] = i4;
+  i1 = i1 + 1 | 0;
+ }
+ return i1 - i3 | 0;
+}
+function copyTempDouble(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+ HEAP8[tempDoublePtr + 4 | 0] = HEAP8[i1 + 4 | 0];
+ HEAP8[tempDoublePtr + 5 | 0] = HEAP8[i1 + 5 | 0];
+ HEAP8[tempDoublePtr + 6 | 0] = HEAP8[i1 + 6 | 0];
+ HEAP8[tempDoublePtr + 7 | 0] = HEAP8[i1 + 7 | 0];
+}
+function __tr_init(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ HEAP32[i1 + 2840 >> 2] = i1 + 148;
+ HEAP32[i1 + 2848 >> 2] = 1064;
+ HEAP32[i1 + 2852 >> 2] = i1 + 2440;
+ HEAP32[i1 + 2860 >> 2] = 1088;
+ HEAP32[i1 + 2864 >> 2] = i1 + 2684;
+ HEAP32[i1 + 2872 >> 2] = 1112;
+ HEAP16[i1 + 5816 >> 1] = 0;
+ HEAP32[i1 + 5820 >> 2] = 0;
+ HEAP32[i1 + 5812 >> 2] = 8;
+ _init_block(i1);
+ STACKTOP = i2;
+ return;
+}
+function copyTempFloat(i1) {
+ i1 = i1 | 0;
+ HEAP8[tempDoublePtr] = HEAP8[i1];
+ HEAP8[tempDoublePtr + 1 | 0] = HEAP8[i1 + 1 | 0];
+ HEAP8[tempDoublePtr + 2 | 0] = HEAP8[i1 + 2 | 0];
+ HEAP8[tempDoublePtr + 3 | 0] = HEAP8[i1 + 3 | 0];
+}
+function _deflateInit_(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ var i5 = 0;
+ i5 = STACKTOP;
+ i4 = _deflateInit2_(i4, i3, 8, 15, 8, 0, i2, i1) | 0;
+ STACKTOP = i5;
+ return i4 | 0;
+}
+function _zcalloc(i3, i1, i2) {
+ i3 = i3 | 0;
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ var i4 = 0;
+ i4 = STACKTOP;
+ i3 = _malloc(Math_imul(i2, i1) | 0) | 0;
+ STACKTOP = i4;
+ return i3 | 0;
+}
+function dynCall_iiii(i4, i3, i2, i1) {
+ i4 = i4 | 0;
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iiii[i4 & 1](i3 | 0, i2 | 0, i1 | 0) | 0;
+}
+function runPostSets() {}
+function _strlen(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = i1;
+ while (HEAP8[i2] | 0) {
+  i2 = i2 + 1 | 0;
+ }
+ return i2 - i1 | 0;
+}
+function stackAlloc(i1) {
+ i1 = i1 | 0;
+ var i2 = 0;
+ i2 = STACKTOP;
+ STACKTOP = STACKTOP + i1 | 0;
+ STACKTOP = STACKTOP + 7 & -8;
+ return i2 | 0;
+}
+function dynCall_iii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ return FUNCTION_TABLE_iii[i3 & 3](i2 | 0, i1 | 0) | 0;
+}
+function setThrew(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ if ((__THREW__ | 0) == 0) {
+  __THREW__ = i1;
+  threwValue = i2;
+ }
+}
+function dynCall_vii(i3, i2, i1) {
+ i3 = i3 | 0;
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ FUNCTION_TABLE_vii[i3 & 1](i2 | 0, i1 | 0);
+}
+function _zcfree(i2, i1) {
+ i2 = i2 | 0;
+ i1 = i1 | 0;
+ i2 = STACKTOP;
+ _free(i1);
+ STACKTOP = i2;
+ return;
+}
+function _compressBound(i1) {
+ i1 = i1 | 0;
+ return i1 + 13 + (i1 >>> 12) + (i1 >>> 14) + (i1 >>> 25) | 0;
+}
+function b0(i1, i2, i3) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ i3 = i3 | 0;
+ abort(0);
+ return 0;
+}
+function b2(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(2);
+ return 0;
+}
+function b1(i1, i2) {
+ i1 = i1 | 0;
+ i2 = i2 | 0;
+ abort(1);
+}
+function stackRestore(i1) {
+ i1 = i1 | 0;
+ STACKTOP = i1;
+}
+function setTempRet9(i1) {
+ i1 = i1 | 0;
+ tempRet9 = i1;
+}
+function setTempRet8(i1) {
+ i1 = i1 | 0;
+ tempRet8 = i1;
+}
+function setTempRet7(i1) {
+ i1 = i1 | 0;
+ tempRet7 = i1;
+}
+function setTempRet6(i1) {
+ i1 = i1 | 0;
+ tempRet6 = i1;
+}
+function setTempRet5(i1) {
+ i1 = i1 | 0;
+ tempRet5 = i1;
+}
+function setTempRet4(i1) {
+ i1 = i1 | 0;
+ tempRet4 = i1;
+}
+function setTempRet3(i1) {
+ i1 = i1 | 0;
+ tempRet3 = i1;
+}
+function setTempRet2(i1) {
+ i1 = i1 | 0;
+ tempRet2 = i1;
+}
+function setTempRet1(i1) {
+ i1 = i1 | 0;
+ tempRet1 = i1;
+}
+function setTempRet0(i1) {
+ i1 = i1 | 0;
+ tempRet0 = i1;
+}
+function stackSave() {
+ return STACKTOP | 0;
+}
+
+// EMSCRIPTEN_END_FUNCS
+  var FUNCTION_TABLE_iiii = [b0,_zcalloc];
+  var FUNCTION_TABLE_vii = [b1,_zcfree];
+  var FUNCTION_TABLE_iii = [b2,_deflate_stored,_deflate_fast,_deflate_slow];
+
+  return { _strlen: _strlen, _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_iiii: dynCall_iiii, dynCall_vii: dynCall_vii, dynCall_iii: dynCall_iii };
+})
+// EMSCRIPTEN_END_ASM
+({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_iiii": invoke_iiii, "invoke_vii": invoke_vii, "invoke_iii": invoke_iii, "_send": _send, "___setErrNo": ___setErrNo, "___assert_fail": ___assert_fail, "_fflush": _fflush, "_pwrite": _pwrite, "__reallyNegative": __reallyNegative, "_sbrk": _sbrk, "___errno_location": ___errno_location, "_emscripten_memcpy_big": _emscripten_memcpy_big, "_fileno": _fileno, "_sysconf": _sysconf, "_puts": _puts, "_mkport": _mkport, "_write": _write, "_llvm_bswap_i32": _llvm_bswap_i32, "_fputc": _fputc, "_abort": _abort, "_fwrite": _fwrite, "_time": _time, "_fprintf": _fprintf, "__formatString": __formatString, "_fputs": _fputs, "_printf": _printf, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "NaN": NaN, "Infinity": Infinity }, buffer);
+var _strlen = Module["_strlen"] = asm["_strlen"];
+var _free = Module["_free"] = asm["_free"];
+var _main = Module["_main"] = asm["_main"];
+var _memset = Module["_memset"] = asm["_memset"];
+var _malloc = Module["_malloc"] = asm["_malloc"];
+var _memcpy = Module["_memcpy"] = asm["_memcpy"];
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var dynCall_iiii = Module["dynCall_iiii"] = asm["dynCall_iiii"];
+var dynCall_vii = Module["dynCall_vii"] = asm["dynCall_vii"];
+var dynCall_iii = Module["dynCall_iii"] = asm["dynCall_iii"];
+
+Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) };
+Runtime.stackSave = function() { return asm['stackSave']() };
+Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
+
+
+// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included
+var i64Math = null;
+
+// === Auto-generated postamble setup entry stuff ===
+
+if (memoryInitializer) {
+  if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+    var data = Module['readBinary'](memoryInitializer);
+    HEAPU8.set(data, STATIC_BASE);
+  } else {
+    addRunDependency('memory initializer');
+    Browser.asyncLoad(memoryInitializer, function(data) {
+      HEAPU8.set(data, STATIC_BASE);
+      removeRunDependency('memory initializer');
+    }, function(data) {
+      throw 'could not load memory initializer ' + memoryInitializer;
+    });
+  }
+}
+
+function ExitStatus(status) {
+  this.name = "ExitStatus";
+  this.message = "Program terminated with exit(" + status + ")";
+  this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
+var initialStackTop;
+var preloadStartTime = null;
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+  // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+  if (!Module['calledRun'] && shouldRunNow) run([].concat(Module["arguments"]));
+  if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+}
+
+Module['callMain'] = Module.callMain = function callMain(args) {
+  assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
+  assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+  args = args || [];
+
+  ensureInitRuntime();
+
+  var argc = args.length+1;
+  function pad() {
+    for (var i = 0; i < 4-1; i++) {
+      argv.push(0);
+    }
+  }
+  var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ];
+  pad();
+  for (var i = 0; i < argc-1; i = i + 1) {
+    argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL));
+    pad();
+  }
+  argv.push(0);
+  argv = allocate(argv, 'i32', ALLOC_NORMAL);
+
+  initialStackTop = STACKTOP;
+
+  try {
+
+    var ret = Module['_main'](argc, argv, 0);
+
+
+    // if we're not running an evented main loop, it's time to exit
+    if (!Module['noExitRuntime']) {
+      exit(ret);
+    }
+  }
+  catch(e) {
+    if (e instanceof ExitStatus) {
+      // exit() throws this once it's done to make sure execution
+      // has been stopped completely
+      return;
+    } else if (e == 'SimulateInfiniteLoop') {
+      // running an evented main loop, don't immediately exit
+      Module['noExitRuntime'] = true;
+      return;
+    } else {
+      if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
+      throw e;
+    }
+  } finally {
+    calledMain = true;
+  }
+}
+
+
+
+
+function run(args) {
+  args = args || Module['arguments'];
+
+  if (preloadStartTime === null) preloadStartTime = Date.now();
+
+  if (runDependencies > 0) {
+    Module.printErr('run() called, but dependencies remain, so not running');
+    return;
+  }
+
+  preRun();
+
+  if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
+  if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
+
+  function doRun() {
+    if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+    Module['calledRun'] = true;
+
+    ensureInitRuntime();
+
+    preMain();
+
+    if (ENVIRONMENT_IS_WEB && preloadStartTime !== null) {
+      Module.printErr('pre-main prep time: ' + (Date.now() - preloadStartTime) + ' ms');
+    }
+
+    if (Module['_main'] && shouldRunNow) {
+      Module['callMain'](args);
+    }
+
+    postRun();
+  }
+
+  if (Module['setStatus']) {
+    Module['setStatus']('Running...');
+    setTimeout(function() {
+      setTimeout(function() {
+        Module['setStatus']('');
+      }, 1);
+      if (!ABORT) doRun();
+    }, 1);
+  } else {
+    doRun();
+  }
+}
+Module['run'] = Module.run = run;
+
+function exit(status) {
+  ABORT = true;
+  EXITSTATUS = status;
+  STACKTOP = initialStackTop;
+
+  // exit the runtime
+  exitRuntime();
+
+  // TODO We should handle this differently based on environment.
+  // In the browser, the best we can do is throw an exception
+  // to halt execution, but in node we could process.exit and
+  // I'd imagine SM shell would have something equivalent.
+  // This would let us set a proper exit status (which
+  // would be great for checking test exit statuses).
+  // https://github.com/kripken/emscripten/issues/1371
+
+  // throw an exception to halt the current execution
+  throw new ExitStatus(status);
+}
+Module['exit'] = Module.exit = exit;
+
+function abort(text) {
+  if (text) {
+    Module.print(text);
+    Module.printErr(text);
+  }
+
+  ABORT = true;
+  EXITSTATUS = 1;
+
+  var extra = '\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.';
+
+  throw 'abort() at ' + stackTrace() + extra;
+}
+Module['abort'] = Module.abort = abort;
+
+// {{PRE_RUN_ADDITIONS}}
+
+if (Module['preInit']) {
+  if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+  while (Module['preInit'].length > 0) {
+    Module['preInit'].pop()();
+  }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+if (Module['noInitialRun']) {
+  shouldRunNow = false;
+}
+
+
+run([].concat(Module["arguments"]));
diff --git a/test/mjsunit/asm/float32array-negative-offset.js b/test/mjsunit/asm/float32array-negative-offset.js
new file mode 100644
index 0000000..524bdc8
--- /dev/null
+++ b/test/mjsunit/asm/float32array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Float32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = +MEM32[i >> 2];
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = +v;
+    MEM32[i >> 2] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = +MEM32[i + 8 >> 2];
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = +v;
+    MEM32[i + 8 >> 2] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(NaN, m.load(-8));
+assertEquals(NaN, m.load8(-16));
+m.store(0, 42.0);
+assertEquals(42.0, m.load8(-8));
+m.store8(-8, 99.0);
+assertEquals(99.0, m.load(0));
+assertEquals(99.0, m.load8(-8));
diff --git a/test/mjsunit/asm/float32array-outofbounds.js b/test/mjsunit/asm/float32array-outofbounds.js
new file mode 100644
index 0000000..8709b70
--- /dev/null
+++ b/test/mjsunit/asm/float32array-outofbounds.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Float32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = +MEM32[i >> 2];
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = +v;
+    MEM32[i >> 2] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(4));
+
+m.store(0, 42.0);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 4 * 32 * 1024, i);
+}
+assertEquals(42.0, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(NaN, m.load(i * 4 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/float32array-store-div.js b/test/mjsunit/asm/float32array-store-div.js
new file mode 100644
index 0000000..78224f9
--- /dev/null
+++ b/test/mjsunit/asm/float32array-store-div.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Float32Array(heap);
+  function foo(i) {
+    MEM32[0] = (i >>> 0) / 2;
+    return MEM32[0];
+  }
+  return { foo: foo };
+}
+
+var foo = Module(this, {}, new ArrayBuffer(64 * 1024)).foo;
+assertEquals(0.5, foo(1));
diff --git a/test/mjsunit/asm/float64array-negative-offset.js b/test/mjsunit/asm/float64array-negative-offset.js
new file mode 100644
index 0000000..154bd82
--- /dev/null
+++ b/test/mjsunit/asm/float64array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM64 = new stdlib.Float64Array(heap);
+  function load(i) {
+    i = i|0;
+    i = +MEM64[i >> 3];
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = +v;
+    MEM64[i >> 3] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = +MEM64[i + 8 >> 3];
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = +v;
+    MEM64[i + 8 >> 3] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(NaN, m.load(-8));
+assertEquals(NaN, m.load8(-16));
+m.store(0, 42.0);
+assertEquals(42.0, m.load8(-8));
+m.store8(-8, 99.0);
+assertEquals(99.0, m.load(0));
+assertEquals(99.0, m.load8(-8));
diff --git a/test/mjsunit/asm/float64array-outofbounds.js b/test/mjsunit/asm/float64array-outofbounds.js
new file mode 100644
index 0000000..106d8e4
--- /dev/null
+++ b/test/mjsunit/asm/float64array-outofbounds.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM64 = new stdlib.Float64Array(heap);
+  function load(i) {
+    i = i|0;
+    i = +MEM64[i >> 3];
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = +v;
+    MEM64[i >> 3] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(8));
+
+m.store(0, 3.12);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 8 * 32 * 1024, i);
+}
+assertEquals(3.12, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(NaN, m.load(i * 8 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/float64array-store-div.js b/test/mjsunit/asm/float64array-store-div.js
new file mode 100644
index 0000000..10b0011
--- /dev/null
+++ b/test/mjsunit/asm/float64array-store-div.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM64 = new stdlib.Float64Array(heap);
+  function foo(i) {
+    MEM64[0] = (i >>> 0) / 2;
+    return MEM64[0];
+  }
+  return { foo: foo };
+}
+
+var foo = Module(this, {}, new ArrayBuffer(64 * 1024)).foo;
+assertEquals(0.5, foo(1));
diff --git a/test/mjsunit/asm/float64mul.js b/test/mjsunit/asm/float64mul.js
new file mode 100644
index 0000000..9cd9582
--- /dev/null
+++ b/test/mjsunit/asm/float64mul.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = +i;
+    return +(i * -1);
+  }
+  function f2(i) {
+    i = +i;
+    return +(-1 * i);
+  }
+  function f3(i) {
+    i = +i;
+    return +(-i);
+  }
+  return { f1: f1, f2: f2, f3: f3 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(64 * 1024));
+
+assertEquals(NaN, m.f1(NaN));
+assertEquals(NaN, m.f2(NaN));
+assertEquals(NaN, m.f3(NaN));
+assertEquals(Infinity, 1 / m.f1(-0));
+assertEquals(Infinity, 1 / m.f2(-0));
+assertEquals(Infinity, 1 / m.f3(-0));
+assertEquals(Infinity, m.f1(-Infinity));
+assertEquals(Infinity, m.f2(-Infinity));
+assertEquals(Infinity, m.f3(-Infinity));
+assertEquals(-Infinity, 1 / m.f1(0));
+assertEquals(-Infinity, 1 / m.f2(0));
+assertEquals(-Infinity, 1 / m.f3(0));
+assertEquals(-Infinity, m.f1(Infinity));
+assertEquals(-Infinity, m.f2(Infinity));
+assertEquals(-Infinity, m.f3(Infinity));
+for (var i = -2147483648; i < 2147483648; i += 3999777) {
+  assertEquals(-i, m.f1(i));
+  assertEquals(-i, m.f2(i));
+  assertEquals(-i, m.f3(i));
+}
diff --git a/test/mjsunit/asm/if-folding.js b/test/mjsunit/asm/if-folding.js
new file mode 100644
index 0000000..80070ee
--- /dev/null
+++ b/test/mjsunit/asm/if-folding.js
@@ -0,0 +1,100 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+
+  function if0() {
+    if (0) return 11;
+    return 12;
+  }
+
+  function if1() {
+    if (1) return 13;
+    return 14;
+  }
+
+  function if2() {
+    if (0) return 15;
+    else return 16;
+  }
+
+  function if3() {
+    if (1) return 17;
+    else return 18;
+  }
+
+  function if4() {
+    return 1 ? 19 : 20;
+  }
+
+  function if5() {
+    return 0 ? 21 : 22;
+  }
+
+  function if6() {
+    var x = 0 ? 23 : 24;
+    return x;
+  }
+
+  function if7() {
+    if (0) { var x = 0 ? 25 : 26; }
+    else { var x = 0 ? 27 : 28; }
+    return x;
+  }
+
+  function if8() {
+    if (0) {
+      if (0) { var x = 0 ? 29 : 30; }
+      else { var x = 0 ? 31 : 32; }
+    } else {
+      if (0) { var x = 0 ? 33 : 34; }
+      else { var x = 0 ? 35 : 36; }
+    }
+    return x;
+  }
+
+  return {if0: if0, if1: if1, if2: if2, if3: if3, if4: if4, if5: if5, if6: if6, if7: if7, if8: if8 };
+}
+
+var m = Module();
+assertEquals(12, m.if0());
+assertEquals(13, m.if1());
+assertEquals(16, m.if2());
+assertEquals(17, m.if3());
+assertEquals(19, m.if4());
+assertEquals(22, m.if5());
+assertEquals(24, m.if6());
+assertEquals(28, m.if7());
+assertEquals(36, m.if8());
+
+
+function Spec(a,b,c) {
+  "use asm";
+
+  var xx = a | 0;
+  var yy = b | 0;
+  var zz = c | 0;
+
+  function f() {
+    if (xx) {
+      if (yy) { var x = zz ? 29 : 30; }
+      else { var x = zz ? 31 : 32; }
+    } else {
+      if (yy) { var x = zz ? 33 : 34; }
+      else { var x = zz ? 35 : 36; }
+    }
+    return x;
+  }
+  return {f: f};
+}
+
+assertEquals(36, Spec(0,0,0).f());
+assertEquals(35, Spec(0,0,1).f());
+assertEquals(34, Spec(0,1,0).f());
+assertEquals(33, Spec(0,1,1).f());
+assertEquals(32, Spec(1,0,0).f());
+assertEquals(31, Spec(1,0,1).f());
+assertEquals(30, Spec(1,1,0).f());
+assertEquals(29, Spec(1,1,1).f());
diff --git a/test/mjsunit/asm/if-reduction.js b/test/mjsunit/asm/if-reduction.js
new file mode 100644
index 0000000..b0dcc13
--- /dev/null
+++ b/test/mjsunit/asm/if-reduction.js
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+
+  function if0() {
+    var x = 0 ? 11 : 12;
+    return (x == 11) | 0;
+  }
+
+  function if1() {
+    var x = 1 ? 13 : 14;
+    return (x == 13) | 0;
+  }
+
+  function if2() {
+    var x = 0 ? 15 : 16;
+    return (x != 15) | 0;
+  }
+
+  function if3() {
+    var x = 1 ? 17 : 18;
+    return (x != 17) | 0;
+  }
+
+  function if4() {
+    var x = 0 ? 19 : 20;
+    var y = (x == 19) ? 21 : 22;
+    return y;
+  }
+
+  function if5() {
+    var x = 1 ? 23 : 24;
+    var y = (x == 23) ? 25 : 26;
+    return y;
+  }
+
+  function if6() {
+    var x = 0 ? 27 : 28;
+    var y = (x == 27) ? 29 : 30;
+    var z = (y == 29) ? 31 : 32;
+    return z;
+  }
+
+  function if7() {
+    var x = 1 ? 33 : 34;
+    var y = (x == 33) ? 35 : 36;
+    var z = (y == 35) ? 37 : 38;
+    var w = (z == 37) ? 39 : 40;
+    return w;
+  }
+
+  function if8() {
+    if (0) {
+      var x = 0 ? 43 : 44;
+      var y = (x == 43) ? 45 : 46;
+      var z = (y == 45) ? 47 : 48;
+      var w = (z == 47) ? 49 : 50;
+    } else {
+      var x = 1 ? 53 : 54;
+      var y = (x == 53) ? 55 : 56;
+      var z = (y == 55) ? 57 : 58;
+      var w = (z == 57) ? 59 : 60;
+    }
+    return w;
+  }
+
+  return {if0: if0, if1: if1, if2: if2, if3: if3, if4: if4, if5: if5, if6: if6, if7: if7, if8: if8 };
+}
+
+var m = Module();
+assertEquals(0, m.if0());
+assertEquals(1, m.if1());
+assertEquals(1, m.if2());
+assertEquals(0, m.if3());
+assertEquals(22, m.if4());
+assertEquals(25, m.if5());
+assertEquals(32, m.if6());
+assertEquals(39, m.if7());
+assertEquals(59, m.if8());
+
+
+function Spec(a,b) {
+  "use asm";
+
+  var xx = a | 0;
+  var yy = b | 0;
+
+  function f() {
+    if (xx) {
+      var x = yy ? 43 : 44;
+      var y = (x == 43) ? 45 : 46;
+      var z = (y == 45) ? 47 : 48;
+      var w = (z == 47) ? 49 : 50;
+    } else {
+      var x = yy ? 53 : 54;
+      var y = (x == 53) ? 55 : 56;
+      var z = (y == 55) ? 57 : 58;
+      var w = (z == 57) ? 59 : 60;
+    }
+    return w;
+  }
+  return {f: f};
+}
+
+assertEquals(60, Spec(0,0).f());
+assertEquals(59, Spec(0,1).f());
+assertEquals(50, Spec(1,0).f());
+assertEquals(49, Spec(1,1).f());
diff --git a/test/mjsunit/asm/if-tonumber.js b/test/mjsunit/asm/if-tonumber.js
new file mode 100644
index 0000000..dd3f73b
--- /dev/null
+++ b/test/mjsunit/asm/if-tonumber.js
@@ -0,0 +1,31 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function foo(i) {
+    i = i|0;
+    if (i > 0) {
+      i = i == 1;
+    } else {
+      i = 1;
+    }
+    return i & 1|0;
+  }
+  return { foo: foo };
+}
+
+var m = Module(stdlib, foreign, buffer);
+
+assertEquals(1, m.foo(-1));
+assertEquals(1, m.foo(-0));
+assertEquals(1, m.foo(0));
+assertEquals(1, m.foo(1));
+assertEquals(0, m.foo(2));
+assertEquals(1, m.foo(true));
+assertEquals(1, m.foo(false));
diff --git a/test/mjsunit/asm/infinite-loops-taken.js b/test/mjsunit/asm/infinite-loops-taken.js
new file mode 100644
index 0000000..d136c62
--- /dev/null
+++ b/test/mjsunit/asm/infinite-loops-taken.js
@@ -0,0 +1,41 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var error = "error";
+function counter(x) {
+  return (function() { if (x-- == 0) throw error;});
+}
+
+function Module() {
+  "use asm";
+
+  function w0(f) {
+    while (1) f();
+    return 108;
+  }
+
+  function w1(f) {
+    if (1) while (1) f();
+    return 109;
+  }
+
+  function w2(f) {
+    if (1) while (1) f();
+    else while (1) f();
+    return 110;
+  }
+
+  function w3(f) {
+    if (0) while (1) f();
+    return 111;
+  }
+
+  return { w0: w0, w1: w1, w2: w2, w3: w3 };
+}
+
+var m = Module();
+assertThrows(function() { m.w0(counter(5)) }, error);
+assertThrows(function() { m.w1(counter(5)) }, error);
+assertThrows(function() { m.w2(counter(5)) }, error);
+assertEquals(111, m.w3(counter(5)));
diff --git a/test/mjsunit/asm/infinite-loops.js b/test/mjsunit/asm/infinite-loops.js
new file mode 100644
index 0000000..03f4f6b
--- /dev/null
+++ b/test/mjsunit/asm/infinite-loops.js
@@ -0,0 +1,53 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+
+  function w0(a) {
+    a = a | 0;
+    if (a) while (1);
+    return 42;
+  }
+
+  function w1(a) {
+    a = a | 0;
+    while (1) return 42;
+    return 106;
+  }
+
+  function d0(a) {
+    a = a | 0;
+    if (a) do ; while(1);
+    return 42;
+  }
+
+  function d1(a) {
+    a = a | 0;
+    do return 42; while(1);
+    return 107;
+  }
+
+  function f0(a) {
+    a = a | 0;
+    if (a) for (;;) ;
+    return 42;
+  }
+
+  function f1(a) {
+    a = a | 0;
+    for(;;) return 42;
+    return 108;
+  }
+
+  return { w0: w0, w1: w1, d0: d0, d1: d1, f0: f0, f1: f1 };
+}
+
+var m = Module();
+assertEquals(42, m.w0(0));
+assertEquals(42, m.w1(0));
+assertEquals(42, m.d0(0));
+assertEquals(42, m.d1(0));
+assertEquals(42, m.f0(0));
+assertEquals(42, m.f1(0));
diff --git a/test/mjsunit/asm/int16array-negative-offset.js b/test/mjsunit/asm/int16array-negative-offset.js
new file mode 100644
index 0000000..5d33115
--- /dev/null
+++ b/test/mjsunit/asm/int16array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM16 = new stdlib.Int16Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM16[i >> 1]|0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM16[i >> 1] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = MEM16[i + 8 >> 1]|0;
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM16[i + 8 >> 1] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(0, m.load(-8));
+assertEquals(0, m.load8(-16));
+m.store(0, 42);
+assertEquals(42, m.load8(-8));
+m.store8(-8, 99);
+assertEquals(99, m.load(0));
+assertEquals(99, m.load8(-8));
diff --git a/test/mjsunit/asm/int16array-outofbounds.js b/test/mjsunit/asm/int16array-outofbounds.js
new file mode 100644
index 0000000..7982c00
--- /dev/null
+++ b/test/mjsunit/asm/int16array-outofbounds.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM16 = new stdlib.Int16Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM16[i >> 1] | 0;
+    return i;
+  }
+  function loadm1() {
+    return MEM16[-1] | 0;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM16[i >> 1] = v;
+  }
+  function storem1(v) {
+    v = v|0;
+    MEM16[-1] = v;
+  }
+  return {load: load, loadm1: loadm1, store: store, storem1: storem1};
+}
+
+var m = Module(this, {}, new ArrayBuffer(2));
+
+m.store(-1000, 4);
+assertEquals(0, m.load(-1000));
+assertEquals(0, m.loadm1());
+m.storem1(1);
+assertEquals(0, m.loadm1());
+m.store(0, 32767);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 2 * 32 * 1024, i);
+}
+assertEquals(32767, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(0, m.load(i * 2 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/int32-div.js b/test/mjsunit/asm/int32-div.js
new file mode 100644
index 0000000..b4d0fef
--- /dev/null
+++ b/test/mjsunit/asm/int32-div.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i|0;
+    return i / 3 | 0;
+  }
+  function f2(i) {
+    i = i|0;
+    return i / 13 | 0;
+  }
+  function f3(i) {
+    i = i|0;
+    return i / 1024 | 0;
+  }
+  function f4(i) {
+    i = i|0;
+    return i / 3733331 | 0;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = -2147483648; i < 2147483648; i += 3999777) {
+  assertEquals(i / 3 | 0, m.f1(i));
+  assertEquals(i / 13 | 0, m.f2(i));
+  assertEquals(i / 1024 | 0, m.f3(i));
+  assertEquals(i / 3733331 | 0, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-mod.js b/test/mjsunit/asm/int32-mod.js
new file mode 100644
index 0000000..b3a7c0e
--- /dev/null
+++ b/test/mjsunit/asm/int32-mod.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i|0;
+    return i % 3;
+  }
+  function f2(i) {
+    i = i|0;
+    return i % 9;
+  }
+  function f3(i) {
+    i = i|0;
+    return i % 1024;
+  }
+  function f4(i) {
+    i = i|0;
+    return i % 3133335;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(i % 3, m.f1(i));
+  assertEquals(i % 9, m.f2(i));
+  assertEquals(i % 1024, m.f3(i));
+  assertEquals(i % 3133335, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-mul.js b/test/mjsunit/asm/int32-mul.js
new file mode 100644
index 0000000..c5af8a0
--- /dev/null
+++ b/test/mjsunit/asm/int32-mul.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i|0;
+    return i * 3 | 0;
+  }
+  function f2(i) {
+    i = i|0;
+    return i * 7 | 0;
+  }
+  function f3(i) {
+    i = i|0;
+    return i * 1024 | 0;
+  }
+  function f4(i) {
+    i = i|0;
+    return i * 3333339 | 0;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = -2147483648; i < 2147483648; i += 3999771) {
+  assertEquals(i * 3 | 0, m.f1(i));
+  assertEquals(i * 7 | 0, m.f2(i));
+  assertEquals(i * 1024 | 0, m.f3(i));
+  assertEquals(i * 3333339 | 0, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-tmod.js b/test/mjsunit/asm/int32-tmod.js
new file mode 100644
index 0000000..0e294d3
--- /dev/null
+++ b/test/mjsunit/asm/int32-tmod.js
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f0(i) {
+    i = i|0;
+    return i % 2 | 0;
+  }
+  function f1(i) {
+    i = i|0;
+    return i % 3 | 0;
+  }
+  function f2(i) {
+    i = i|0;
+    return i % 9 | 0;
+  }
+  function f3(i) {
+    i = i|0;
+    return i % 1024 | 0;
+  }
+  function f4(i) {
+    i = i|0;
+    return i % 3333339 | 0;
+  }
+  return { f0: f0, f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = -2147483648; i < 2147483648; i += 3999773) {
+  assertEquals(i % 2 | 0, m.f0(i));
+  assertEquals(i % 3 | 0, m.f1(i));
+  assertEquals(i % 9 | 0, m.f2(i));
+  assertEquals(i % 1024 | 0, m.f3(i));
+  assertEquals(i % 3333339 | 0, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-udiv.js b/test/mjsunit/asm/int32-udiv.js
new file mode 100644
index 0000000..9c67d6f
--- /dev/null
+++ b/test/mjsunit/asm/int32-udiv.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i>>>0;
+    return i / 3 | 0;
+  }
+  function f2(i) {
+    i = i>>>0;
+    return i / 17 | 0;
+  }
+  function f3(i) {
+    i = i>>>0;
+    return i / 1024 | 0;
+  }
+  function f4(i) {
+    i = i>>>0;
+    return i / 3343330 | 0;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = 0; i < 4294967296; i += 3999777) {
+  assertEquals(i / 3 | 0, m.f1(i));
+  assertEquals(i / 17 | 0, m.f2(i));
+  assertEquals(i / 1024 | 0, m.f3(i));
+  assertEquals(i / 3343330 | 0, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32-umod.js b/test/mjsunit/asm/int32-umod.js
new file mode 100644
index 0000000..2268966
--- /dev/null
+++ b/test/mjsunit/asm/int32-umod.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  function f1(i) {
+    i = i>>>0;
+    return i % 3;
+  }
+  function f2(i) {
+    i = i>>>0;
+    return i % 11;
+  }
+  function f3(i) {
+    i = i>>>0;
+    return i % 1024;
+  }
+  function f4(i) {
+    i = i>>>0;
+    return i % 3333337;
+  }
+  return { f1: f1, f2: f2, f3: f3, f4: f4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+for (var i = 0; i < 4294967296; i += 3999777) {
+  assertEquals(i % 3, m.f1(i));
+  assertEquals(i % 11, m.f2(i));
+  assertEquals(i % 1024, m.f3(i));
+  assertEquals(i % 3333337, m.f4(i));
+}
diff --git a/test/mjsunit/asm/int32array-constant-key.js b/test/mjsunit/asm/int32array-constant-key.js
new file mode 100644
index 0000000..bb5b650
--- /dev/null
+++ b/test/mjsunit/asm/int32array-constant-key.js
@@ -0,0 +1,62 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function loadm4194304() {
+    return MEM32[-4194304];
+  }
+  function loadm0() {
+    return MEM32[-0];
+  }
+  function load0() {
+    return MEM32[0];
+  }
+  function load4() {
+    return MEM32[4];
+  }
+  function storem4194304(v) {
+    MEM32[-4194304] = v;
+  }
+  function storem0(v) {
+    MEM32[-0] = v;
+  }
+  function store0(v) {
+    MEM32[0] = v;
+  }
+  function store4(v) {
+    MEM32[4] = v;
+  }
+  return { loadm4194304: loadm4194304, storem4194304: storem4194304,
+           loadm0: loadm0, storem0: storem0, load0: load0, store0: store0,
+           load4: load4, store4: store4 };
+}
+
+var m = Module(this, {}, new ArrayBuffer(4));
+
+assertEquals(undefined, m.loadm4194304());
+assertEquals(0, m.loadm0());
+assertEquals(0, m.load0());
+assertEquals(undefined, m.load4());
+m.storem4194304(123456789);
+assertEquals(undefined, m.loadm4194304());
+assertEquals(0, m.loadm0());
+assertEquals(0, m.load0());
+assertEquals(undefined, m.load4());
+m.storem0(987654321);
+assertEquals(undefined, m.loadm4194304());
+assertEquals(987654321, m.loadm0());
+assertEquals(987654321, m.load0());
+assertEquals(undefined, m.load4());
+m.store0(0x12345678);
+assertEquals(undefined, m.loadm4194304());
+assertEquals(0x12345678, m.loadm0());
+assertEquals(0x12345678, m.load0());
+assertEquals(undefined, m.load4());
+m.store4(43);
+assertEquals(undefined, m.loadm4194304());
+assertEquals(0x12345678, m.loadm0());
+assertEquals(0x12345678, m.load0());
+assertEquals(undefined, m.load4());
diff --git a/test/mjsunit/asm/int32array-negative-offset.js b/test/mjsunit/asm/int32array-negative-offset.js
new file mode 100644
index 0000000..d1a8efa
--- /dev/null
+++ b/test/mjsunit/asm/int32array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM32[i >> 2]|0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM32[i >> 2] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = MEM32[i + 8 >> 2]|0;
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM32[i + 8 >> 2] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(0, m.load(-8));
+assertEquals(0, m.load8(-16));
+m.store(0, 42);
+assertEquals(42, m.load8(-8));
+m.store8(-8, 99);
+assertEquals(99, m.load(0));
+assertEquals(99, m.load8(-8));
diff --git a/test/mjsunit/asm/int32array-outofbounds.js b/test/mjsunit/asm/int32array-outofbounds.js
new file mode 100644
index 0000000..ba7043d
--- /dev/null
+++ b/test/mjsunit/asm/int32array-outofbounds.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM32[i >> 2] | 0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM32[i >> 2] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(4));
+
+m.store(0, 0x12345678);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 4 * 32 * 1024, i);
+}
+assertEquals(0x12345678, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(0, m.load(i * 4 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/int32array-unaligned.js b/test/mjsunit/asm/int32array-unaligned.js
new file mode 100644
index 0000000..698ec5e
--- /dev/null
+++ b/test/mjsunit/asm/int32array-unaligned.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM32[i >> 2] | 0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM32[i >> 2] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1024));
+
+m.store(0, 0x12345678);
+m.store(4, -1);
+m.store(8, -1);
+for (var i = 0; i < 4; ++i) {
+  assertEquals(0x12345678, m.load(i));
+}
+for (var i = 4; i < 12; ++i) {
+  assertEquals(-1, m.load(i));
+}
+for (var j = 4; j < 8; ++j) {
+  m.store(j, 0x11223344);
+  for (var i = 0; i < 4; ++i) {
+    assertEquals(0x12345678, m.load(i));
+  }
+  for (var i = 4; i < 8; ++i) {
+    assertEquals(0x11223344, m.load(i));
+  }
+  for (var i = 8; i < 12; ++i) {
+    assertEquals(-1, m.load(i));
+  }
+}
diff --git a/test/mjsunit/asm/int32div.js b/test/mjsunit/asm/int32div.js
new file mode 100644
index 0000000..f5d2433
--- /dev/null
+++ b/test/mjsunit/asm/int32div.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Int32Div(divisor) {
+  var name = "div_";
+  if (divisor < 0) {
+    name += "minus_";
+  }
+  name += Math.abs(divisor);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend | 0) / " + divisor + ") | 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1, 0,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var div = Int32Div(divisor);
+  for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend / divisor) | 0, div(dividend));
+  }
+}
diff --git a/test/mjsunit/asm/int32mod-constant.js b/test/mjsunit/asm/int32mod-constant.js
new file mode 100644
index 0000000..fdbdc5d
--- /dev/null
+++ b/test/mjsunit/asm/int32mod-constant.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Int32Mod(divisor) {
+  var name = "mod_";
+  if (divisor < 0) {
+    name += "minus_";
+  }
+  name += Math.abs(divisor);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend | 0) % " + divisor + ") | 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1, 0,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var mod = Int32Mod(divisor);
+  for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend % divisor) | 0, mod(dividend));
+  }
+}
diff --git a/test/mjsunit/asm/int32mod.js b/test/mjsunit/asm/int32mod.js
new file mode 100644
index 0000000..22fa813
--- /dev/null
+++ b/test/mjsunit/asm/int32mod.js
@@ -0,0 +1,26 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+var mod = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function mod(dividend, divisor) {
+    dividend = dividend|0;
+    divisor = divisor|0;
+    return (dividend % divisor) | 0;
+  }
+  return { mod: mod };
+})(stdlib, foreign, heap).mod;
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1, 0,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend % divisor) | 0, mod(dividend, divisor));
+  }
+}
diff --git a/test/mjsunit/asm/int8array-negative-offset.js b/test/mjsunit/asm/int8array-negative-offset.js
new file mode 100644
index 0000000..47dbc1b
--- /dev/null
+++ b/test/mjsunit/asm/int8array-negative-offset.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var m = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM8 = new stdlib.Int8Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM8[i >> 0]|0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM8[i >> 0] = v;
+  }
+  function load8(i) {
+    i = i|0;
+    i = MEM8[i + 8 >> 0]|0;
+    return i;
+  }
+  function store8(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM8[i + 8 >> 0] = v;
+  }
+  return { load: load, store: store, load8: load8, store8: store8 };
+})(stdlib, foreign, buffer);
+
+assertEquals(0, m.load(-8));
+assertEquals(0, m.load8(-16));
+m.store(0, 42);
+assertEquals(42, m.load8(-8));
+m.store8(-8, 99);
+assertEquals(99, m.load(0));
+assertEquals(99, m.load8(-8));
diff --git a/test/mjsunit/asm/math-abs.js b/test/mjsunit/asm/math-abs.js
new file mode 100644
index 0000000..6387749
--- /dev/null
+++ b/test/mjsunit/asm/math-abs.js
@@ -0,0 +1,84 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib) {
+  "use asm";
+
+  var abs = stdlib.Math.abs;
+
+  // f: double -> double
+  function f(a) {
+    a = +a;
+    return +abs(a);
+  }
+
+  // g: unsigned -> double
+  function g(a) {
+    a = a>>>0;
+    return +abs(a);
+  }
+
+  // h: signed -> double
+  function h(a) {
+    a = a|0;
+    return +abs(a);
+  }
+
+  return { f: f, g: g, h: h };
+}
+
+var m = Module({ Math: Math });
+var f = m.f;
+var g = m.g;
+var h = m.h;
+
+assertTrue(isNaN(f(NaN)));
+assertTrue(isNaN(f(undefined)));
+assertTrue(isNaN(f(function() {})));
+
+assertEquals("Infinity", String(1/f(0)));
+assertEquals("Infinity", String(1/f(-0)));
+assertEquals("Infinity", String(f(Infinity)));
+assertEquals("Infinity", String(f(-Infinity)));
+
+assertEquals(0,   f(0));
+assertEquals(0.1, f(0.1));
+assertEquals(0.5, f(0.5));
+assertEquals(0.1, f(-0.1));
+assertEquals(0.5, f(-0.5));
+assertEquals(1,   f(1));
+assertEquals(1.1, f(1.1));
+assertEquals(1.5, f(1.5));
+assertEquals(1,   f(-1));
+assertEquals(1.1, f(-1.1));
+assertEquals(1.5, f(-1.5));
+
+assertEquals(0,          g(0));
+assertEquals(0,          g(0.1));
+assertEquals(0,          g(0.5));
+assertEquals(0,          g(-0.1));
+assertEquals(0,          g(-0.5));
+assertEquals(1,          g(1));
+assertEquals(1,          g(1.1));
+assertEquals(1,          g(1.5));
+assertEquals(4294967295, g(-1));
+assertEquals(4294967295, g(-1.1));
+assertEquals(4294967295, g(-1.5));
+
+assertEquals(0, h(0));
+assertEquals(0, h(0.1));
+assertEquals(0, h(0.5));
+assertEquals(0, h(-0.1));
+assertEquals(0, h(-0.5));
+assertEquals(1, h(1));
+assertEquals(1, h(1.1));
+assertEquals(1, h(1.5));
+assertEquals(1, h(-1));
+assertEquals(1, h(-1.1));
+assertEquals(1, h(-1.5));
+
+assertEquals(Number.MIN_VALUE, f(Number.MIN_VALUE));
+assertEquals(Number.MIN_VALUE, f(-Number.MIN_VALUE));
+assertEquals(Number.MAX_VALUE, f(Number.MAX_VALUE));
+assertEquals(Number.MAX_VALUE, f(-Number.MAX_VALUE));
diff --git a/test/mjsunit/asm/math-ceil.js b/test/mjsunit/asm/math-ceil.js
new file mode 100644
index 0000000..edb9493
--- /dev/null
+++ b/test/mjsunit/asm/math-ceil.js
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib) {
+  "use asm";
+
+  var ceil = stdlib.Math.ceil;
+
+  // f: double -> float
+  function f(a) {
+    a = +a;
+    return ceil(a);
+  }
+
+  return { f: f };
+}
+
+var f = Module({ Math: Math }).f;
+
+assertTrue(isNaN(f(NaN)));
+assertTrue(isNaN(f(undefined)));
+assertTrue(isNaN(f(function() {})));
+
+assertEquals(0,                   f(0));
+assertEquals(+0,                  f(+0));
+assertEquals(-0,                  f(-0));
+assertEquals(1,                   f(0.49999));
+assertEquals(1,                   f(0.6));
+assertEquals(1,                   f(0.5));
+assertEquals(-0,                  f(-0.1));
+assertEquals(-0,                  f(-0.5));
+assertEquals(-0,                  f(-0.6));
+assertEquals(-1,                  f(-1.6));
+assertEquals(-0,                  f(-0.50001));
+
+assertEquals("Infinity", String(f(Infinity)));
+assertEquals("-Infinity", String(f(-Infinity)));
diff --git a/test/mjsunit/asm/math-floor.js b/test/mjsunit/asm/math-floor.js
new file mode 100644
index 0000000..e8c3f34
--- /dev/null
+++ b/test/mjsunit/asm/math-floor.js
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib) {
+  "use asm";
+
+  var floor = stdlib.Math.floor;
+
+  // f: double -> float
+  function f(a) {
+    a = +a;
+    return floor(a);
+  }
+
+  return { f: f };
+}
+
+var f = Module({ Math: Math }).f;
+
+assertTrue(isNaN(f(NaN)));
+assertTrue(isNaN(f(undefined)));
+assertTrue(isNaN(f(function() {})));
+
+assertEquals(0,                   f(0));
+assertEquals(+0,                  f(+0));
+assertEquals(-0,                  f(-0));
+assertEquals(0,                   f(0.49999));
+assertEquals(+0,                  f(0.6));
+assertEquals(+0,                  f(0.5));
+assertEquals(-1,                  f(-0.1));
+assertEquals(-1,                  f(-0.5));
+assertEquals(-1,                  f(-0.6));
+assertEquals(-2,                  f(-1.6));
+assertEquals(-1,                  f(-0.50001));
+
+assertEquals("Infinity", String(f(Infinity)));
+assertEquals("-Infinity", String(f(-Infinity)));
diff --git a/test/mjsunit/asm/math-fround.js b/test/mjsunit/asm/math-fround.js
new file mode 100644
index 0000000..b1d37e9
--- /dev/null
+++ b/test/mjsunit/asm/math-fround.js
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib) {
+  "use asm";
+
+  var fround = stdlib.Math.fround;
+
+  // f: double -> float
+  function f(a) {
+    a = +a;
+    return fround(a);
+  }
+
+  return { f: f };
+}
+
+var f = Module({ Math: Math }).f;
+
+assertTrue(isNaN(f(NaN)));
+assertTrue(isNaN(f(undefined)));
+assertTrue(isNaN(f(function() {})));
+
+assertEquals("Infinity", String(1/f(0)));
+assertEquals("-Infinity", String(1/f(-0)));
+assertEquals("Infinity", String(f(Infinity)));
+assertEquals("-Infinity", String(f(-Infinity)));
+assertEquals("Infinity", String(f(1E200)));
+assertEquals("-Infinity", String(f(-1E200)));
+assertEquals("Infinity", String(1/f(1E-300)));
+assertEquals("-Infinity", String(1/f(-1E-300)));
+
+assertEquals(0,                  f(0));
+assertEquals(1,                  f(1));
+assertEquals(1.5,                f(1.5));
+assertEquals(1.3370000123977661, f(1.337));
+assertEquals(-4.300000190734863, f(-4.3));
diff --git a/test/mjsunit/asm/sign-extend.js b/test/mjsunit/asm/sign-extend.js
new file mode 100644
index 0000000..62d8d34
--- /dev/null
+++ b/test/mjsunit/asm/sign-extend.js
@@ -0,0 +1,45 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var sext8 = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function sext8(i) {
+    i = i|0;
+    i = i << 24 >> 24;
+    return i|0;
+  }
+  return { sext8: sext8 };
+})(stdlib, foreign, buffer).sext8;
+
+assertEquals(-128, sext8(128));
+assertEquals(-1, sext8(-1));
+assertEquals(-1, sext8(255));
+assertEquals(0, sext8(0));
+assertEquals(0, sext8(256));
+assertEquals(42, sext8(42));
+assertEquals(127, sext8(127));
+
+
+var sext16 = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function sext16(i) {
+    i = i|0;
+    i = i << 16 >> 16;
+    return i|0;
+  }
+  return { sext16: sext16 };
+})(stdlib, foreign, buffer).sext16;
+
+assertEquals(-32768, sext16(32768));
+assertEquals(-1, sext16(-1));
+assertEquals(-1, sext16(65535));
+assertEquals(0, sext16(0));
+assertEquals(0, sext16(65536));
+assertEquals(128, sext16(128));
+assertEquals(32767, sext16(32767));
diff --git a/test/mjsunit/asm/uint32-less-than-shift.js b/test/mjsunit/asm/uint32-less-than-shift.js
new file mode 100644
index 0000000..7384e21
--- /dev/null
+++ b/test/mjsunit/asm/uint32-less-than-shift.js
@@ -0,0 +1,61 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  'use asm';
+
+  function foo1(i1) {
+    i1 = i1 | 0;
+    var i10 = i1 >> 5;
+    if (i10 >>> 0 < 5) {
+      return 1;
+    } else {
+      return 0;
+    }
+    return 0;
+  }
+
+  function foo2(i1) {
+    i1 = i1 | 0;
+    var i10 = i1 / 32 | 0;
+    if (i10 >>> 0 < 5) {
+      return 1;
+    } else {
+      return 0;
+    }
+    return 0;
+  }
+
+  function foo3(i1) {
+    i1 = i1 | 0;
+    var i10 = (i1 + 32 | 0) / 32 | 0;
+    if (i10 >>> 0 < 5) {
+      return 1;
+    } else {
+      return 0;
+    }
+    return 0;
+  }
+  return {foo1: foo1, foo2: foo2, foo3: foo3};
+}
+
+var m = Module(this, {}, undefined);
+
+for (var i = 0; i < 4 * 32; i++) {
+  assertEquals(1, m.foo1(i));
+  assertEquals(1, m.foo2(i));
+  assertEquals(1, m.foo3(i));
+}
+
+for (var i = 4 * 32; i < 5 * 32; i++) {
+  assertEquals(1, m.foo1(i));
+  assertEquals(1, m.foo2(i));
+  assertEquals(0, m.foo3(i));
+}
+
+for (var i = 5 * 32; i < 10 * 32; i++) {
+  assertEquals(0, m.foo1(i));
+  assertEquals(0, m.foo2(i));
+  assertEquals(0, m.foo3(i));
+}
diff --git a/test/mjsunit/asm/uint32div.js b/test/mjsunit/asm/uint32div.js
new file mode 100644
index 0000000..dcbb73b
--- /dev/null
+++ b/test/mjsunit/asm/uint32div.js
@@ -0,0 +1,45 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Uint32Div(divisor) {
+  var name = "div_";
+  name += divisor;
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend >>> 0) / " + divisor + ") >>> 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var div = Uint32Div(divisor);
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend / divisor) >>> 0, div(dividend));
+  }
+}
+
+var div = (function(stdlib, foreign, heap) {
+  "use asm";
+  function div(dividend, divisor) {
+    return (dividend >>> 0) / (divisor >>> 0) | 0;
+  }
+  return {div: div};
+})(stdlib, foreign, heap).div;
+
+for (var i in divisors) {
+  var divisor =  divisors[i];
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend >>> 0) / (divisor >>> 0) | 0,
+                 div(dividend, divisor));
+  }
+}
diff --git a/test/mjsunit/asm/uint32mod-constant.js b/test/mjsunit/asm/uint32mod-constant.js
new file mode 100644
index 0000000..4ba94da
--- /dev/null
+++ b/test/mjsunit/asm/uint32mod-constant.js
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Uint32Mod(divisor) {
+  var name = "mod_";
+  name += divisor;
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend >>> 0) % " + divisor + ") >>> 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var mod = Uint32Mod(divisor);
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend % divisor) >>> 0, mod(dividend));
+  }
+}
diff --git a/test/mjsunit/asm/uint32mod.js b/test/mjsunit/asm/uint32mod.js
new file mode 100644
index 0000000..fa40507
--- /dev/null
+++ b/test/mjsunit/asm/uint32mod.js
@@ -0,0 +1,25 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+var mod = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function mod(dividend, divisor) {
+    dividend = dividend >>> 0;
+    divisor = divisor >>> 0;
+    return (dividend % divisor) >>> 0;
+  }
+  return { mod: mod };
+})(stdlib, foreign, heap).mod;
+
+var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend % divisor) >>> 0, mod(dividend, divisor));
+  }
+}
diff --git a/test/mjsunit/asm/uint8array-outofbounds.js b/test/mjsunit/asm/uint8array-outofbounds.js
new file mode 100644
index 0000000..179efa4
--- /dev/null
+++ b/test/mjsunit/asm/uint8array-outofbounds.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM8 = new stdlib.Uint8Array(heap);
+  function load(i) {
+    i = i|0;
+    i = MEM8[i] | 0;
+    return i;
+  }
+  function store(i, v) {
+    i = i|0;
+    v = v|0;
+    MEM8[i] = v;
+  }
+  return { load: load, store: store };
+}
+
+var m = Module(this, {}, new ArrayBuffer(1));
+
+m.store(0, 255);
+for (var i = 1; i < 64; ++i) {
+  m.store(i * 1 * 32 * 1024, i);
+}
+assertEquals(255, m.load(0));
+for (var i = 1; i < 64; ++i) {
+  assertEquals(0, m.load(i * 1 * 32 * 1024));
+}
diff --git a/test/mjsunit/asm/word32and.js b/test/mjsunit/asm/word32and.js
new file mode 100644
index 0000000..6c41f88
--- /dev/null
+++ b/test/mjsunit/asm/word32and.js
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Word32And(rhs) {
+  var name = "and_0x" + Number(rhs).toString(16);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(lhs) {\n"
+      + "  return (lhs | 0) & 0x" + Number(rhs).toString(16) + ";\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var masks = [0xffffffff, 0xf0f0f0f0, 0x80ffffff, 0x07f77f0f, 0xdeadbeef,
+             0x0fffff00, 0x0ff0, 0xff, 0x00];
+for (var i in masks) {
+  var rhs = masks[i];
+  var and = Word32And(rhs);
+  for (var lhs = -2147483648; lhs < 2147483648; lhs += 3999773) {
+    assertEquals(lhs & rhs, and(lhs));
+  }
+}
diff --git a/test/mjsunit/asm/word32ror.js b/test/mjsunit/asm/word32ror.js
new file mode 100644
index 0000000..9535bde
--- /dev/null
+++ b/test/mjsunit/asm/word32ror.js
@@ -0,0 +1,37 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+var rol = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function rol(x, y) {
+    x = x | 0;
+    y = y | 0;
+    return (x << y) | (x >>> (32 - y));
+  }
+  return { rol: rol };
+})(stdlib, foreign, heap).rol;
+
+assertEquals(10, rol(10, 0));
+assertEquals(2, rol(1, 1));
+assertEquals(0x40000000, rol(1, 30));
+assertEquals(-0x80000000, rol(1, 31));
+
+var ror = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function ror(x, y) {
+    x = x | 0;
+    y = y | 0;
+    return (x << (32 - y)) | (x >>> y);
+  }
+  return { ror: ror };
+})(stdlib, foreign, heap).ror;
+
+assertEquals(10, ror(10, 0));
+assertEquals(-0x80000000, ror(1, 1));
+assertEquals(0x40000000, ror(1, 2));
+assertEquals(2, ror(1, 31));
diff --git a/test/mjsunit/asm/zero-extend.js b/test/mjsunit/asm/zero-extend.js
new file mode 100644
index 0000000..a1f9da6
--- /dev/null
+++ b/test/mjsunit/asm/zero-extend.js
@@ -0,0 +1,37 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+
+var zext8 = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function zext8(i) {
+    i = i|0;
+    return i & 0xff;
+  }
+  return { zext8: zext8 };
+})(stdlib, foreign, buffer).zext8;
+
+assertEquals(0, zext8(0));
+assertEquals(0, zext8(0x100));
+assertEquals(0xff, zext8(-1));
+assertEquals(0xff, zext8(0xff));
+
+
+var zext16 = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function zext16(i) {
+    i = i|0;
+    return i & 0xffff;
+  }
+  return { zext16: zext16 };
+})(stdlib, foreign, buffer).zext16;
+
+assertEquals(0, zext16(0));
+assertEquals(0, zext16(0x10000));
+assertEquals(0xffff, zext16(-1));
+assertEquals(0xffff, zext16(0xffff));
diff --git a/test/mjsunit/big-array-literal.js b/test/mjsunit/big-array-literal.js
index 13f91f8..401807f 100644
--- a/test/mjsunit/big-array-literal.js
+++ b/test/mjsunit/big-array-literal.js
@@ -27,6 +27,7 @@
 
 // On MacOS X 10.7.5, this test needs a stack size of at least 788 kBytes.
 // Flags: --stack-size=800
+// Flags: --turbo-deoptimization
 
 // Test that we can make large object literals that work.
 // Also test that we can attempt to make even larger object literals without
diff --git a/test/mjsunit/boolean.js b/test/mjsunit/boolean.js
index d955855..9b9edd2 100644
--- a/test/mjsunit/boolean.js
+++ b/test/mjsunit/boolean.js
@@ -72,3 +72,10 @@
 assertEquals('foo', o.p || (o.p == 0));
 assertEquals('foo', o.p || (o.p == null));
 assertEquals('foo', o.p || (o.p == o.p));
+
+// JSToBoolean(x:string)
+function f(x) { return !!("" + x); }
+assertEquals(false, f(""));
+assertEquals(true, f("narf"));
+assertEquals(true, f(12345678));
+assertEquals(true, f(undefined));
diff --git a/test/mjsunit/compiler/deopt-inlined-from-call.js b/test/mjsunit/compiler/deopt-inlined-from-call.js
new file mode 100644
index 0000000..24d7354
--- /dev/null
+++ b/test/mjsunit/compiler/deopt-inlined-from-call.js
@@ -0,0 +1,154 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//   * Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above
+//   copyright notice, this list of conditions and the following
+//   disclaimer in the documentation and/or other materials provided
+//   with the distribution.
+//   * Neither the name of Google Inc. nor the names of its
+//   contributors may be used to endorse or promote products derived
+//   from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noalways-opt
+
+var global = this;
+
+Array.prototype.f = function() {
+  return 0;
+};
+
+(function() {
+  var called = 0;
+
+  function g(x, y, called) {
+    return called + 1;
+  }
+
+  function f(deopt, called) {
+    return g([].f.call({}), deopt + 1, called);
+  }
+
+  called = f(0, called);
+  called = f(0, called);
+  %OptimizeFunctionOnNextCall(f);
+  called = f(0, called);
+  assertOptimized(f);
+  called = f({}, called);
+  assertUnoptimized(f);
+  assertEquals(4, called);
+})();
+
+(function() {
+  // The array built-ins are only inlined if the receiver is a
+  // HConstant, this seems to require a *unique* global identifier
+  // each time.
+  global.a1 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].pop.call(a1) + b.value;
+  }
+
+  assertEquals(7, f(obj));
+  assertEquals(6, f(obj));
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals(5, f(obj));
+  assertOptimized(f);
+  assertEquals(4, f({d: 0, value: 3}));
+  assertUnoptimized(f);
+  assertEquals(0, a1.length);
+})();
+
+
+(function() {
+  global.a2 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].shift.call(a2) + b.value;
+  }
+
+  assertEquals(4, f(obj));
+  assertEquals(5, f(obj));
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals(6, f(obj));
+  assertOptimized(f);
+  assertEquals(7, f({d: 0, value: 3}));
+  assertUnoptimized(f);
+  assertEquals(0, a2.length);
+})();
+
+(function() {
+  global.a3 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].push.call(a3, b.value);
+  }
+
+  assertEquals(5, f(obj));
+  assertEquals(6, f(obj));
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals(7, f(obj));
+  assertOptimized(f);
+  assertEquals(8, f({d: 0, value: 3}));
+  assertUnoptimized(f);
+  assertEquals(8, a3.length);
+  assertEquals(3, a3[7]);
+})();
+
+(function() {
+  global.a4 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].indexOf.call(a4, b.value);
+  }
+
+  f(obj);
+  f(obj);
+  %OptimizeFunctionOnNextCall(f);
+  var index1 = f(obj);
+  assertOptimized(f);
+  var index2 = f({d: 0, value: 3});
+  assertUnoptimized(f);
+
+  assertEquals(2, index1);
+  assertEquals(index1, index2);
+})();
+
+(function() {
+  global.a5 = [1,2,3,4];
+  var obj = {value: 3};
+
+  function f(b) {
+    return [].lastIndexOf.call(a5, b.value);
+  }
+
+  f(obj);
+  f(obj);
+  %OptimizeFunctionOnNextCall(f);
+  var index1 = f(obj);
+  assertOptimized(f);
+  var index2 = f({d: 0, value: 3});
+  assertUnoptimized(f);
+
+  assertEquals(2, index1);
+  assertEquals(index1, index2);
+})();
diff --git a/test/mjsunit/compiler/division-by-constant.js b/test/mjsunit/compiler/division-by-constant.js
index 0778e95..d3f3ac3 100644
--- a/test/mjsunit/compiler/division-by-constant.js
+++ b/test/mjsunit/compiler/division-by-constant.js
@@ -101,6 +101,7 @@
 
 // -----------------------------------------------------------------------------
 
+
 function TestDivisionLike(ref, construct, values, divisor) {
   // Define the function to test.
   var OptFun = new Function("dividend", construct(divisor));
@@ -111,12 +112,14 @@
   %OptimizeFunctionOnNextCall(OptFun);
   OptFun(13);
 
-  // Check results.
-  values.forEach(function(dividend) {
+function dude(dividend) {
     // Avoid deopt caused by overflow, we do not want to test this here.
     if (dividend === -2147483648 && divisor === -1) return;
     assertEquals(ref(dividend, divisor), OptFun(dividend));
-  });
+  }
+
+  // Check results.
+  values.forEach(dude);
 }
 
 function Test(ref, construct) {
diff --git a/test/mjsunit/compiler/inlined-call-mapcheck.js b/test/mjsunit/compiler/inlined-call-mapcheck.js
new file mode 100644
index 0000000..84ec1d2
--- /dev/null
+++ b/test/mjsunit/compiler/inlined-call-mapcheck.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//   * Redistributions of source code must retain the above copyright
+//     notice, this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above
+//     copyright notice, this list of conditions and the following
+//     disclaimer in the documentation and/or other materials provided
+//     with the distribution.
+//   * Neither the name of Google Inc. nor the names of its
+//     contributors may be used to endorse or promote products derived
+//     from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noalways-opt
+
+(function() {
+    function f(x) {
+        for (i = 0; i < 1; i++) {
+            x.call(this);
+        }
+    }
+
+    function g() {}
+
+    f(g);
+    f(g);
+    %OptimizeFunctionOnNextCall(f);
+    assertThrows(function() { f('whatever') }, TypeError);
+})();
diff --git a/test/mjsunit/compiler/inlined-call.js b/test/mjsunit/compiler/inlined-call.js
new file mode 100644
index 0000000..dfa1675
--- /dev/null
+++ b/test/mjsunit/compiler/inlined-call.js
@@ -0,0 +1,190 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//   * Redistributions of source code must retain the above copyright
+//     notice, this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above
+//     copyright notice, this list of conditions and the following
+//     disclaimer in the documentation and/or other materials provided
+//     with the distribution.
+//   * Neither the name of Google Inc. nor the names of its
+//     contributors may be used to endorse or promote products derived
+//     from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noalways-opt
+
+var global = this;
+
+// For the HConstant
+Array.prototype.fun = function() {
+  funRecv = this;
+  called++;
+  assertEquals(0, arguments.length);
+};
+
+Array.prototype.funStrict = function() {
+  "use strict";
+  funStrictRecv = this;
+  called++;
+  assertEquals(0, arguments.length);
+};
+
+Array.prototype.manyArgs = function() {
+  "use strict";
+  assertEquals(5, arguments.length);
+  assertEquals(0, this);
+  assertEquals(5, arguments[4]);
+  called++;
+}
+
+Array.prototype.manyArgsSloppy = function() {
+  assertEquals(global, this);
+  assertEquals(5, arguments.length);
+  assertEquals(5, arguments[4]);
+  called++;
+}
+
+var array = [];
+for (var i = 0; i < 100; ++i) {
+  array[i] = i;
+}
+
+var copy = array.slice();
+
+function unshiftsArray(num) {
+  [].unshift.call(array, num);
+}
+
+unshiftsArray(50);
+unshiftsArray(60);
+%OptimizeFunctionOnNextCall(unshiftsArray);
+unshiftsArray(80);
+unshiftsArray(50);
+unshiftsArray(60);
+
+copy.unshift(50);
+copy.unshift(60);
+copy.unshift(80);
+copy.unshift(50);
+copy.unshift(60);
+
+assertOptimized(unshiftsArray);
+assertArrayEquals(array, copy);
+
+
+var called = 0;
+var funRecv;
+
+function callNoArgs() {
+  [].fun.call();
+}
+
+callNoArgs();
+callNoArgs();
+assertEquals(this, funRecv);
+%OptimizeFunctionOnNextCall(callNoArgs);
+callNoArgs();
+assertEquals(this, funRecv);
+assertEquals(3, called);
+assertOptimized(callNoArgs);
+
+var funStrictRecv;
+called = 0;
+
+function callStrictNoArgs() {
+  [].funStrict.call();
+}
+
+callStrictNoArgs();
+callStrictNoArgs();
+assertEquals(undefined, funStrictRecv);
+%OptimizeFunctionOnNextCall(callStrictNoArgs);
+callStrictNoArgs();
+assertEquals(undefined, funStrictRecv);
+assertEquals(3, called);
+assertOptimized(callStrictNoArgs);
+
+called = 0;
+
+
+function callManyArgs() {
+  [].manyArgs.call(0, 1, 2, 3, 4, 5);
+}
+
+callManyArgs();
+callManyArgs();
+%OptimizeFunctionOnNextCall(callManyArgs);
+callManyArgs();
+assertOptimized(callManyArgs);
+assertEquals(called, 3);
+
+called = 0;
+
+
+function callManyArgsSloppy() {
+  [].manyArgsSloppy.call(null, 1, 2, 3, 4, 5);
+}
+
+callManyArgsSloppy();
+callManyArgsSloppy();
+%OptimizeFunctionOnNextCall(callManyArgsSloppy);
+callManyArgsSloppy();
+assertOptimized(callManyArgsSloppy);
+assertEquals(called, 3);
+
+var str = "hello";
+var code = str.charCodeAt(3);
+called = 0;
+function callBuiltinIndirectly() {
+  called++;
+  return "".charCodeAt.call(str, 3);
+}
+
+callBuiltinIndirectly();
+callBuiltinIndirectly();
+%OptimizeFunctionOnNextCall(callBuiltinIndirectly);
+assertEquals(code, callBuiltinIndirectly());
+assertOptimized(callBuiltinIndirectly);
+assertEquals(3, called);
+
+this.array = [1,2,3,4,5,6,7,8,9];
+var copy = this.array.slice();
+called = 0;
+
+function callInlineableBuiltinIndirectlyWhileInlined() {
+    called++;
+    return [].push.apply(array, arguments);
+}
+
+function callInlined(num) {
+  return callInlineableBuiltinIndirectlyWhileInlined(num);
+}
+
+callInlineableBuiltinIndirectlyWhileInlined(1);
+callInlineableBuiltinIndirectlyWhileInlined(2);
+%OptimizeFunctionOnNextCall(callInlineableBuiltinIndirectlyWhileInlined);
+callInlineableBuiltinIndirectlyWhileInlined(3);
+assertOptimized(callInlineableBuiltinIndirectlyWhileInlined);
+
+callInlined(1);
+callInlined(2);
+%OptimizeFunctionOnNextCall(callInlined);
+callInlined(3);
+copy.push(1, 2, 3, 1, 2, 3);
+assertOptimized(callInlined);
+assertArrayEquals(copy, this.array);
+assertEquals(6, called);
diff --git a/test/mjsunit/compiler/literals.js b/test/mjsunit/compiler/literals.js
index 8607cd9..3bda9fc 100644
--- a/test/mjsunit/compiler/literals.js
+++ b/test/mjsunit/compiler/literals.js
@@ -38,8 +38,8 @@
 // "/" comes just before "0".
 assertThrows('"\\x1/"');
 assertThrows('"\\u111/"');
-assertEquals("\\x1/", RegExp("\\x1/").source);
-assertEquals("\\u111/", RegExp("\\u111/").source);
+assertEquals("\\x1\\/", RegExp("\\x1/").source);
+assertEquals("\\u111\\/", RegExp("\\u111/").source);
 
 // ":" comes just after "9".
 assertThrows('"\\x1:"');
diff --git a/test/mjsunit/compiler/regress-3786.js b/test/mjsunit/compiler/regress-3786.js
new file mode 100644
index 0000000..d30ac0e
--- /dev/null
+++ b/test/mjsunit/compiler/regress-3786.js
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var f = stdlib.Math.cos;
+  function foo() {
+    return f(48,48,48,59,32,102,111,110,116,45,119,101,105,103,104,116,58,98,111,108,100,59,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,32,99,111,108,111,114,61,34,35,70,70,48,48,48,48,34,62,70,79,82,69,88,47,80,65,82,38,35,51,48,52,59,60,119,98,114,32,47,62,84,69,32,38,35,51,48,52,59,38,35,51,53,48,59,76,69,77,76,69,82,38,35,51,48,52,59,60,47,102,111,110,116,62,60,47,115,112,97,110,62,60,47,116,100,62,10,60,47,116,114,62,60,116,114,62,10,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,62,60,115,112,97,110,32,105,100,61,34,97,99,95,100,101,115,99,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,49,112,120,59,32,99,111,108,111,114,58,35,48,48,48,48,48,48,59,32,102,111,110,116,45,102,97,109,105,108,121,58,65,114,105,97,108,44,32,72,101,108,118,101,116,105,99,97,44,32,115,97,110,115,45,115,101,114,105,102,44,86,101,114,100,97,110,97,34,62,38,112,111,117,110,100,59,47,36,32,50,32,112,105,112,44,32,89,84,76,32,49,50,32,112,105,112,44,65,108,116,38,35,51,48,53,59,110,32,51,32,99,101,110,116,46,32,83,97,98,105,116,32,83,112,114,101,97,100,45,84,38,117,117,109,108,59,114,60,119,98,114,32,47,62,107,32,66,97,110,107,97,115,38,35,51,48,53,59,32,65,86,65,78,84,65,74,73,60,47,102,111,110,116,62,60,47,115,112,97,110,62,60,47,116,100,62,10,60,47,116,114,62,60,116,114,62,10,60,116,100,32,97,108,105,103,110,61,34,108,101,102,116,34,62,60,100,105,118,32,105,100,61,34,97,99,95,117,114,108,34,62,60,102,111,110,116,32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,48,112,120,59,32,99,111,108,111,114,58,35,70,70,54,54,57,57,59,32,102,111,110,116,45,102,97114,105,97);
+  }
+  return { foo: foo };
+})(this, {}).foo();
diff --git a/test/mjsunit/compiler/regress-439743.js b/test/mjsunit/compiler/regress-439743.js
new file mode 100644
index 0000000..288e2a4
--- /dev/null
+++ b/test/mjsunit/compiler/regress-439743.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function module(stdlib, foreign, heap) {
+    "use asm";
+    var MEM32 = new stdlib.Int32Array(heap);
+    function foo(i) {
+      i = i|0;
+      MEM32[0] = i;
+      return MEM32[i + 4 >> 2]|0;
+    }
+    return { foo: foo };
+}
+
+var foo = module(this, {}, new ArrayBuffer(64*1024)).foo;
+assertEquals(-4, foo(-4));
diff --git a/test/mjsunit/compiler/regress-443744.js b/test/mjsunit/compiler/regress-443744.js
new file mode 100644
index 0000000..5e7f3bc
--- /dev/null
+++ b/test/mjsunit/compiler/regress-443744.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var m = (function(stdlib, foreign, heap) {
+  "use asm";
+  var MEM = new stdlib.Uint8Array(heap);
+  function f(x) {
+    x = x | 0;
+    MEM[x] = 0;
+  }
+  return {f: f};
+})(this, {}, new ArrayBuffer(1));
+m.f(-926416896 * 32 * 1024);
diff --git a/test/mjsunit/compiler/regress-444508.js b/test/mjsunit/compiler/regress-444508.js
new file mode 100644
index 0000000..e7d51ae
--- /dev/null
+++ b/test/mjsunit/compiler/regress-444508.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function Module(stdlib, foreign, heap) {
+  "use asm";
+  // This is not valid asm.js, but should nevertheless work.
+  var MEM = new Uint8ClampedArray(heap);
+  function foo(i) { MEM[0] = 1; }
+  return {foo: foo};
+})(this, {}, new ArrayBuffer(64 * 1024)).foo();
diff --git a/test/mjsunit/compiler/regress-444695.js b/test/mjsunit/compiler/regress-444695.js
new file mode 100644
index 0000000..168ae25
--- /dev/null
+++ b/test/mjsunit/compiler/regress-444695.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function(stdlib, foreign, heap) {
+  "use asm";
+  var MEM = new stdlib.Uint8Array(heap);
+  function foo(x) { MEM[x | 0] *= 0; }
+  return {foo: foo};
+})(this, {}, new ArrayBuffer(1)).foo;
+foo(-926416896 * 8 * 1024);
diff --git a/test/mjsunit/compiler/regress-445267.js b/test/mjsunit/compiler/regress-445267.js
new file mode 100644
index 0000000..465168b
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445267.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM16 = new stdlib.Int16Array(heap);
+  function foo(i) {
+    i = i|0;
+    i = MEM16[i + 2147483650 >> 1]|0;
+    return i;
+  }
+  return { foo: foo };
+})(this, {}, new ArrayBuffer(64 * 1024)).foo;
+
+foo(0);
diff --git a/test/mjsunit/compiler/regress-445732.js b/test/mjsunit/compiler/regress-445732.js
new file mode 100644
index 0000000..199a29a
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445732.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --turbo-asm
+
+"use asm";
+
+%NeverOptimizeFunction(f);
+function f() { }
+f();
diff --git a/test/mjsunit/compiler/regress-445858.js b/test/mjsunit/compiler/regress-445858.js
new file mode 100644
index 0000000..b2214ea
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445858.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM = new stdlib.Int8Array(heap);
+  function foo(i) {
+    i = i|0;
+    i[0] = i;
+    return MEM[i + 1 >> 0]|0;
+  }
+  return { foo: foo };
+})(this, {}, new ArrayBuffer(64 * 1024)).foo;
+foo(-1);
diff --git a/test/mjsunit/compiler/regress-445859.js b/test/mjsunit/compiler/regress-445859.js
new file mode 100644
index 0000000..256af3e
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445859.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var foo = (function Module(global, env, buffer) {
+  "use asm";
+  var i8 = new global.Int8Array(buffer);
+  function foo() { i8[0] += 4294967295; }
+  return { foo: foo };
+})(this, {}, new ArrayBuffer(64 * 1024)).foo;
+foo();
diff --git a/test/mjsunit/compiler/regress-445876.js b/test/mjsunit/compiler/regress-445876.js
new file mode 100644
index 0000000..30e10e5
--- /dev/null
+++ b/test/mjsunit/compiler/regress-445876.js
@@ -0,0 +1,12 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(x) {
+  while (1) { s++; }
+  while (x) { s++; }
+}
+
+assertThrows(function () { f(1); });
diff --git a/test/mjsunit/compiler/regress-446156.js b/test/mjsunit/compiler/regress-446156.js
new file mode 100644
index 0000000..f3cd2dd
--- /dev/null
+++ b/test/mjsunit/compiler/regress-446156.js
@@ -0,0 +1,11 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function Module(stdlib, foreign, heap) {
+  "use asm";
+  // This is not valid asm.js, but should nevertheless work.
+  var MEM = new Uint8ClampedArray(heap);
+  function foo(  )  { MEM[0] ^=  1; }
+  return {foo: foo};
+})(this, {}, new ArrayBuffer(  ) ).foo();
diff --git a/test/mjsunit/compiler/regress-446778.js b/test/mjsunit/compiler/regress-446778.js
new file mode 100644
index 0000000..a7fa3fd
--- /dev/null
+++ b/test/mjsunit/compiler/regress-446778.js
@@ -0,0 +1,17 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module() {
+  "use asm";
+  function f() {
+   var i = (140737463189505);
+   do {
+    i = i + i | 0;
+    x = undefined + i | 0;
+   } while (!i);
+  }
+  return { f: f };
+}
+
+Module().f();
diff --git a/test/mjsunit/compiler/regress-bit-number-constant.js b/test/mjsunit/compiler/regress-bit-number-constant.js
new file mode 100644
index 0000000..d36fe30
--- /dev/null
+++ b/test/mjsunit/compiler/regress-bit-number-constant.js
@@ -0,0 +1,17 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = this;
+var buffer = new ArrayBuffer(64 * 1024);
+var foreign = {}
+
+var foo = (function Module(stdlib, foreign, heap) {
+  "use asm";
+  function foo(i) {
+    return !(i ? 1 : false);
+  }
+  return {foo:foo};
+})(stdlib, foreign, buffer).foo;
+
+assertFalse(foo(1));
diff --git a/test/mjsunit/compiler/regress-int32array-outofbounds-nan.js b/test/mjsunit/compiler/regress-int32array-outofbounds-nan.js
new file mode 100644
index 0000000..2eba2a4
--- /dev/null
+++ b/test/mjsunit/compiler/regress-int32array-outofbounds-nan.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, heap) {
+  "use asm";
+  var MEM32 = new stdlib.Int32Array(heap);
+  function foo(i) {
+    i = i|0;
+    return +MEM32[i >> 2];
+  }
+  return {foo: foo};
+}
+
+var foo = Module(this, {}, new ArrayBuffer(4)).foo;
+assertEquals(NaN, foo(-4));
+assertEquals(NaN, foo(4));
diff --git a/test/mjsunit/compiler/regress-ntl-effect.js b/test/mjsunit/compiler/regress-ntl-effect.js
new file mode 100644
index 0000000..708fe32
--- /dev/null
+++ b/test/mjsunit/compiler/regress-ntl-effect.js
@@ -0,0 +1,16 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function g() {
+  throw 0;
+}
+
+function f() {
+  g();
+  while (1) {}
+}
+
+assertThrows(function () { f(); });
diff --git a/test/mjsunit/compiler/regress-register-allocator.js b/test/mjsunit/compiler/regress-register-allocator.js
new file mode 100644
index 0000000..08877ee
--- /dev/null
+++ b/test/mjsunit/compiler/regress-register-allocator.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function Module(stdlib, foreign, buffer) {
+  "use asm";
+  var HEAP32 = new stdlib.Int32Array(buffer);
+  function g(a) {
+    HEAP32[a] = 9982 * 100;
+    return a;
+  }
+  function f(i1) {
+    i1 = i1 | 0;
+    var i2 = HEAP32[i1 >> 2] | 0;
+    g(i1);
+    L2909: {
+      L2: {
+        if (0) {
+          if (0) break L2;
+          g(i2);
+          break L2909;
+        }
+      }
+      var r = (HEAP32[1] | 0) / 100 | 0;
+      g(r);
+      return r;
+    }
+  }
+  return {f: f};
+}
+
+var f = Module(this, {}, new ArrayBuffer(64 * 1024)).f;
+assertEquals(9982, f(1));
diff --git a/test/mjsunit/compiler/regress-register-allocator2.js b/test/mjsunit/compiler/regress-register-allocator2.js
new file mode 100644
index 0000000..06e0c49
--- /dev/null
+++ b/test/mjsunit/compiler/regress-register-allocator2.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f() {
+  var x = 0;
+  var y = 0;
+  x ^= undefined;
+  assertEquals(x /= 1);
+  assertEquals(NaN, y %= 1);
+  assertEquals(y = 1);
+  f();
+  y = -2;
+  assertEquals(x >>= 1);
+  assertEquals(0, ((y+(y+(y+((y^(x%5))+y)))+(y+y))>>y)+y);
+}
+try { f(); } catch (e) {}
diff --git a/test/mjsunit/compiler/regress-register-allocator3.js b/test/mjsunit/compiler/regress-register-allocator3.js
new file mode 100644
index 0000000..f412c57
--- /dev/null
+++ b/test/mjsunit/compiler/regress-register-allocator3.js
@@ -0,0 +1,46 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+function Module() {
+  "use asm";
+  function f() {
+   var $0 = 0, $25 = 0, $i$014$i = 0, $sum$013$i = 0, $v_0$01$i = 0, $v_1$02$i = 0, $v_10$011$i = 0, $v_11$012$i = 0, $v_2$03$i = 0, $v_3$04$i = 0, $v_4$05$i = 0, $v_5$06$i = 0, $v_6$07$i = 0, $v_7$08$i = 0, $v_8$09$i = 0, $v_9$010$i = 0;
+   $i$014$i = 0;
+   $sum$013$i = 0;
+   $v_0$01$i = 8;
+   $v_1$02$i = 9;
+   $v_10$011$i = 18;
+   $v_11$012$i = 19;
+   $v_2$03$i = 10;
+   $v_3$04$i = 11;
+   $v_4$05$i = 12;
+   $v_5$06$i = 13;
+   $v_6$07$i = 14;
+   $v_7$08$i = 15;
+   $v_8$09$i = 16;
+   $v_9$010$i = 17;
+   do {
+    $v_0$01$i = $v_3$04$i + $v_9$010$i + $v_0$01$i | 0;
+    $v_1$02$i = $v_4$05$i + $v_10$011$i + $v_1$02$i | 0;
+    $v_2$03$i = $v_5$06$i + $v_11$012$i + $v_2$03$i | 0;
+    $v_3$04$i = $v_3$04$i + $v_6$07$i + $v_0$01$i | 0;
+    $v_4$05$i = $v_4$05$i + $v_7$08$i + $v_1$02$i | 0;
+    $v_5$06$i = $v_5$06$i + $v_8$09$i + $v_2$03$i | 0;
+    $v_6$07$i = $v_6$07$i + $v_9$010$i + $v_3$04$i | 0;
+    $v_7$08$i = $v_7$08$i + $v_10$011$i + $v_4$05$i | 0;
+    $v_8$09$i = $v_8$09$i + $v_11$012$i + $v_5$06$i | 0;
+    $v_9$010$i = $v_0$01$i + $v_9$010$i + $v_6$07$i | 0;
+    $v_10$011$i = $v_1$02$i + $v_10$011$i + $v_7$08$i | 0;
+    $v_11$012$i = $v_2$03$i + $v_11$012$i + $v_8$09$i | 0;
+    $25 = $v_0$01$i + $v_1$02$i | 0;
+    $sum$013$i = $v_2$03$i + $sum$013$i + $v_5$06$i + $v_4$05$i + $v_8$09$i + $v_3$04$i + $25 + $v_7$08$i + $v_11$012$i + $v_6$07$i + $v_10$011$i + $v_9$010$i | 0;
+    $i$014$i = $i$014$i + 1 | 0;
+   } while (($i$014$i | 0) <= 0);
+   return $sum$013$i - ($v_5$06$i + $v_2$03$i + $v_4$05$i + $v_8$09$i + $25 + $v_3$04$i + $v_7$08$i + $v_11$012$i + $v_6$07$i + $v_10$011$i + $v_9$010$i);
+  }
+  return { f: f };
+}
+
+Module().f();
diff --git a/test/mjsunit/compiler/regress-uint8-deopt.js b/test/mjsunit/compiler/regress-uint8-deopt.js
new file mode 100644
index 0000000..ba2823f
--- /dev/null
+++ b/test/mjsunit/compiler/regress-uint8-deopt.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --turbo-asm --turbo-deoptimization --allow-natives-syntax
+
+function Module(heap) {
+  "use asm";
+  var a = new Uint8Array(heap);
+  function f() {
+    var x = a[0] | 0;
+    %DeoptimizeFunction(f);
+    return x;
+  }
+  return f;
+}
+assertEquals(0, Module(new ArrayBuffer(1))());
diff --git a/test/mjsunit/compiler/shift-shr.js b/test/mjsunit/compiler/shift-shr.js
index a300b2a..52cd370 100644
--- a/test/mjsunit/compiler/shift-shr.js
+++ b/test/mjsunit/compiler/shift-shr.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --allow-natives-syntax --noopt-safe-uint32-operations
+// Flags: --allow-natives-syntax
 
 // Check the results of `left >>> right`. The result is always unsigned (and
 // therefore positive).
diff --git a/test/mjsunit/compiler/truncating-store.js b/test/mjsunit/compiler/truncating-store.js
new file mode 100644
index 0000000..9e3dd38
--- /dev/null
+++ b/test/mjsunit/compiler/truncating-store.js
@@ -0,0 +1,98 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function() {
+  var asm = (function Module(global, env, buffer) {
+    "use asm";
+
+    var i8 = new global.Int8Array(buffer);
+    var u8 = new global.Uint8Array(buffer);
+    var i16 = new global.Int16Array(buffer);
+    var u16 = new global.Uint16Array(buffer);
+    var i32 = new global.Int32Array(buffer);
+    var u32 = new global.Uint32Array(buffer);
+
+    var H = 0;
+
+    function store_i8() {
+      H = 4294967295;
+      i8[0 >> 0]= H;
+      return i8[0 >> 0];
+    }
+
+    function store_u8() {
+      H = 4294967295;
+      u8[0 >> 0]= H;
+      return u8[0 >> 0];
+    }
+
+    function store_i16() {
+      H = 4294967295;
+      i16[0 >> 0]= H;
+      return i16[0 >> 0];
+    }
+
+    function store_u16() {
+      H = 4294967295;
+      u16[0 >> 0]= H;
+      return u16[0 >> 0];
+    }
+
+    function store_i32() {
+      H = 4294967295;
+      i32[0 >> 0]= H;
+      return i32[0 >> 0];
+    }
+
+    function store_u32() {
+      H = 4294967295;
+      u32[0 >> 0]= H;
+      return u32[0 >> 0];
+    }
+
+    return { store_i8: store_i8,
+             store_u8: store_u8,
+             store_i16: store_i16,
+             store_u16: store_u16,
+             store_i32: store_i32,
+             store_u32: store_u32 };
+  })({
+    "Int8Array": Int8Array,
+    "Uint8Array": Uint8Array,
+    "Int16Array": Int16Array,
+    "Uint16Array": Uint16Array,
+    "Int32Array": Int32Array,
+    "Uint32Array": Uint32Array
+  }, {}, new ArrayBuffer(64 * 1024));
+
+  assertEquals(-1, asm.store_i8());
+  assertEquals(255, asm.store_u8());
+  assertEquals(-1, asm.store_i16());
+  assertEquals(65535, asm.store_u16());
+  assertEquals(-1, asm.store_i32());
+  assertEquals(4294967295, asm.store_u32());
+})();
+
+(function() {
+  var asm = (function Module(global, env, buffer) {
+    "use asm";
+
+    var i32 = new global.Int32Array(buffer);
+
+    var H = 0;
+
+    // This is not valid asm.js, but we should still generate correct code.
+    function store_i32_from_string() {
+      H = "3";
+      i32[0 >> 0]= H;
+      return i32[0 >> 0];
+    }
+
+    return { store_i32_from_string: store_i32_from_string };
+  })({
+    "Int32Array": Int32Array
+  }, {}, new ArrayBuffer(64 * 1024));
+
+  assertEquals(3, asm.store_i32_from_string());
+})();
diff --git a/test/mjsunit/debug-clearbreakpointgroup.js b/test/mjsunit/debug-clearbreakpointgroup.js
index 137dfec..3c03bda 100644
--- a/test/mjsunit/debug-clearbreakpointgroup.js
+++ b/test/mjsunit/debug-clearbreakpointgroup.js
@@ -36,13 +36,17 @@
 
 var base_request = '"seq":0,"type":"request","command":"clearbreakpointgroup"';
 var scriptId = null;
+var muteListener = false;
 
 function safeEval(code) {
   try {
+    muteListener = true;
     return eval('(' + code + ')');
   } catch (e) {
     assertEquals(void 0, e);
     return undefined;
+  } finally {
+    muteListener = false;
   }
 }
 
@@ -58,6 +62,7 @@
 }
 
 function listener(event, exec_state, event_data, data) {
+  if (muteListener) return;
   try {
     if (event == Debug.DebugEvent.Break) {
       // Get the debug command processor.
diff --git a/test/mjsunit/debug-compile-event.js b/test/mjsunit/debug-compile-event.js
index c38cd84..8623406 100644
--- a/test/mjsunit/debug-compile-event.js
+++ b/test/mjsunit/debug-compile-event.js
@@ -37,7 +37,7 @@
 var source_count = 0;  // Total number of scources compiled.
 var host_compilations = 0;  // Number of scources compiled through the API.
 var eval_compilations = 0;  // Number of scources compiled through eval.
-
+var mute_listener = false;
 
 function compileSource(source) {
   current_source = source;
@@ -45,8 +45,20 @@
   source_count++;
 }
 
+function safeEval(code) {
+  try {
+    mute_listener = true;
+    return eval('(' + code + ')');
+  } catch (e) {
+    assertEquals(void 0, e);
+    return undefined;
+  } finally {
+    mute_listener = false;
+  }
+}
 
 function listener(event, exec_state, event_data, data) {
+  if (mute_listener) return;
   try {
     if (event == Debug.DebugEvent.BeforeCompile ||
         event == Debug.DebugEvent.AfterCompile ||
@@ -81,7 +93,7 @@
       }
       // Check that script context is included into the event message.
       var json = event_data.toJSONProtocol();
-      var msg = eval('(' + json + ')');
+      var msg = safeEval(json);
       assertTrue('context' in msg.body.script);
 
       // Check that we pick script name from //# sourceURL, iff present
diff --git a/test/mjsunit/debug-evaluate-locals-optimized-double.js b/test/mjsunit/debug-evaluate-locals-optimized-double.js
index 6696ec5..84b7e20 100644
--- a/test/mjsunit/debug-evaluate-locals-optimized-double.js
+++ b/test/mjsunit/debug-evaluate-locals-optimized-double.js
@@ -89,9 +89,10 @@
           }
 
           // All frames except the bottom one have two scopes.
-          assertEquals(2, frame.scopeCount());
+          assertEquals(3, frame.scopeCount());
           assertEquals(debug.ScopeType.Local, frame.scope(0).scopeType());
-          assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType());
+          assertEquals(debug.ScopeType.Script, frame.scope(1).scopeType());
+          assertEquals(debug.ScopeType.Global, frame.scope(2).scopeType());
 
           Object.keys(expected_locals).forEach(function (name) {
             assertEquals(expected_locals[name],
@@ -134,8 +135,9 @@
                        frame.evaluate(arguments_sum).value());
         } else {
           // The bottom frame only have the global scope.
-          assertEquals(1, frame.scopeCount());
-          assertEquals(debug.ScopeType.Global, frame.scope(0).scopeType());
+          assertEquals(2, frame.scopeCount());
+          assertEquals(debug.ScopeType.Script, frame.scope(0).scopeType());
+          assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType());
         }
 
         // Check the frame function.
diff --git a/test/mjsunit/debug-evaluate-locals-optimized.js b/test/mjsunit/debug-evaluate-locals-optimized.js
index d424001..9d539fe 100644
--- a/test/mjsunit/debug-evaluate-locals-optimized.js
+++ b/test/mjsunit/debug-evaluate-locals-optimized.js
@@ -79,10 +79,11 @@
                          frame.argumentValue(j).value());
           }
 
-          // All frames except the bottom one have two scopes.
-          assertEquals(2, frame.scopeCount());
+          // All frames except the bottom one have three scopes.
+          assertEquals(3, frame.scopeCount());
           assertEquals(debug.ScopeType.Local, frame.scope(0).scopeType());
-          assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType());
+          assertEquals(debug.ScopeType.Script, frame.scope(1).scopeType());
+          assertEquals(debug.ScopeType.Global, frame.scope(2).scopeType());
 
           Object.keys(expected_locals).forEach(function (name) {
             assertEquals(expected_locals[name],
@@ -124,9 +125,10 @@
           assertEquals(expected_args_sum,
                        frame.evaluate(arguments_sum).value());
         } else {
-          // The bottom frame only have the global scope.
-          assertEquals(1, frame.scopeCount());
-          assertEquals(debug.ScopeType.Global, frame.scope(0).scopeType());
+          // The bottom frame only have the script scope and the global scope.
+          assertEquals(2, frame.scopeCount());
+          assertEquals(debug.ScopeType.Script, frame.scope(0).scopeType());
+          assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType());
         }
 
         // Check the frame function.
diff --git a/test/mjsunit/debug-evaluate-with-context.js b/test/mjsunit/debug-evaluate-with-context.js
index 5e1c83c..fa615ad 100644
--- a/test/mjsunit/debug-evaluate-with-context.js
+++ b/test/mjsunit/debug-evaluate-with-context.js
@@ -32,6 +32,7 @@
 var evaluate_callback;
 
 function listener(event, exec_state, event_data, data) {
+  if (event !== Debug.DebugEvent.Break) return;
   try {
     var context = { what_is_capybara: "a fish" };
     var context2 = { what_is_capybara: "a fish", what_is_parrot: "a beard" };
diff --git a/test/mjsunit/debug-function-scopes.js b/test/mjsunit/debug-function-scopes.js
index b51e8b4..8992fe7 100644
--- a/test/mjsunit/debug-function-scopes.js
+++ b/test/mjsunit/debug-function-scopes.js
@@ -48,7 +48,8 @@
                   With: 2,
                   Closure: 3,
                   Catch: 4,
-                  Block: 5 };
+                  Block: 5,
+                  Script: 6};
 
 var f1 = (function F1(x) {
   function F2(y) {
@@ -68,21 +69,23 @@
 
 var mirror = Debug.MakeMirror(f1);
 
-assertEquals(5, mirror.scopeCount());
+assertEquals(6, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
 CheckScope(mirror.scope(1), { w: 5, v: "Capybara" }, ScopeType.With);
 CheckScope(mirror.scope(2), { y: 17, z: 22 }, ScopeType.Closure);
 CheckScope(mirror.scope(3), { x: 5 }, ScopeType.Closure);
-CheckScope(mirror.scope(4), {}, ScopeType.Global);
+CheckScope(mirror.scope(4), {}, ScopeType.Script);
+CheckScope(mirror.scope(5), {}, ScopeType.Global);
 
 var f2 = function() { return 5; }
 
 var mirror = Debug.MakeMirror(f2);
 
-assertEquals(1, mirror.scopeCount());
+assertEquals(2, mirror.scopeCount());
 
-CheckScope(mirror.scope(0), {}, ScopeType.Global);
+CheckScope(mirror.scope(0), {}, ScopeType.Script);
+CheckScope(mirror.scope(1), {}, ScopeType.Global);
 
 var f3 = (function F1(invisible_parameter) {
   var invisible1 = 1;
@@ -99,11 +102,12 @@
 
 var mirror = Debug.MakeMirror(f3);
 
-assertEquals(3, mirror.scopeCount());
+assertEquals(4, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { visible2: 20 }, ScopeType.Closure);
 CheckScope(mirror.scope(1), { visible1: 10 }, ScopeType.Closure);
-CheckScope(mirror.scope(2), {}, ScopeType.Global);
+CheckScope(mirror.scope(2), {}, ScopeType.Script);
+CheckScope(mirror.scope(3), {}, ScopeType.Global);
 
 
 var f4 = (function One() {
@@ -122,11 +126,12 @@
 
 var mirror = Debug.MakeMirror(f4);
 
-assertEquals(3, mirror.scopeCount());
+assertEquals(4, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { e2: "I'm error 2" }, ScopeType.Catch);
 CheckScope(mirror.scope(1), { e1: "I'm error 1" }, ScopeType.Catch);
-CheckScope(mirror.scope(2), {}, ScopeType.Global);
+CheckScope(mirror.scope(2), {}, ScopeType.Script);
+CheckScope(mirror.scope(3), {}, ScopeType.Global);
 
 
 var f5 = (function Raz(p1, p2) {
@@ -141,11 +146,12 @@
 
 var mirror = Debug.MakeMirror(f5);
 
-assertEquals(3, mirror.scopeCount());
+assertEquals(4, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { p4: 20, p6: 22 }, ScopeType.Closure);
 CheckScope(mirror.scope(1), { p1: 1 }, ScopeType.Closure);
-CheckScope(mirror.scope(2), {}, ScopeType.Global);
+CheckScope(mirror.scope(2), {}, ScopeType.Script);
+CheckScope(mirror.scope(3), {}, ScopeType.Global);
 
 
 function CheckNoScopeVisible(f) {
diff --git a/test/mjsunit/debug-references.js b/test/mjsunit/debug-references.js
index 763e354..bb33976 100644
--- a/test/mjsunit/debug-references.js
+++ b/test/mjsunit/debug-references.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --turbo-deoptimization
 // Get the Debug object exposed from the debug context global object.
 Debug = debug.Debug
 
diff --git a/test/mjsunit/debug-scopes.js b/test/mjsunit/debug-scopes.js
index 4823496..7c08120 100644
--- a/test/mjsunit/debug-scopes.js
+++ b/test/mjsunit/debug-scopes.js
@@ -130,6 +130,7 @@
     assertEquals(i, response.body.scopes[i].index);
     assertEquals(scopes[i], response.body.scopes[i].type);
     if (scopes[i] == debug.ScopeType.Local ||
+        scopes[i] == debug.ScopeType.Script ||
         scopes[i] == debug.ScopeType.Closure) {
       assertTrue(response.body.scopes[i].object.ref < 0);
     } else {
@@ -193,6 +194,7 @@
   assertEquals(scope.scopeType(), response.body.type);
   assertEquals(number, response.body.index);
   if (scope.scopeType() == debug.ScopeType.Local ||
+      scope.scopeType() == debug.ScopeType.Script ||
       scope.scopeType() == debug.ScopeType.Closure) {
     assertTrue(response.body.object.ref < 0);
   } else {
@@ -215,6 +217,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -231,6 +234,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1}, 0, exec_state);
 };
@@ -248,6 +252,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,x:3}, 0, exec_state);
 };
@@ -266,6 +271,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state);
 };
@@ -283,6 +289,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -300,6 +307,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({i:5}, 0, exec_state);
 };
@@ -321,6 +329,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4,i:5,j:6}, 0, exec_state);
 };
@@ -340,6 +349,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -362,6 +372,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
   CheckScopeContent({}, 1, exec_state);
@@ -382,6 +393,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2}, 0, exec_state);
 };
@@ -404,6 +416,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:2,b:1}, 0, exec_state);
   CheckScopeContent({a:1,b:2}, 1, exec_state);
@@ -428,6 +441,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent(with_object, 0, exec_state);
   CheckScopeContent(with_object, 1, exec_state);
@@ -443,6 +457,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.With,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent(with_object, 0, exec_state);
   CheckScopeContent(with_object, 1, exec_state);
@@ -472,6 +487,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -494,6 +510,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
 };
@@ -519,6 +536,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,x:3}, 1, exec_state);
 };
@@ -545,6 +563,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4}, 1, exec_state);
 };
@@ -574,6 +593,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4,f:function(){}}, 1, exec_state);
 };
@@ -602,6 +622,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4,f:function(){}}, 1, exec_state);
 };
@@ -631,6 +652,7 @@
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
   CheckScopeContent({f:function(){}}, 2, exec_state);
@@ -665,6 +687,7 @@
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4,i:5,j:6}, 1, exec_state);
@@ -684,6 +707,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 2}, 0, exec_state);
 };
@@ -705,6 +729,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
 };
 closure_9();
@@ -746,6 +771,7 @@
                    debug.ScopeType.With,
                    debug.ScopeType.Closure,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({b:16}, 0, exec_state);
   CheckScopeContent({a:15}, 1, exec_state);
@@ -771,6 +797,7 @@
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.With,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 2}, 0, exec_state);
 };
@@ -794,6 +821,7 @@
                    debug.ScopeType.Local,
                    debug.ScopeType.With,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 3}, 0, exec_state);
   CheckScopeContent({x: 2}, 1, exec_state);
@@ -826,6 +854,7 @@
                    debug.ScopeType.Local,
                    debug.ScopeType.Closure,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
 }
 closure_in_with_3();
@@ -836,6 +865,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.With,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 2}, 0, exec_state);
   CheckScopeContent({x: 1}, 1, exec_state);
@@ -852,7 +882,7 @@
 // Test global scope.
 BeginTest("Global");
 listener_delegate = function(exec_state) {
-  CheckScopeChain([debug.ScopeType.Global], exec_state);
+  CheckScopeChain([debug.ScopeType.Script, debug.ScopeType.Global], exec_state);
 };
 debugger;
 EndTest();
@@ -871,6 +901,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({e:'Exception'}, 0, exec_state);
 };
@@ -894,6 +925,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({n:10}, 0, exec_state);
   CheckScopeContent({e:'Exception'}, 1, exec_state);
@@ -918,6 +950,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({e:'Exception'}, 0, exec_state);
   CheckScopeContent({y:78}, 1, exec_state);
@@ -944,6 +977,7 @@
   CheckScopeChain([debug.ScopeType.With,
                    debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({n:10}, 0, exec_state);
   CheckScopeContent({e:'Exception'}, 1, exec_state);
@@ -957,6 +991,7 @@
 BeginTest("Catch block 5");
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Catch,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({e:'Exception'}, 0, exec_state);
 };
@@ -975,6 +1010,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Catch,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x: 2}, 0, exec_state);
   CheckScopeContent({e:'Exception'}, 1, exec_state);
@@ -1005,6 +1041,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Catch,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({e:'Exception'}, 0, exec_state);
 };
diff --git a/test/mjsunit/debug-script.js b/test/mjsunit/debug-script.js
index 5ffada1..07f0e3c 100644
--- a/test/mjsunit/debug-script.js
+++ b/test/mjsunit/debug-script.js
@@ -26,6 +26,13 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Flags: --expose-debug-as debug --expose-gc --send-idle-notification
+// Flags: --allow-natives-syntax
+// Flags: --noharmony-shipping
+// Note: this test checks that that the number of scripts reported as native
+// by Debug.scripts() is the same as a number of core native scripts.
+// Native scripts that are added by --harmony-shipping are classified
+// as 'experimental', but are still returned by Debug.scripts(), so
+// we disable harmony-shipping for this test
 
 // Get the Debug object exposed from the debug context global object.
 Debug = debug.Debug;
@@ -59,7 +66,7 @@
 }
 
 // This has to be updated if the number of native scripts change.
-assertTrue(named_native_count == 26 || named_native_count == 27);
+assertEquals(%NativeScriptsCount(), named_native_count);
 // Only the 'gc' extension is loaded.
 assertEquals(1, extension_count);
 // This script and mjsunit.js has been loaded.  If using d8, d8 loads
diff --git a/test/mjsunit/debug-step-turbofan.js b/test/mjsunit/debug-step-turbofan.js
new file mode 100644
index 0000000..c8c346b
--- /dev/null
+++ b/test/mjsunit/debug-step-turbofan.js
@@ -0,0 +1,57 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --turbo-filter=g --allow-natives-syntax
+
+// Test that Debug::PrepareForBreakPoints can deal with turbofan code (g)
+// on the stack.  Without deoptimization support, we will not be able to
+// replace optimized code for g by unoptimized code with debug break slots.
+// This would cause stepping to fail (V8 issue 3660).
+
+function f(x) {
+  g(x);
+  var a = 0;              // Break 6
+  return a;               // Break 7
+}                         // Break 8
+
+function g(x) {
+  if (x) h();
+  var a = 0;              // Break 2
+  var b = 1;              // Break 3
+  return a + b;           // Break 4
+}                         // Break 5
+
+function h() {
+  debugger;               // Break 0
+}                         // Break 1
+
+Debug = debug.Debug;
+var exception = null;
+var break_count = 0;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    exec_state.prepareStep(Debug.StepAction.StepNext, 1);
+    print(exec_state.frame(0).sourceLineText());
+    var match = exec_state.frame(0).sourceLineText().match(/Break (\d)/);
+    assertNotNull(match);
+    assertEquals(break_count++, parseInt(match[1]));
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+f(0);
+f(0);
+%OptimizeFunctionOnNextCall(g);
+
+Debug.setListener(listener);
+
+f(1);
+
+Debug.setListener(null);  // Break 9
+assertNull(exception);
+assertEquals(10, break_count);
diff --git a/test/mjsunit/debug-step.js b/test/mjsunit/debug-step.js
index 2233e36..45f077f 100644
--- a/test/mjsunit/debug-step.js
+++ b/test/mjsunit/debug-step.js
@@ -68,7 +68,7 @@
 state = 0;
 result = -1;
 f();
-assertEquals(499, result);
+assertEquals(332, result);
 
 // Check that performing 1000 steps with a break point on the statement in the
 // for loop (line 2) will only make i 0 as a real break point breaks even when
diff --git a/test/mjsunit/debug-stepframe.js b/test/mjsunit/debug-stepframe.js
new file mode 100644
index 0000000..8f4ee4c
--- /dev/null
+++ b/test/mjsunit/debug-stepframe.js
@@ -0,0 +1,111 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+function f0() {
+  var v00 = 0;              // Break 1
+  var v01 = 1;
+  // Normal function call in a catch scope.
+  try {
+    throw 1;
+  } catch (e) {
+    try{
+      f1();
+    } catch (e) {
+      var v02 = 2;          // Break 13
+    }
+  }
+  var v03 = 3;
+  var v04 = 4;
+}
+
+function f1() {
+  var v10 = 0;              // Break 2
+  var v11 = 1;
+  // Getter call.
+  var v12 = o.get;
+  var v13 = 3               // Break 4
+  // Setter call.
+  o.set = 2;
+  var v14 = 4;              // Break 6
+  // Function.prototype.call.
+  f2.call();
+  var v15 = 5;              // Break 12
+  var v16 = 6;
+  // Exit function by throw.
+  throw 1;
+  var v17 = 7;
+}
+
+function get() {
+  var g0 = 0;               // Break 3
+  var g1 = 1;
+  return 3;
+}
+
+function set() {
+  var s0 = 0;               // Break 5
+  return 3;
+}
+
+function f2() {
+  var v20 = 0;              // Break 7
+  // Construct call.
+  var v21 = new c0();
+  var v22 = 2;              // Break 9
+  // Bound function.
+  b0();
+  return 2;                 // Break 11
+}
+
+function c0() {
+  this.v0 = 0;              // Break 8
+  this.v1 = 1;
+}
+
+function f3() {
+  var v30 = 0;              // Break 10
+  var v31 = 1;
+  return 3;
+}
+
+var b0 = f3.bind(o);
+
+var o = {};
+Object.defineProperty(o, "get", { get : get });
+Object.defineProperty(o, "set", { set : set });
+
+Debug = debug.Debug;
+var break_count = 0
+var exception = null;
+var step_size;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    var line = exec_state.frame(0).sourceLineText();
+    print(line);
+    var match = line.match(/\/\/ Break (\d+)$/);
+    assertEquals(2, match.length);
+    assertEquals(break_count, parseInt(match[1]));
+    break_count += step_size;
+    exec_state.prepareStep(Debug.StepAction.StepFrame, step_size);
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+for (step_size = 1; step_size < 6; step_size++) {
+  print("step size = " + step_size);
+  break_count = 0;
+  Debug.setListener(listener);
+  debugger;                 // Break 0
+  f0();
+  Debug.setListener(null);  // Break 14
+  assertTrue(break_count > 14);
+}
+
+assertNull(exception);
diff --git a/test/mjsunit/debug-stepin-foreach.js b/test/mjsunit/debug-stepin-foreach.js
new file mode 100644
index 0000000..fa728e0
--- /dev/null
+++ b/test/mjsunit/debug-stepin-foreach.js
@@ -0,0 +1,51 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+// Tests stepping into through Array.prototype.forEach callbacks.
+
+Debug = debug.Debug
+var exception = null;
+var break_count = 0;
+var expected_breaks = -1;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace");
+      if (!break_count) {
+        // Count number of expected breakpoints in this source file.
+        var source_text = exec_state.frame(0).func().script().source();
+        expected_breaks = source_text.match(/\/\/\s*Break\s+\d+\./g).length;
+        print("Expected breaks: " + expected_breaks);
+      }
+      var source = exec_state.frame(0).sourceLineText();
+      print("paused at: " + source);
+      assertTrue(source.indexOf("// Break " + break_count + ".") > 0,
+                 "Unexpected pause at: " + source + "\n" +
+                 "Expected: // Break " + break_count + ".");
+      ++break_count;
+      if (break_count !== expected_breaks) {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 1);
+      }
+    }
+  } catch(e) {
+    exception = e;
+    print(e, e.stack);
+  }
+};
+
+Debug.setListener(listener);
+
+debugger; // Break 0.
+[1,2].forEach(callback); // Break 1.
+
+function callback(x) {
+  return x; // Break 2. // Break 4.
+} // Break 3. // Break 5.
+
+assertNull(exception); // Break 6.
+assertEquals(expected_breaks, break_count);
+
+Debug.setListener(null);
diff --git a/test/mjsunit/debug-stepin-property-function-call.js b/test/mjsunit/debug-stepin-property-function-call.js
new file mode 100644
index 0000000..081fb24
--- /dev/null
+++ b/test/mjsunit/debug-stepin-property-function-call.js
@@ -0,0 +1,153 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --nocrankshaft
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+var exception = null;
+var state = 1;
+
+// Simple debug event handler which first time will cause 'step in' action
+// to get into g.call and than check that execution is stopped inside
+// function 'g'.
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      if (state == 1) {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 3);
+        state = 2;
+      } else if (state == 2) {
+        assertTrue(event_data.sourceLineText().indexOf("Expected to step") > 0,
+          "source line: \"" + event_data.sourceLineText() + "\"");
+        state = 3;
+      }
+    }
+  } catch(e) {
+    print("Exception: " + e);
+    exception = e;
+  }
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+var count = 0;
+var obj = {
+  fun: function() {
+    ++count;
+    return count; // Expected to step
+  }
+};
+obj.fun2 = obj.fun;
+
+function testCall_Dots() {
+  debugger;
+  obj.fun();
+}
+
+function testCall_Quotes() {
+  debugger;
+  obj["fun"]();
+}
+
+function testCall_Call() {
+  debugger;
+  obj.fun.call(obj);
+}
+
+function testCall_Apply() {
+  debugger;
+  obj.fun.apply(obj);
+}
+
+function testCall_Variable() {
+  var functionName = "fun";
+  debugger;
+  obj[functionName]();
+}
+
+function testCall_Fun2() {
+  debugger;
+  obj.fun2();
+}
+
+function testCall_InternStrings() {
+  var cache = { "fun": "fun" };
+  var functionName = "fu" + "n";
+  debugger;
+  obj[cache[functionName]]();
+}
+
+function testCall_ViaFunRef() {
+  var functionName = "fu" + "n";
+  var funRef = obj[functionName];
+  debugger;
+  funRef();
+}
+
+// bug 2888
+function testCall_RuntimeVariable1() {
+  var functionName = "fu" + "n";
+  debugger;
+  obj[functionName]();
+}
+
+// bug 2888
+function testCall_RuntimeVariable2() {
+  var functionName = "un".replace(/u/, "fu");
+  debugger;
+  obj[functionName]();
+}
+
+// bug 2888
+function testCall_RuntimeVariable3() {
+  var expr = "fu" + "n";
+  const functionName = expr;
+  assertEquals("fun", functionName);
+  debugger;
+  obj[functionName]();
+}
+
+var functionsCalled = 0;
+for (var n in this) {
+  if (n.substr(0, 4) != 'test' || typeof this[n] !== "function") {
+    continue;
+  }
+  state = 1;
+  print("Running " + n + "...");
+  this[n]();
+  ++functionsCalled;
+  assertNull(exception, n);
+  assertEquals(3, state, n);
+  assertEquals(functionsCalled, count, n);
+}
+
+assertEquals(11, functionsCalled);
+
+// Get rid of the debug event listener.
+Debug.setListener(null);
diff --git a/test/mjsunit/deserialize-optimize-inner.js b/test/mjsunit/deserialize-optimize-inner.js
new file mode 100644
index 0000000..72df320
--- /dev/null
+++ b/test/mjsunit/deserialize-optimize-inner.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --cache=code --no-lazy --serialize-inner
+
+function f(x, y) { return x + y; }
+
+assertEquals(1, f(0, 1));
+assertEquals(5, f(2, 3));
+%OptimizeFunctionOnNextCall(f);
+assertEquals(9, f(4, 5));
+assertOptimized(f);
diff --git a/test/mjsunit/es6/array-iterator.js b/test/mjsunit/es6/array-iterator.js
index 96122cd..767991e 100644
--- a/test/mjsunit/es6/array-iterator.js
+++ b/test/mjsunit/es6/array-iterator.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --harmony-tostring
 
 
 var NONE = 0;
@@ -158,6 +158,15 @@
       Object.getOwnPropertyNames(ArrayIteratorPrototype));
   assertHasOwnProperty(ArrayIteratorPrototype, 'next', DONT_ENUM);
   assertHasOwnProperty(ArrayIteratorPrototype, Symbol.iterator, DONT_ENUM);
+
+  assertEquals("[object Array Iterator]",
+      Object.prototype.toString.call(iterator));
+  assertEquals("Array Iterator", ArrayIteratorPrototype[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(
+      ArrayIteratorPrototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("Array Iterator", desc.value);
 }
 TestArrayIteratorPrototype();
 
diff --git a/test/mjsunit/es6/collection-iterator.js b/test/mjsunit/es6/collection-iterator.js
index 5503fe5..18b3f1a 100644
--- a/test/mjsunit/es6/collection-iterator.js
+++ b/test/mjsunit/es6/collection-iterator.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --harmony-tostring
 
 
 (function TestSetIterator() {
@@ -19,6 +19,15 @@
 
   assertEquals(new Set().values().__proto__, SetIteratorPrototype);
   assertEquals(new Set().entries().__proto__, SetIteratorPrototype);
+
+  assertEquals("[object Set Iterator]",
+      Object.prototype.toString.call(iter));
+  assertEquals("Set Iterator", SetIteratorPrototype[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(
+      SetIteratorPrototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("Set Iterator", desc.value);
 })();
 
 
@@ -120,6 +129,15 @@
   assertEquals(new Map().values().__proto__, MapIteratorPrototype);
   assertEquals(new Map().keys().__proto__, MapIteratorPrototype);
   assertEquals(new Map().entries().__proto__, MapIteratorPrototype);
+
+  assertEquals("[object Map Iterator]",
+      Object.prototype.toString.call(iter));
+  assertEquals("Map Iterator", MapIteratorPrototype[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(
+      MapIteratorPrototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("Map Iterator", desc.value);
 })();
 
 
diff --git a/test/mjsunit/es6/collections.js b/test/mjsunit/es6/collections.js
index 940c0b9..92cd087 100644
--- a/test/mjsunit/es6/collections.js
+++ b/test/mjsunit/es6/collections.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --expose-gc --allow-natives-syntax
+// Flags: --expose-gc --allow-natives-syntax --harmony-tostring
 
 
 function assertSize(expected, collection) {
@@ -266,7 +266,6 @@
 assertTrue(WeakMap.prototype.get instanceof Function)
 assertTrue(WeakMap.prototype.has instanceof Function)
 assertTrue(WeakMap.prototype.delete instanceof Function)
-assertTrue(WeakMap.prototype.clear instanceof Function)
 
 
 // Test some common JavaScript idioms for WeakSets
@@ -275,7 +274,6 @@
 assertTrue(WeakSet.prototype.add instanceof Function)
 assertTrue(WeakSet.prototype.has instanceof Function)
 assertTrue(WeakSet.prototype.delete instanceof Function)
-assertTrue(WeakSet.prototype.clear instanceof Function)
 
 
 // Test class of instance and prototype.
@@ -300,7 +298,7 @@
 function TestPrototype(C) {
   assertTrue(C.prototype instanceof Object);
   assertEquals({
-    value: {},
+    value: C.prototype,
     writable: false,
     enumerable: false,
     configurable: false
@@ -471,30 +469,6 @@
 })();
 
 
-// Test WeakMap clear
-(function() {
-  var k = new Object();
-  var w = new WeakMap();
-  w.set(k, 23);
-  assertTrue(w.has(k));
-  assertEquals(23, w.get(k));
-  w.clear();
-  assertFalse(w.has(k));
-  assertEquals(undefined, w.get(k));
-})();
-
-
-// Test WeakSet clear
-(function() {
-  var k = new Object();
-  var w = new WeakSet();
-  w.add(k);
-  assertTrue(w.has(k));
-  w.clear();
-  assertFalse(w.has(k));
-})();
-
-
 (function TestMinusZeroSet() {
   var s = new Set();
   s.add(-0);
@@ -691,6 +665,33 @@
   assertEquals(4950, accumulated);
 })();
 
+
+(function TestSetForEachReceiverAsObject() {
+  var set = new Set(["1", "2"]);
+
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  var a = [];
+  set.forEach(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  set.forEach(function() { a.push(this); }, {});
+  assertEquals(a[0], a[1]);
+})();
+
+
+(function TestSetForEachReceiverAsObjectInStrictMode() {
+  var set = new Set(["1", "2"]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  var a = [];
+  set.forEach(function() { 'use strict'; a.push(this); }, "");
+  assertTrue(a[0] === "" && a[0] === a[1]);
+})();
+
+
 (function TestMapForEachInvalidTypes() {
   assertThrows(function() {
     Map.prototype.map.forEach.call({});
@@ -998,6 +999,36 @@
 })();
 
 
+(function TestMapForEachReceiverAsObject() {
+  var map = new Map();
+  map.set("key1", "value1");
+  map.set("key2", "value2");
+
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  var a = [];
+  map.forEach(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  map.forEach(function() { a.push(this); }, {});
+  assertEquals(a[0], a[1]);
+})();
+
+
+(function TestMapForEachReceiverAsObjectInStrictMode() {
+  var map = new Map();
+  map.set("key1", "value1");
+  map.set("key2", "value2");
+
+  // In strict mode primitive values should not be coerced to an object.
+  var a = [];
+  map.forEach(function() { 'use strict'; a.push(this); }, "");
+  assertTrue(a[0] === "" && a[0] === a[1]);
+})();
+
+
 // Allows testing iterator-based constructors easily.
 var oneAndTwo = new Map();
 var k0 = {key: 0};
@@ -1366,3 +1397,12 @@
 }
 TestMapConstructorIterableValue(Map);
 TestMapConstructorIterableValue(WeakMap);
+
+function TestCollectionToString(C) {
+  assertEquals("[object " + C.name + "]",
+      Object.prototype.toString.call(new C()));
+}
+TestCollectionToString(Map);
+TestCollectionToString(Set);
+TestCollectionToString(WeakMap);
+TestCollectionToString(WeakSet);
diff --git a/test/mjsunit/es6/debug-stepin-microtasks.js b/test/mjsunit/es6/debug-stepin-microtasks.js
new file mode 100644
index 0000000..8dbdb34
--- /dev/null
+++ b/test/mjsunit/es6/debug-stepin-microtasks.js
@@ -0,0 +1,101 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --expose-debug-as debug
+
+Debug = debug.Debug
+var exception = null;
+var break_count = 0;
+var expected_breaks = -1;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace");
+      if (!break_count) {
+        // Count number of expected breakpoints in this source file.
+        var source_text = exec_state.frame(0).func().script().source();
+        expected_breaks = source_text.match(/\/\/\s*Break\s+\d+\./g).length;
+        print("Expected breaks: " + expected_breaks);
+      }
+      var source = exec_state.frame(0).sourceLineText();
+      print("paused at: " + source);
+      assertTrue(source.indexOf("// Break " + break_count + ".") > 0,
+                 "Unexpected pause at: " + source + "\n" +
+                 "Expected: // Break " + break_count + ".");
+      if (source.indexOf("StepOver.") !== -1) {
+        exec_state.prepareStep(Debug.StepAction.StepNext, 1);
+      } else {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 1);
+      }
+      ++break_count;
+    }
+  } catch (e) {
+    exception = e;
+    print(e, e.stack);
+  }
+};
+
+Debug.setListener(listener);
+
+Promise.resolve(42)
+  .then(promise1)
+  .then(Object) // Should skip stepping into native.
+  .then(Boolean) // Should skip stepping into native.
+  .then(promise2)
+  .catch(promise3)
+  .catch(function(e) {
+    %AbortJS("FAIL: uncaught exception " + e);
+  });
+
+function promise1() {
+  debugger; // Break 0.
+  return exception || 1; // Break 1.
+} // Break 2.
+
+function promise2() {
+  throw new Error; // Break 3.
+}
+
+function promise3() {
+  installObservers(); // Break 4. StepOver.
+  return break_count; // Break 5.
+} // Break 6.
+
+function installObservers() {
+  var dummy = {};
+  Object.observe(dummy, observer1);
+  Object.observe(dummy, Object); // Should skip stepping into native.
+  Object.observe(dummy, Boolean); // Should skip stepping into native.
+  Object.observe(dummy, observer2);
+  dummy.foo = 1;
+}
+
+function observer1() {
+  return exception || 3; // Break 7.
+} // Break 8.
+
+function observer2() {
+  Promise.resolve().then(promise4); // Break 9. StepOver.
+  return break_count + 1; // Break 10.
+} // Break 11.
+
+function promise4() {
+  finalize(); // Break 12. StepOver.
+  return 0; // Break 13.
+} // Break 14. StepOver.
+
+function finalize() {
+  var dummy = {};
+  Object.observe(dummy, function() {
+    if (expected_breaks !== break_count) {
+      %AbortJS("FAIL: expected <" + expected_breaks + "> breaks instead of <" +
+               break_count + ">");
+    }
+    if (exception !== null) {
+      %AbortJS("FAIL: exception: " + exception);
+    }
+  });
+  dummy.foo = 1;
+}
diff --git a/test/mjsunit/es6/debug-stepnext-for.js b/test/mjsunit/es6/debug-stepnext-for.js
new file mode 100644
index 0000000..98af911
--- /dev/null
+++ b/test/mjsunit/es6/debug-stepnext-for.js
@@ -0,0 +1,116 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --harmony
+
+Debug = debug.Debug;
+var break_count = 0
+var exception = null;
+var log = []
+
+var s = 0;
+var a = [1, 2, 3];
+var i = 0;
+
+function f() {
+  "use strict";
+  debugger;                      // Break a
+  var j;                         // Break b
+
+  for (var i in null) {          // Break c
+    s += a[i];
+  }
+
+  for (j in null) {              // Break d
+    s += a[j];
+  }
+
+  for (var i in a) {             // Break e
+    s += a[i];                   // Break E
+  }
+
+  for (j in a) {                 // Break f
+    s += a[j];                   // Break F
+  }
+
+  for (let i in a) {             // Break g
+    s += a[i];                   // Break G
+  }
+
+  for (var i of a) {             // Break h
+    s += i;                      // Break H
+  }
+
+  for (j of a) {                 // Break i
+    s += j;                      // Break I
+  }
+
+  for (let i of a) {             // Break j
+    s += i;                      // Break J
+  }
+
+  for (var i = 0; i < 3; i++) {  // Break k
+    s += a[i];                   // Break K
+  }
+
+  for (j = 0; j < 3; j++) {      // Break l
+    s += a[j];                   // Break L
+  }
+
+  // TODO(yangguo): add test case for for-let.
+}                                // Break y
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    var line = exec_state.frame(0).sourceLineText();
+    var col = exec_state.frame(0).sourceColumn();
+    print(line);
+    var match = line.match(/\/\/ Break (\w)$/);
+    assertEquals(2, match.length);
+    log.push(match[1] + col);
+    exec_state.prepareStep(Debug.StepAction.StepNext, 1);
+    break_count++;
+  } catch (e) {
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+f();
+Debug.setListener(null);         // Break z
+
+print(JSON.stringify(log));
+// The let declaration differs from var in that the loop variable
+// is declared in every iteration.
+var expected = [
+  // Entry
+  "a2","b2",
+  // Empty for-in-var: var decl, get enumerable
+  "c7","c16",
+  // Empty for-in: get enumerable
+  "d12",
+  // For-in-var: var decl, get enumerable, assign, body, assign, body, ...
+  "e7","e16","e11","E4","e11","E4","e11","E4","e11",
+  // For-in: get enumerable, assign, body, assign, body, ...
+  "f12","f7","F4","f7","F4","f7","F4","f7",
+  // For-in-let: get enumerable, next, new let, body, next, new let, ...
+  "g16","g11","g7","G4","g11","g7","G4","g11","g7","G4","g11",
+  // For-of-var: var decl, next(), body, next(), body, ...
+  "h7","h16","H4","h16","H4","h16","H4","h16",
+  // For-of: next(), body, next(), body, ...
+  "i12","I4","i12","I4","i12","I4","i12",
+  // For-of-let: next(), new let, body, next(), new let, ...
+  "j16","j7","J4","j16","j7","J4","j16","j7","J4","j16",
+  // For-var: var decl, condition, body, next, condition, body, ...
+  "k7","k20","K4","k23","k20","K4","k23","k20","K4","k23","k20",
+  // For: init, condition, body, next, condition, body, ...
+  "l11","l16","L4","l19","l16","L4","l19","l16","L4","l19","l16",
+  // Exit.
+  "y0","z0",
+]
+
+assertArrayEquals(expected, log);
+assertEquals(48, s);
+assertNull(exception);
diff --git a/test/mjsunit/es6/generators-debug-scopes.js b/test/mjsunit/es6/generators-debug-scopes.js
index d55e561..126572d 100644
--- a/test/mjsunit/es6/generators-debug-scopes.js
+++ b/test/mjsunit/es6/generators-debug-scopes.js
@@ -97,6 +97,7 @@
     assertEquals(i, response.body.scopes[i].index);
     assertEquals(scopes[i], response.body.scopes[i].type);
     if (scopes[i] == debug.ScopeType.Local ||
+        scopes[i] == debug.ScopeType.Script ||
         scopes[i] == debug.ScopeType.Closure) {
       assertTrue(response.body.scopes[i].object.ref < 0);
     } else {
@@ -159,6 +160,7 @@
   assertEquals(scope.scopeType(), response.body.type);
   assertEquals(number, response.body.index);
   if (scope.scopeType() == debug.ScopeType.Local ||
+      scope.scopeType() == debug.ScopeType.Script ||
       scope.scopeType() == debug.ScopeType.Closure) {
     assertTrue(response.body.object.ref < 0);
   } else {
@@ -178,6 +180,7 @@
         [],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({}, 0, exec_state);
         });
@@ -188,6 +191,7 @@
         [1],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1}, 0, exec_state);
         });
@@ -198,6 +202,7 @@
         [1],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1,x:3}, 0, exec_state);
         });
@@ -208,6 +213,7 @@
         [1, 2],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state);
         });
@@ -218,6 +224,7 @@
         [],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({}, 0, exec_state);
         });
@@ -228,6 +235,7 @@
         [],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({i:5}, 0, exec_state);
         });
@@ -242,6 +250,7 @@
         [1, 2],
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1,b:2,x:3,y:4,i:5,j:6}, 0, exec_state);
         });
@@ -254,6 +263,7 @@
           CheckScopeChain([debug.ScopeType.With,
                            debug.ScopeType.With,
                            debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({}, 0, exec_state);
           CheckScopeContent({}, 1, exec_state);
@@ -267,6 +277,7 @@
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Local,
                            debug.ScopeType.Closure,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({a:1}, 1, exec_state);
         },
@@ -305,6 +316,7 @@
                            debug.ScopeType.With,
                            debug.ScopeType.Closure,
                            debug.ScopeType.Closure,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({b:16}, 0, exec_state);
           CheckScopeContent({a:15}, 1, exec_state);
@@ -321,6 +333,7 @@
         function (exec_state) {
           CheckScopeChain([debug.ScopeType.Catch,
                            debug.ScopeType.Local,
+                           debug.ScopeType.Script,
                            debug.ScopeType.Global], exec_state);
           CheckScopeContent({e:'Exception'}, 0, exec_state);
         });
diff --git a/test/mjsunit/es6/generators-iteration.js b/test/mjsunit/es6/generators-iteration.js
index b6fcdaa..faeb683 100644
--- a/test/mjsunit/es6/generators-iteration.js
+++ b/test/mjsunit/es6/generators-iteration.js
@@ -41,10 +41,7 @@
 }
 
 function assertThrownIteratorIsClosed(iter) {
-  // TODO(yusukesuzuki): Since status of a thrown generator is "executing",
-  // following tests are failed.
-  // https://code.google.com/p/v8/issues/detail?id=3096
-  // assertIteratorIsClosed(iter);
+  assertIteratorIsClosed(iter);
 }
 
 function TestGeneratorResultPrototype() {
diff --git a/test/mjsunit/es6/generators-mirror.js b/test/mjsunit/es6/generators-mirror.js
index 6925285..bf21f4d 100644
--- a/test/mjsunit/es6/generators-mirror.js
+++ b/test/mjsunit/es6/generators-mirror.js
@@ -24,7 +24,7 @@
   return this.refs_[handle];
 }
 
-function TestGeneratorMirror(g, test) {
+function TestGeneratorMirror(g, status, line, column, receiver) {
   // Create mirror and JSON representation.
   var mirror = debug.MakeMirror(g);
   var serializer = debug.MakeMirrorSerializer();
@@ -44,41 +44,69 @@
   assertFalse(mirror.isPrimitive());
   assertEquals('Generator', mirror.className());
 
-  assertTrue(mirror.receiver().isUndefined());
+  assertEquals(receiver, mirror.receiver().value());
   assertEquals(generator, mirror.func().value());
 
-  test(mirror);
+  assertEquals(status, mirror.status());
+
+  // Note that line numbers are 0-based, not 1-based.
+  var loc = mirror.sourceLocation();
+  if (status === 'suspended') {
+    assertTrue(!!loc);
+    assertEquals(line, loc.line);
+    assertEquals(column, loc.column);
+  } else {
+    assertEquals(undefined, loc);
+  }
+
+  TestInternalProperties(mirror, status, receiver);
 }
 
-var iter = generator(function () {
-  assertEquals('running', debug.MakeMirror(iter).status());
-})
-
-// Note that line numbers are 0-based, not 1-based.
-function assertSourceLocation(loc, line, column) {
-  assertEquals(line, loc.line);
-  assertEquals(column, loc.column);
+function TestInternalProperties(mirror, status, receiver) {
+  var properties = mirror.internalProperties();
+  assertEquals(3, properties.length);
+  assertEquals("[[GeneratorStatus]]", properties[0].name());
+  assertEquals(status, properties[0].value().value());
+  assertEquals("[[GeneratorFunction]]", properties[1].name());
+  assertEquals(generator, properties[1].value().value());
+  assertEquals("[[GeneratorReceiver]]", properties[2].name());
+  assertEquals(receiver, properties[2].value().value());
 }
 
-TestGeneratorMirror(iter, function (mirror) {
-  assertEquals('suspended', mirror.status())
-  assertSourceLocation(mirror.sourceLocation(), 7, 19);
-});
-
-iter.next();
-TestGeneratorMirror(iter, function (mirror) {
-  assertEquals('suspended', mirror.status())
-  assertSourceLocation(mirror.sourceLocation(), 9, 2);
-});
-
-iter.next();
-TestGeneratorMirror(iter, function (mirror) {
-  assertEquals('suspended', mirror.status())
-  assertSourceLocation(mirror.sourceLocation(), 11, 2);
-});
-
-iter.next();
-TestGeneratorMirror(iter, function (mirror) {
-  assertEquals('closed', mirror.status())
+var iter = generator(function() {
+  var mirror = debug.MakeMirror(iter);
+  assertEquals('running', mirror.status());
   assertEquals(undefined, mirror.sourceLocation());
+  TestInternalProperties(mirror, 'running');
 });
+
+TestGeneratorMirror(iter, 'suspended', 7, 19);
+
+iter.next();
+TestGeneratorMirror(iter, 'suspended', 9, 2);
+
+iter.next();
+TestGeneratorMirror(iter, 'suspended', 11, 2);
+
+iter.next();
+TestGeneratorMirror(iter, 'closed');
+
+// Test generator with receiver.
+var obj = {foo: 42};
+var iter2 = generator.call(obj, function() {
+  var mirror = debug.MakeMirror(iter2);
+  assertEquals('running', mirror.status());
+  assertEquals(undefined, mirror.sourceLocation());
+  TestInternalProperties(mirror, 'running', obj);
+});
+
+TestGeneratorMirror(iter2, 'suspended', 7, 19, obj);
+
+iter2.next();
+TestGeneratorMirror(iter2, 'suspended', 9, 2, obj);
+
+iter2.next();
+TestGeneratorMirror(iter2, 'suspended', 11, 2, obj);
+
+iter2.next();
+TestGeneratorMirror(iter2, 'closed', 0, 0, obj);
diff --git a/test/mjsunit/es6/generators-objects.js b/test/mjsunit/es6/generators-objects.js
index 8a052ff..8039ca8 100644
--- a/test/mjsunit/es6/generators-objects.js
+++ b/test/mjsunit/es6/generators-objects.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --harmony-scoping --allow-natives-syntax
+// Flags: --harmony-scoping --allow-natives-syntax --harmony-tostring
 
 // Test instantations of generators.
 
@@ -66,6 +66,9 @@
   assertTrue(iter instanceof g);
   assertEquals("Generator", %_ClassOf(iter));
   assertEquals("[object Generator]", String(iter));
+  assertEquals("[object Generator]", Object.prototype.toString.call(iter));
+  var gf = iter.__proto__.constructor;
+  assertEquals("[object GeneratorFunction]", Object.prototype.toString.call(gf));
   assertEquals([], Object.getOwnPropertyNames(iter));
   assertTrue(iter !== new g());
 }
diff --git a/test/mjsunit/es6/generators-states.js b/test/mjsunit/es6/generators-states.js
new file mode 100644
index 0000000..0a2173a
--- /dev/null
+++ b/test/mjsunit/es6/generators-states.js
@@ -0,0 +1,67 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test generator states.
+
+function Foo() {}
+function Bar() {}
+
+function assertIteratorResult(value, done, result) {
+  assertEquals({ value: value, done: done}, result);
+}
+
+function assertIteratorIsClosed(iter) {
+  assertIteratorResult(undefined, true, iter.next());
+  // Next and throw on a closed iterator.
+  assertDoesNotThrow(function() { iter.next(); });
+  assertThrows(function() { iter.throw(new Bar); }, Bar);
+}
+
+var iter;
+function* nextGenerator() { yield iter.next(); }
+function* throwGenerator() { yield iter.throw(new Bar); }
+
+// Throw on a suspendedStart iterator.
+iter = nextGenerator();
+assertThrows(function() { iter.throw(new Foo) }, Foo)
+assertThrows(function() { iter.throw(new Foo) }, Foo)
+assertIteratorIsClosed(iter);
+
+// The same.
+iter = throwGenerator();
+assertThrows(function() { iter.throw(new Foo) }, Foo)
+assertThrows(function() { iter.throw(new Foo) }, Foo)
+assertIteratorIsClosed(iter);
+
+// Next on an executing iterator raises a TypeError.
+iter = nextGenerator();
+assertThrows(function() { iter.next() }, TypeError)
+assertIteratorIsClosed(iter);
+
+// Throw on an executing iterator raises a TypeError.
+iter = throwGenerator();
+assertThrows(function() { iter.next() }, TypeError)
+assertIteratorIsClosed(iter);
+
+// Next on an executing iterator doesn't change the state of the
+// generator.
+iter = (function* () {
+  try {
+    iter.next();
+    yield 1;
+  } catch (e) {
+    try {
+      // This next() should raise the same exception, because the first
+      // next() left the iter in the executing state.
+      iter.next();
+      yield 2;
+    } catch (e) {
+      yield 3;
+    }
+  }
+  yield 4;
+})();
+assertIteratorResult(3, false, iter.next());
+assertIteratorResult(4, false, iter.next());
+assertIteratorIsClosed(iter);
diff --git a/test/mjsunit/es6/json.js b/test/mjsunit/es6/json.js
new file mode 100644
index 0000000..3fad083
--- /dev/null
+++ b/test/mjsunit/es6/json.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-tostring
+
+function testJSONToString() {
+  assertEquals('[object JSON]', "" + JSON);
+  assertEquals("JSON", JSON[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(JSON, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("JSON", desc.value);
+}
+testJSONToString();
diff --git a/test/mjsunit/es6/math-log2-log10.js b/test/mjsunit/es6/math-log2-log10.js
index 4479894..fa3f468 100644
--- a/test/mjsunit/es6/math-log2-log10.js
+++ b/test/mjsunit/es6/math-log2-log10.js
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --allow-natives-syntax
+
 [Math.log10, Math.log2].forEach( function(fun) {
   assertTrue(isNaN(fun(NaN)));
   assertTrue(isNaN(fun(fun)));
@@ -39,7 +41,59 @@
   assertEquals("Infinity", String(fun(Infinity)));
 });
 
-for (var i = -300; i < 300; i += 0.7) {
-  assertEqualsDelta(i, Math.log10(Math.pow(10, i)), 1E-13);
-  assertEqualsDelta(i, Math.log2(Math.pow(2, i)), 1E-13);
+for (var i = -310; i <= 308; i += 0.5) {
+  assertEquals(i, Math.log10(Math.pow(10, i)));
+  // Square roots are tested below.
+  if (i != -0.5 && i != 0.5) assertEquals(i, Math.log2(Math.pow(2, i)));
+}
+
+// Test denormals.
+assertEquals(-307.77759430519706, Math.log10(1.5 * Math.pow(2, -1023)));
+
+// Test Math.log2(2^k) for -1074 <= k <= 1023.
+var n = -1074;
+// This loop covers n from -1074 to -1043
+for (var lowbits = 1; lowbits <= 0x80000000; lowbits *= 2) {
+  var x = %_ConstructDouble(0, lowbits);
+  assertEquals(n, Math.log2(x));
+  n++;
+}
+// This loop covers n from -1042 to -1023
+for (var hibits = 1; hibits <= 0x80000; hibits *= 2) {
+  var x = %_ConstructDouble(hibits, 0);
+  assertEquals(n, Math.log2(x));
+  n++;
+}
+// The rest of the normal values of 2^n
+var x = 1;
+for (var n = -1022; n <= 1023; ++n) {
+  var x = Math.pow(2, n);
+  assertEquals(n, Math.log2(x));
+}
+
+// Test special values.
+// Expectation isn't exactly 1/2 because Math.SQRT2 isn't exactly sqrt(2).
+assertEquals(0.5000000000000001, Math.log2(Math.SQRT2));
+
+// Expectation isn't exactly -1/2 because Math.SQRT1_2 isn't exactly sqrt(1/2).
+assertEquals(-0.4999999999999999, Math.log2(Math.SQRT1_2));
+
+assertEquals(3.321928094887362, Math.log2(10));
+assertEquals(6.643856189774724, Math.log2(100));
+
+// Test relationships
+x = 1;
+for (var k = 0; k < 1000; ++k) {
+  var y = Math.abs(Math.log2(x) + Math.log2(1/x));
+  assertEqualsDelta(0, y, 1.5e-14);
+  x *= 1.1;
+}
+
+x = Math.pow(2, -100);
+for (var k = 0; k < 1000; ++k) {
+  var y = Math.log2(x);
+  var expected = Math.log(x) / Math.LN2;
+  var err = Math.abs(y - expected) / expected;
+  assertEqualsDelta(0, err, 1e-15);
+  x *= 1.1;
 }
diff --git a/test/mjsunit/es6/math.js b/test/mjsunit/es6/math.js
new file mode 100644
index 0000000..3f76f11
--- /dev/null
+++ b/test/mjsunit/es6/math.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-tostring
+
+function testMathToString() {
+  assertEquals('[object Math]', "" + Math);
+  assertEquals("Math", Math[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(Math, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("Math", desc.value);
+}
+testMathToString();
diff --git a/test/mjsunit/es6/mirror-collections.js b/test/mjsunit/es6/mirror-collections.js
index e10f5c1..81a98b8 100644
--- a/test/mjsunit/es6/mirror-collections.js
+++ b/test/mjsunit/es6/mirror-collections.js
@@ -51,6 +51,7 @@
 map.delete(o1);
 var mapMirror = debug.MakeMirror(map);
 testMapMirror(mapMirror);
+
 var entries = mapMirror.entries();
 assertEquals(1, entries.length);
 assertSame(o2, entries[0].key);
@@ -59,6 +60,7 @@
 map.set(o3, o2);
 map.delete(o2);
 map.set(undefined, 44);
+
 entries = mapMirror.entries();
 assertEquals(3, entries.length);
 assertSame(o1, entries[0].key);
@@ -68,6 +70,10 @@
 assertEquals(undefined, entries[2].key);
 assertEquals(44, entries[2].value);
 
+assertEquals(3, mapMirror.entries(0).length);
+assertEquals(1, mapMirror.entries(1).length);
+assertEquals(2, mapMirror.entries(2).length);
+
 // Test the mirror object for Sets
 var set = new Set();
 set.add(o1);
@@ -78,6 +84,7 @@
 testSetMirror(setMirror);
 var values = setMirror.values();
 assertEquals(2, values.length);
+assertEquals(1, setMirror.values(1).length);
 assertSame(o2, values[0]);
 assertEquals(undefined, values[1]);
 
@@ -96,6 +103,8 @@
 function testWeakMapEntries(weakMapMirror) {
   var entries = weakMapMirror.entries();
   assertEquals(2, entries.length);
+  assertEquals(2, weakMapMirror.entries(0).length);
+  assertEquals(1, weakMapMirror.entries(1).length);
   var found = 0;
   for (var i = 0; i < entries.length; i++) {
     if (Object.is(entries[i].key, o1)) {
@@ -129,6 +138,8 @@
 function testWeakSetValues(weakSetMirror) {
   var values = weakSetMirror.values();
   assertEquals(2, values.length);
+  assertEquals(2, weakSetMirror.values(0).length);
+  assertEquals(1, weakSetMirror.values(1).length);
   var found = 0;
   for (var i = 0; i < values.length; i++) {
     if (Object.is(values[i], o1)) {
diff --git a/test/mjsunit/es6/mirror-iterators.js b/test/mjsunit/es6/mirror-iterators.js
new file mode 100644
index 0000000..22ce424
--- /dev/null
+++ b/test/mjsunit/es6/mirror-iterators.js
@@ -0,0 +1,103 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for collection iterators.
+
+function testIteratorMirror(iter, offset, expected, opt_limit) {
+  while (offset-- > 0) iter.next();
+
+  var mirror = debug.MakeMirror(iter);
+  assertTrue(mirror.isIterator());
+
+  var preview = mirror.preview(opt_limit);
+  assertArrayEquals(expected, preview);
+
+  // Check that iterator has not changed after taking preview.
+  var values = [];
+  for (var i of iter) {
+    if (opt_limit && values.length >= opt_limit) break;
+    values.push(i);
+  }
+  assertArrayEquals(expected, values);
+}
+
+function testIteratorInternalProperties(iter, offset, kind, index, has_more) {
+  while (offset-- > 0) iter.next();
+
+  var mirror = debug.MakeMirror(iter);
+  assertTrue(mirror.isIterator());
+
+  var properties = mirror.internalProperties();
+  assertEquals(3, properties.length);
+  assertEquals("[[IteratorHasMore]]", properties[0].name());
+  assertEquals(has_more, properties[0].value().value());
+  assertEquals("[[IteratorIndex]]", properties[1].name());
+  assertEquals(index, properties[1].value().value());
+  assertEquals("[[IteratorKind]]", properties[2].name());
+  assertEquals(kind, properties[2].value().value());
+}
+
+var o1 = { foo: 1 };
+var o2 = { foo: 2 };
+
+var map = new Map();
+map.set(41, 42);
+map.set(o1, o2);
+
+testIteratorMirror(map.keys(), 0, [41, o1]);
+testIteratorMirror(map.values(), 0, [42, o2]);
+testIteratorMirror(map.entries(), 0, [[41, 42], [o1, o2]]);
+
+testIteratorMirror(map.keys(), 1, [o1]);
+testIteratorMirror(map.values(), 1, [o2]);
+testIteratorMirror(map.entries(), 1, [[o1, o2]]);
+
+testIteratorMirror(map.keys(), 2, []);
+testIteratorMirror(map.values(), 2, []);
+testIteratorMirror(map.entries(), 2, []);
+
+// Test with maximum limit.
+testIteratorMirror(map.keys(), 0, [41], 1);
+testIteratorMirror(map.values(), 0, [42], 1);
+testIteratorMirror(map.entries(), 0, [[41, 42]], 1);
+
+testIteratorInternalProperties(map.keys(), 0, "keys", 0, true);
+testIteratorInternalProperties(map.values(), 1, "values", 1, true);
+testIteratorInternalProperties(map.entries(), 2, "entries", 2, false);
+testIteratorInternalProperties(map.keys(), 3, "keys", 2, false);
+
+var set = new Set();
+set.add(41);
+set.add(42);
+set.add(o1);
+set.add(o2);
+
+testIteratorMirror(set.keys(), 0, [41, 42, o1, o2]);
+testIteratorMirror(set.values(), 0, [41, 42, o1, o2]);
+testIteratorMirror(set.entries(), 0, [[41, 41], [42, 42], [o1, o1], [o2, o2]]);
+
+testIteratorMirror(set.keys(), 1, [42, o1, o2]);
+testIteratorMirror(set.values(), 1, [42, o1, o2]);
+testIteratorMirror(set.entries(), 1, [[42, 42], [o1, o1], [o2, o2]]);
+
+testIteratorMirror(set.keys(), 3, [o2]);
+testIteratorMirror(set.values(), 3, [o2]);
+testIteratorMirror(set.entries(), 3, [[o2, o2]]);
+
+testIteratorMirror(set.keys(), 5, []);
+testIteratorMirror(set.values(), 5, []);
+testIteratorMirror(set.entries(), 5, []);
+
+// Test with maximum limit.
+testIteratorMirror(set.keys(), 1, [42, o1], 2);
+testIteratorMirror(set.values(), 1, [42, o1], 2);
+testIteratorMirror(set.entries(), 1, [[42, 42], [o1, o1]], 2);
+
+testIteratorInternalProperties(set.keys(), 0, "values", 0, true);
+testIteratorInternalProperties(set.values(), 1, "values", 1, true);
+testIteratorInternalProperties(set.entries(), 2, "entries", 2, true);
+testIteratorInternalProperties(set.keys(), 3, "values", 3, true);
+testIteratorInternalProperties(set.values(), 4, "values", 4, false);
+testIteratorInternalProperties(set.entries(), 5, "entries", 4, false);
diff --git a/test/mjsunit/harmony/numeric-literals.js b/test/mjsunit/es6/numeric-literals.js
similarity index 100%
rename from test/mjsunit/harmony/numeric-literals.js
rename to test/mjsunit/es6/numeric-literals.js
diff --git a/test/mjsunit/es6/object-tostring.js b/test/mjsunit/es6/object-tostring.js
new file mode 100644
index 0000000..26dff14
--- /dev/null
+++ b/test/mjsunit/es6/object-tostring.js
@@ -0,0 +1,133 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-tostring
+
+var global = this;
+
+var funs = {
+  Object:   [ Object ],
+  Function: [ Function ],
+  Array:    [ Array ],
+  String:   [ String ],
+  Boolean:  [ Boolean ],
+  Number:   [ Number ],
+  Date:     [ Date ],
+  RegExp:   [ RegExp ],
+  Error:    [ Error, TypeError, RangeError, SyntaxError, ReferenceError,
+              EvalError, URIError ]
+}
+for (f in funs) {
+  for (i in funs[f]) {
+    assertEquals("[object " + f + "]",
+                 Object.prototype.toString.call(new funs[f][i]),
+                 funs[f][i]);
+    assertEquals("[object Function]",
+                 Object.prototype.toString.call(funs[f][i]),
+                 funs[f][i]);
+  }
+}
+
+function testToStringTag(className) {
+  // Using builtin toStringTags
+  var obj = {};
+  obj[Symbol.toStringTag] = className;
+  assertEquals("[object ~" + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // Getter throws
+  obj = {};
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { throw className; }
+  });
+  assertThrows(function() {
+    Object.prototype.toString.call(obj);
+  }, className);
+
+  // Getter does not throw
+  obj = {};
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { return className; }
+  });
+  assertEquals("[object ~" + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // Custom, non-builtin toStringTags
+  obj = {};
+  obj[Symbol.toStringTag] = "X" + className;
+  assertEquals("[object X" + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // With getter
+  obj = {};
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { return "X" + className; }
+  });
+  assertEquals("[object X" + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // Undefined toStringTag should return [object className]
+  var obj = className === "Arguments" ?
+      (function() { return arguments; })() : new global[className];
+  obj[Symbol.toStringTag] = undefined;
+  assertEquals("[object " + className + "]",
+               Object.prototype.toString.call(obj));
+
+  // With getter
+  var obj = className === "Arguments" ?
+      (function() { return arguments; })() : new global[className];
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { return undefined; }
+  });
+  assertEquals("[object " + className + "]",
+               Object.prototype.toString.call(obj));
+}
+
+[
+  "Arguments",
+  "Array",
+  "Boolean",
+  "Date",
+  "Error",
+  "Function",
+  "Number",
+  "RegExp",
+  "String"
+].forEach(testToStringTag);
+
+function testToStringTagNonString(value) {
+  var obj = {};
+  obj[Symbol.toStringTag] = value;
+  assertEquals("[object ???]", Object.prototype.toString.call(obj));
+
+  // With getter
+  obj = {};
+  Object.defineProperty(obj, Symbol.toStringTag, {
+    get: function() { return value; }
+  });
+  assertEquals("[object ???]", Object.prototype.toString.call(obj));
+}
+
+[
+  null,
+  function() {},
+  [],
+  {},
+  /regexp/,
+  42,
+  Symbol("sym"),
+  new Date(),
+  (function() { return arguments; })(),
+  true,
+  new Error("oops"),
+  new String("str")
+].forEach(testToStringTagNonString);
+
+function testObjectToStringPropertyDesc() {
+  var desc = Object.getOwnPropertyDescriptor(Object.prototype, "toString");
+  assertTrue(desc.writable);
+  assertFalse(desc.enumerable);
+  assertTrue(desc.configurable);
+}
+testObjectToStringPropertyDesc();
diff --git a/test/mjsunit/es6/promises.js b/test/mjsunit/es6/promises.js
index faf154e..04059aa 100644
--- a/test/mjsunit/es6/promises.js
+++ b/test/mjsunit/es6/promises.js
@@ -25,13 +25,21 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --allow-natives-syntax
+// Flags: --allow-natives-syntax --harmony-tostring
 
 // Make sure we don't rely on functions patchable by monkeys.
 var call = Function.prototype.call.call.bind(Function.prototype.call)
 var observe = Object.observe;
-var getOwnPropertyNames = Object.getOwnPropertyNames
-var defineProperty = Object.defineProperty
+var getOwnPropertyNames = Object.getOwnPropertyNames;
+var defineProperty = Object.defineProperty;
+
+
+(function() {
+  // Test before clearing global (fails otherwise)
+  assertEquals("[object Promise]",
+      Object.prototype.toString.call(new Promise(function() {})));
+})();
+
 
 function clear(o) {
   if (o === null || (typeof o !== 'object' && typeof o !== 'function')) return
diff --git a/test/mjsunit/es6/regress/regress-3902.js b/test/mjsunit/es6/regress/regress-3902.js
new file mode 100644
index 0000000..768a4a1
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-3902.js
@@ -0,0 +1,15 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function* g() {}
+assertTrue(Object.getOwnPropertyDescriptor(g.__proto__, "constructor").configurable);
+assertTrue(Object.getOwnPropertyDescriptor(g.prototype.__proto__, "constructor").configurable);
+
+function FakeGeneratorFunctionConstructor() {}
+Object.defineProperty(g.__proto__, "constructor", {value: FakeGeneratorFunctionConstructor});
+assertSame(g.__proto__.constructor, FakeGeneratorFunctionConstructor);
+
+function FakeGeneratorObjectConstructor() {}
+Object.defineProperty(g.prototype.__proto__, "constructor", {value: FakeGeneratorObjectConstructor});
+assertSame(g.prototype.__proto__.constructor, FakeGeneratorObjectConstructor);
diff --git a/test/mjsunit/es6/string-iterator.js b/test/mjsunit/es6/string-iterator.js
index e6bea6d..769f549 100644
--- a/test/mjsunit/es6/string-iterator.js
+++ b/test/mjsunit/es6/string-iterator.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Flags: --harmony-tostring
 
 function TestStringPrototypeIterator() {
   assertTrue(String.prototype.hasOwnProperty(Symbol.iterator));
@@ -59,6 +60,12 @@
   assertArrayEquals(['next'],
       Object.getOwnPropertyNames(StringIteratorPrototype));
   assertEquals('[object String Iterator]', "" + iterator);
+  assertEquals("String Iterator", StringIteratorPrototype[Symbol.toStringTag]);
+  var desc = Object.getOwnPropertyDescriptor(
+      StringIteratorPrototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.writable);
+  assertEquals("String Iterator", desc.value);
 }
 TestStringIteratorPrototype();
 
diff --git a/test/mjsunit/es6/symbols.js b/test/mjsunit/es6/symbols.js
index 60737af..b9811f5 100644
--- a/test/mjsunit/es6/symbols.js
+++ b/test/mjsunit/es6/symbols.js
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --expose-gc --allow-natives-syntax
+// Flags: --expose-gc --allow-natives-syntax --harmony-tostring
 
 var symbols = []
 
@@ -501,3 +501,11 @@
   assertSame("x3", Symbol.keyFor(symbol3))
 }
 TestRegistry()
+
+
+function TestGetOwnPropertySymbolsOnPrimitives() {
+  assertEquals(Object.getOwnPropertySymbols(true), []);
+  assertEquals(Object.getOwnPropertySymbols(5000), []);
+  assertEquals(Object.getOwnPropertySymbols("OK"), []);
+}
+TestGetOwnPropertySymbolsOnPrimitives();
diff --git a/test/mjsunit/es6/unscopables.js b/test/mjsunit/es6/unscopables.js
index 36365d2..03612be 100644
--- a/test/mjsunit/es6/unscopables.js
+++ b/test/mjsunit/es6/unscopables.js
@@ -143,6 +143,13 @@
     assertEquals(2, y);
     assertEquals(3, z);
   }
+
+  object[Symbol.unscopables] = {x: 0, y: undefined};
+  with (object) {
+    assertEquals(1, x);
+    assertEquals(5, y);
+    assertEquals(3, z);
+  }
 }
 runTest(TestBasics);
 
@@ -161,6 +168,13 @@
   with (object) {
     assertEquals(1, x);
   }
+
+  object[Symbol.unscopables] = {
+    __proto__: {x: undefined}
+  };
+  with (object) {
+    assertEquals(2, x);
+  }
 }
 runTest(TestUnscopableChain);
 
@@ -222,6 +236,14 @@
     assertEquals(5, y);
     assertEquals(3, z);
   }
+
+  proto[Symbol.unscopables] = {y: true};
+  object[Symbol.unscopables] = {x: true, y: undefined};
+  with (object) {
+    assertEquals(1, x);
+    assertEquals(5, y);
+    assertEquals(3, z);
+  }
 }
 runTest(TestOnProto);
 
@@ -341,6 +363,20 @@
 TestChangeDuringWithWithPossibleOptimization4({});
 
 
+function TestChangeDuringWithWithPossibleOptimization4(object) {
+  var x = 1;
+  object.x = 2;
+  object[Symbol.unscopables] = {x: true};
+  with (object) {
+    for (var i = 0; i < 1000; i++) {
+      if (i === 500) object[Symbol.unscopables].x = undefined;
+      assertEquals(i < 500 ? 1 : 2, x);
+    }
+  }
+}
+TestChangeDuringWithWithPossibleOptimization4({});
+
+
 function TestAccessorReceiver(object, proto) {
   var x = 'local';
 
@@ -532,9 +568,11 @@
   var x = 1;
   object.x = 2;
 
+  var calls = 0;
   var unscopables = {
     get x() {
-      assertUnreachable();
+      calls++;
+      return calls === 1 ? true : undefined;
     }
   };
 
@@ -542,7 +580,9 @@
     assertEquals(2, x);
     object[Symbol.unscopables] = unscopables;
     assertEquals(1, x);
+    assertEquals(2, x);
   }
+  assertEquals(2, calls);
 }
 runTest(TestAccessorOnUnscopables);
 
@@ -659,3 +699,25 @@
   }, CustomError);
 }
 TestGetUnscopablesGetterThrows();
+
+
+function TestGetUnscopablesGetterThrows2() {
+  var object = {
+    get x() {
+      assertUnreachable();
+    }
+  };
+  function CustomError() {}
+
+  object[Symbol.unscopables] = {
+    get x() {
+      throw new CustomError();
+    }
+  };
+  assertThrows(function() {
+    with (object) {
+      x;
+    }
+  }, CustomError);
+}
+TestGetUnscopablesGetterThrows();
diff --git a/test/mjsunit/es7/regress/regress-443982.js b/test/mjsunit/es7/regress/regress-443982.js
new file mode 100644
index 0000000..5a2e9cd
--- /dev/null
+++ b/test/mjsunit/es7/regress/regress-443982.js
@@ -0,0 +1,22 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var records;
+function observer(r) {
+  records = r;
+}
+
+Object.defineProperty(Array.prototype, '0', {
+  get: function() { return 0; },
+  set: function() { throw "boom!"; }
+});
+arr = [1, 2];
+Array.observe(arr, observer);
+arr.length = 0;
+assertEquals(0, arr.length);
+
+Object.deliverChangeRecords(observer);
+assertEquals(1, records.length);
+assertEquals('splice', records[0].type);
+assertArrayEquals([1, 2], records[0].removed);
diff --git a/test/mjsunit/fast-prototype.js b/test/mjsunit/fast-prototype.js
index 9864761..c59ec94 100644
--- a/test/mjsunit/fast-prototype.js
+++ b/test/mjsunit/fast-prototype.js
@@ -114,9 +114,9 @@
   assertTrue(key == 'a');
   break;
 }
-assertFalse(%HasFastProperties(x));
+assertTrue(%HasFastProperties(x));
 x.d = 4;
-assertFalse(%HasFastProperties(x));
+assertTrue(%HasFastProperties(x));
 for (key in x) {
   assertTrue(key == 'a');
   break;
diff --git a/test/mjsunit/function-call.js b/test/mjsunit/function-call.js
index 88df353..fb91dcd 100644
--- a/test/mjsunit/function-call.js
+++ b/test/mjsunit/function-call.js
@@ -162,13 +162,10 @@
 
   var exception = false;
   try {
-    // We call all functions with no parameters, which means that essential
-    // parameters will have the undefined value.
-    // The test for whether the "this" value is null or undefined is always
-    // performed before access to the other parameters, so even if the
-    // undefined value is an invalid argument value, it mustn't change
-    // the result of the test.
-    should_throw_on_null_and_undefined[i].call(null);
+    // We need to pass a dummy object argument ({}) to these functions because
+    // of Object.prototype.isPrototypeOf's special behavior, see issue 3483
+    // for more details.
+    should_throw_on_null_and_undefined[i].call(null, {});
   } catch (e) {
     exception = true;
     checkExpectedMessage(e);
@@ -177,7 +174,7 @@
 
   exception = false;
   try {
-    should_throw_on_null_and_undefined[i].call(undefined);
+    should_throw_on_null_and_undefined[i].call(undefined, {});
   } catch (e) {
     exception = true;
     checkExpectedMessage(e);
@@ -186,7 +183,7 @@
 
   exception = false;
   try {
-    should_throw_on_null_and_undefined[i].apply(null);
+    should_throw_on_null_and_undefined[i].apply(null, [{}]);
   } catch (e) {
     exception = true;
     checkExpectedMessage(e);
@@ -195,7 +192,7 @@
 
   exception = false;
   try {
-    should_throw_on_null_and_undefined[i].apply(undefined);
+    should_throw_on_null_and_undefined[i].apply(undefined, [{}]);
   } catch (e) {
     exception = true;
     checkExpectedMessage(e);
@@ -248,7 +245,9 @@
 
 // Test that we still throw when calling with thisArg null or undefined
 // through an array mapping function.
-var array = [1,2,3,4,5];
+// We need to make sure that the elements of `array` are all object values,
+// see issue 3483 for more details.
+var array = [{}, [], new Number, new Map, new WeakSet];
 for (var j = 0; j < mapping_functions.length; j++) {
   for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
     exception = false;
diff --git a/test/mjsunit/function-length-accessor.js b/test/mjsunit/function-length-accessor.js
index 357ac3f..97c9f65 100644
--- a/test/mjsunit/function-length-accessor.js
+++ b/test/mjsunit/function-length-accessor.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony-scoping
+// Flags: --harmony-scoping --lazy
 
 function foo(a, b, c, d) {
   "use strict"
diff --git a/test/mjsunit/getters-on-elements.js b/test/mjsunit/getters-on-elements.js
index 3bc360f..7f2c98b 100644
--- a/test/mjsunit/getters-on-elements.js
+++ b/test/mjsunit/getters-on-elements.js
@@ -176,7 +176,7 @@
           create_func_double,
           create_func_fast];
 
-for(var c = 0; c < 3; c++) {
+for(var c = 0; c < cf.length; c++) {
   base_getter_test(cf[c]);
 }
 
diff --git a/test/mjsunit/harmony/array-concat.js b/test/mjsunit/harmony/array-concat.js
new file mode 100644
index 0000000..286aefd
--- /dev/null
+++ b/test/mjsunit/harmony/array-concat.js
@@ -0,0 +1,686 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-arrays --harmony-classes
+
+(function testArrayConcatArity() {
+  "use strict";
+  assertEquals(1, Array.prototype.concat.length);
+})();
+
+
+(function testArrayConcatNoPrototype() {
+  "use strict";
+  assertEquals(void 0, Array.prototype.concat.prototype);
+})();
+
+
+(function testArrayConcatDescriptor() {
+  "use strict";
+  var desc = Object.getOwnPropertyDescriptor(Array.prototype, 'concat');
+  assertEquals(false, desc.enumerable);
+})();
+
+
+(function testConcatArrayLike() {
+  "use strict";
+  var obj = {
+    "length": 6,
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
+  var arr = ["X", "Y", "Z"];
+  assertEquals([void 0, "A", void 0, "B", void 0, "C",
+               { "length": 3, "0": "0", "1": "1", "2": "2" },
+               "X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr));
+})();
+
+
+(function testConcatArrayLikeStringLength() {
+  "use strict";
+  var obj = {
+    "length": "6",
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
+  var arr = ["X", "Y", "Z"];
+  assertEquals([void 0, "A", void 0, "B", void 0, "C",
+               { "length": 3, "0": "0", "1": "1", "2": "2" },
+               "X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr));
+})();
+
+
+(function testConcatArrayLikeNegativeLength() {
+  "use strict";
+  var obj = {
+    "length": -6,
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  assertEquals([], [].concat(obj));
+  obj.length = -6.7;
+  assertEquals([], [].concat(obj));
+  obj.length = "-6";
+  assertEquals([], [].concat(obj));
+})();
+
+
+(function testConcatArrayLikeToLengthThrows() {
+  "use strict";
+  var obj = {
+    "length": {valueOf: null, toString: null},
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
+  var arr = ["X", "Y", "Z"];
+  assertThrows(function() {
+    Array.prototype.concat.call(obj, obj2, arr);
+  }, TypeError);
+})();
+
+
+(function testConcatArrayLikePrimitiveNonNumberLength() {
+  "use strict";
+  var obj = {
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  obj.length = {toString: function() { return "SIX"; }, valueOf: null };
+  assertEquals([], [].concat(obj));
+  obj.length = {toString: null, valueOf: function() { return "SIX"; } };
+  assertEquals([], [].concat(obj));
+})();
+
+
+(function testConcatArrayLikeLengthToStringThrows() {
+  "use strict";
+  function MyError() {}
+  var obj = {
+    "length": { toString: function() {
+        throw new MyError();
+      }, valueOf: null
+    },
+    "1": "A",
+    "3": "B",
+    "5": "C"
+  };
+  obj[Symbol.isConcatSpreadable] = true;
+  assertThrows(function() {
+    [].concat(obj);
+  }, MyError);
+})();
+
+
+(function testConcatArrayLikeLengthValueOfThrows() {
+  "use strict";
+  function MyError() {}
+  var obj = {
+    "length": { valueOf: function() {
+      throw new MyError();
+    }, toString: null
+  },
+  "1": "A",
+  "3": "B",
+  "5": "C"
+};
+obj[Symbol.isConcatSpreadable] = true;
+assertThrows(function() {
+  [].concat(obj);
+}, MyError);
+})();
+
+
+(function testConcatHoleyArray() {
+  "use strict";
+  var arr = [];
+  arr[4] = "Item 4";
+  arr[8] = "Item 8";
+  var arr2 = [".", "!", "?"];
+  assertEquals([void 0, void 0, void 0, void 0, "Item 4", void 0, void 0,
+                void 0, "Item 8", ".", "!", "?"], arr.concat(arr2));
+})();
+
+
+(function testIsConcatSpreadableGetterThrows() {
+  "use strict";
+  function MyError() {}
+  var obj = {};
+  Object.defineProperty(obj, Symbol.isConcatSpreadable, {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    [].concat(obj);
+  }, MyError);
+
+  assertThrows(function() {
+    Array.prototype.concat.call(obj, 1, 2, 3);
+  }, MyError);
+})();
+
+
+(function testConcatLengthThrows() {
+  "use strict";
+  function MyError() {}
+  var obj = {};
+  obj[Symbol.isConcatSpreadable] = true;
+  Object.defineProperty(obj, "length", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    [].concat(obj);
+  }, MyError);
+
+  assertThrows(function() {
+    Array.prototype.concat.call(obj, 1, 2, 3);
+  }, MyError);
+})();
+
+
+(function testConcatArraySubclass() {
+  "use strict";
+  // TODO(caitp): when concat is called on instances of classes which extend
+  // Array, they should:
+  //
+  // - return an instance of the class, rather than an Array instance (if from
+  //   same Realm)
+  // - always treat such classes as concat-spreadable
+})();
+
+
+(function testConcatNonArray() {
+  "use strict";
+  class NonArray {
+    constructor() { Array.apply(this, arguments); }
+  };
+
+  var obj = new NonArray(1,2,3);
+  var result = Array.prototype.concat.call(obj, 4, 5, 6);
+  assertEquals(Array, result.constructor);
+  assertEquals([obj,4,5,6], result);
+  assertFalse(result instanceof NonArray);
+})();
+
+
+function testConcatTypedArray(type, elems, modulo) {
+  "use strict";
+  var items = new Array(elems);
+  var ta_by_len = new type(elems);
+  for (var i = 0; i < elems; ++i) {
+    ta_by_len[i] = items[i] = modulo === false ? i : elems % modulo;
+  }
+  var ta = new type(items);
+  assertEquals([ta, ta], [].concat(ta, ta));
+  ta[Symbol.isConcatSpreadable] = true;
+  assertEquals(items, [].concat(ta));
+
+  assertEquals([ta_by_len, ta_by_len], [].concat(ta_by_len, ta_by_len));
+  ta_by_len[Symbol.isConcatSpreadable] = true;
+  assertEquals(items, [].concat(ta_by_len));
+
+  // TypedArray with fake `length`.
+  ta = new type(1);
+  var defValue = ta[0];
+  var expected = new Array(4000);
+  expected[0] = defValue;
+
+  Object.defineProperty(ta, "length", { value: 4000 });
+  ta[Symbol.isConcatSpreadable] = true;
+  assertEquals(expected, [].concat(ta));
+}
+
+(function testConcatSmallTypedArray() {
+  var max = [2^8, 2^16, 2^32, false, false];
+  [
+    Uint8Array,
+    Uint16Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array
+  ].forEach(function(ctor, i) {
+    testConcatTypedArray(ctor, 1, max[i]);
+  });
+})();
+
+
+(function testConcatLargeTypedArray() {
+  var max = [2^8, 2^16, 2^32, false, false];
+  [
+    Uint8Array,
+    Uint16Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array
+  ].forEach(function(ctor, i) {
+    testConcatTypedArray(ctor, 4000, max[i]);
+  });
+})();
+
+
+(function testConcatStrictArguments() {
+  var args = (function(a, b, c) { "use strict"; return arguments; })(1,2,3);
+  args[Symbol.isConcatSpreadable] = true;
+  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
+
+  Object.defineProperty(args, "length", { value: 6 });
+  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
+})();
+
+
+(function testConcatSloppyArguments() {
+  var args = (function(a, b, c) { return arguments; })(1,2,3);
+  args[Symbol.isConcatSpreadable] = true;
+  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
+
+  Object.defineProperty(args, "length", { value: 6 });
+  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
+})();
+
+
+(function testConcatSloppyArgumentsWithDupes() {
+  var args = (function(a, a, a) { return arguments; })(1,2,3);
+  args[Symbol.isConcatSpreadable] = true;
+  assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
+
+  Object.defineProperty(args, "length", { value: 6 });
+  assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
+})();
+
+
+(function testConcatSloppyArgumentsThrows() {
+  function MyError() {}
+  var args = (function(a) { return arguments; })(1,2,3);
+  Object.defineProperty(args, 0, {
+    get: function() { throw new MyError(); }
+  });
+  args[Symbol.isConcatSpreadable] = true;
+  assertThrows(function() {
+    return [].concat(args, args);
+  }, MyError);
+})();
+
+
+(function testConcatHoleySloppyArguments() {
+  var args = (function(a) { return arguments; })(1,2,3);
+  delete args[1];
+  args[Symbol.isConcatSpreadable] = true;
+  assertEquals([1, void 0, 3, 1, void 0, 3], [].concat(args, args));
+})();
+
+
+(function testConcatSpreadableStringWrapper() {
+  "use strict";
+  var str1 = new String("yuck\uD83D\uDCA9")
+  // String wrapper objects are not concat-spreadable by default
+  assertEquals([str1], [].concat(str1));
+
+  // String wrapper objects may be individually concat-spreadable
+  str1[Symbol.isConcatSpreadable] = true;
+  assertEquals(["y", "u", "c", "k", "\uD83D", "\uDCA9"],
+               [].concat(str1));
+
+  String.prototype[Symbol.isConcatSpreadable] = true;
+  // String wrapper objects may be concat-spreadable
+  assertEquals(["y", "u", "c", "k", "\uD83D", "\uDCA9"],
+               [].concat(new String("yuck\uD83D\uDCA9")));
+
+  // String values are never concat-spreadable
+  assertEquals(["yuck\uD83D\uDCA9"], [].concat("yuck\uD83D\uDCA9"));
+  delete String.prototype[Symbol.isConcatSpreadable];
+})();
+
+
+(function testConcatSpreadableBooleanWrapper() {
+  "use strict";
+  var bool = new Boolean(true)
+  // Boolean wrapper objects are not concat-spreadable by default
+  assertEquals([bool], [].concat(bool));
+
+  // Boolean wrapper objects may be individually concat-spreadable
+  bool[Symbol.isConcatSpreadable] = true;
+  bool.length = 3;
+  bool[0] = 1, bool[1] = 2, bool[2] = 3;
+  assertEquals([1, 2, 3], [].concat(bool));
+
+  Boolean.prototype[Symbol.isConcatSpreadable] = true;
+  // Boolean wrapper objects may be concat-spreadable
+  assertEquals([], [].concat(new Boolean(true)));
+  Boolean.prototype[0] = 1;
+  Boolean.prototype[1] = 2;
+  Boolean.prototype[2] = 3;
+  Boolean.prototype.length = 3;
+  assertEquals([1,2,3], [].concat(new Boolean(true)));
+
+  // Boolean values are never concat-spreadable
+  assertEquals([true], [].concat(true));
+  delete Boolean.prototype[Symbol.isConcatSpreadable];
+  delete Boolean.prototype[0];
+  delete Boolean.prototype[1];
+  delete Boolean.prototype[2];
+  delete Boolean.prototype.length;
+})();
+
+
+(function testConcatSpreadableNumberWrapper() {
+  "use strict";
+  var num = new Number(true)
+  // Number wrapper objects are not concat-spreadable by default
+  assertEquals([num], [].concat(num));
+
+  // Number wrapper objects may be individually concat-spreadable
+  num[Symbol.isConcatSpreadable] = true;
+  num.length = 3;
+  num[0] = 1, num[1] = 2, num[2] = 3;
+  assertEquals([1, 2, 3], [].concat(num));
+
+  Number.prototype[Symbol.isConcatSpreadable] = true;
+  // Number wrapper objects may be concat-spreadable
+  assertEquals([], [].concat(new Number(123)));
+  Number.prototype[0] = 1;
+  Number.prototype[1] = 2;
+  Number.prototype[2] = 3;
+  Number.prototype.length = 3;
+  assertEquals([1,2,3], [].concat(new Number(123)));
+
+  // Number values are never concat-spreadable
+  assertEquals([true], [].concat(true));
+  delete Number.prototype[Symbol.isConcatSpreadable];
+  delete Number.prototype[0];
+  delete Number.prototype[1];
+  delete Number.prototype[2];
+  delete Number.prototype.length;
+})();
+
+
+(function testConcatSpreadableFunction() {
+  "use strict";
+  var fn = function(a, b, c) {}
+  // Functions are not concat-spreadable by default
+  assertEquals([fn], [].concat(fn));
+
+  // Functions may be individually concat-spreadable
+  fn[Symbol.isConcatSpreadable] = true;
+  fn[0] = 1, fn[1] = 2, fn[2] = 3;
+  assertEquals([1, 2, 3], [].concat(fn));
+
+  Function.prototype[Symbol.isConcatSpreadable] = true;
+  // Functions may be concat-spreadable
+  assertEquals([void 0, void 0, void 0], [].concat(function(a,b,c) {}));
+  Function.prototype[0] = 1;
+  Function.prototype[1] = 2;
+  Function.prototype[2] = 3;
+  assertEquals([1,2,3], [].concat(function(a, b, c) {}));
+
+  delete Function.prototype[Symbol.isConcatSpreadable];
+  delete Function.prototype[0];
+  delete Function.prototype[1];
+  delete Function.prototype[2];
+})();
+
+
+(function testConcatSpreadableRegExp() {
+  "use strict";
+  var re = /abc/;
+  // RegExps are not concat-spreadable by default
+  assertEquals([re], [].concat(re));
+
+  // RegExps may be individually concat-spreadable
+  re[Symbol.isConcatSpreadable] = true;
+  re[0] = 1, re[1] = 2, re[2] = 3, re.length = 3;
+  assertEquals([1, 2, 3], [].concat(re));
+
+  // RegExps may be concat-spreadable
+  RegExp.prototype[Symbol.isConcatSpreadable] = true;
+  RegExp.prototype.length = 3;
+
+  assertEquals([void 0, void 0, void 0], [].concat(/abc/));
+  RegExp.prototype[0] = 1;
+  RegExp.prototype[1] = 2;
+  RegExp.prototype[2] = 3;
+  assertEquals([1,2,3], [].concat(/abc/));
+
+  delete RegExp.prototype[Symbol.isConcatSpreadable];
+  delete RegExp.prototype[0];
+  delete RegExp.prototype[1];
+  delete RegExp.prototype[2];
+  delete RegExp.prototype.length;
+})();
+
+
+(function testArrayConcatSpreadableSparseObject() {
+  "use strict";
+  var obj = { length: 5 };
+  obj[Symbol.isConcatSpreadable] = true;
+  assertEquals([void 0, void 0, void 0, void 0, void 0], [].concat(obj));
+
+  obj.length = 4000;
+  assertEquals(new Array(4000), [].concat(obj));
+})();
+
+
+// ES5 tests
+(function testArrayConcatES5() {
+  "use strict";
+  var poses;
+  var pos;
+
+  poses = [140, 4000000000];
+  while (pos = poses.shift()) {
+    var a = new Array(pos);
+    var array_proto = [];
+    a.__proto__ = array_proto;
+    assertEquals(pos, a.length);
+    a.push('foo');
+    assertEquals(pos + 1, a.length);
+    var b = ['bar'];
+    var c = a.concat(b);
+    assertEquals(pos + 2, c.length);
+    assertEquals("undefined", typeof(c[pos - 1]));
+    assertEquals("foo", c[pos]);
+    assertEquals("bar", c[pos + 1]);
+
+    // Can we fool the system by putting a number in a string?
+    var onetwofour = "124";
+    a[onetwofour] = 'doo';
+    assertEquals(a[124], 'doo');
+    c = a.concat(b);
+    assertEquals(c[124], 'doo');
+
+    // If we put a number in the prototype, then the spec says it should be
+    // copied on concat.
+    array_proto["123"] = 'baz';
+    assertEquals(a[123], 'baz');
+
+    c = a.concat(b);
+    assertEquals(pos + 2, c.length);
+    assertEquals("baz", c[123]);
+    assertEquals("undefined", typeof(c[pos - 1]));
+    assertEquals("foo", c[pos]);
+    assertEquals("bar", c[pos + 1]);
+
+    // When we take the number off the prototype it disappears from a, but
+    // the concat put it in c itself.
+    array_proto["123"] = undefined;
+    assertEquals("undefined", typeof(a[123]));
+    assertEquals("baz", c[123]);
+
+    // If the element of prototype is shadowed, the element on the instance
+    // should be copied, but not the one on the prototype.
+    array_proto[123] = 'baz';
+    a[123] = 'xyz';
+    assertEquals('xyz', a[123]);
+    c = a.concat(b);
+    assertEquals('xyz', c[123]);
+
+    // Non-numeric properties on the prototype or the array shouldn't get
+    // copied.
+    array_proto.moe = 'joe';
+    a.ben = 'jerry';
+    assertEquals(a["moe"], 'joe');
+    assertEquals(a["ben"], 'jerry');
+    c = a.concat(b);
+    // ben was not copied
+    assertEquals("undefined", typeof(c.ben));
+
+    // When we take moe off the prototype it disappears from all arrays.
+    array_proto.moe = undefined;
+    assertEquals("undefined", typeof(c.moe));
+
+    // Negative indices don't get concated.
+    a[-1] = 'minus1';
+    assertEquals("minus1", a[-1]);
+    assertEquals("undefined", typeof(a[0xffffffff]));
+    c = a.concat(b);
+    assertEquals("undefined", typeof(c[-1]));
+    assertEquals("undefined", typeof(c[0xffffffff]));
+    assertEquals(c.length, a.length + 1);
+  }
+
+  poses = [140, 4000000000];
+  while (pos = poses.shift()) {
+    var a = new Array(pos);
+    assertEquals(pos, a.length);
+    a.push('foo');
+    assertEquals(pos + 1, a.length);
+    var b = ['bar'];
+    var c = a.concat(b);
+    assertEquals(pos + 2, c.length);
+    assertEquals("undefined", typeof(c[pos - 1]));
+    assertEquals("foo", c[pos]);
+    assertEquals("bar", c[pos + 1]);
+
+    // Can we fool the system by putting a number in a string?
+    var onetwofour = "124";
+    a[onetwofour] = 'doo';
+    assertEquals(a[124], 'doo');
+    c = a.concat(b);
+    assertEquals(c[124], 'doo');
+
+    // If we put a number in the prototype, then the spec says it should be
+    // copied on concat.
+    Array.prototype["123"] = 'baz';
+    assertEquals(a[123], 'baz');
+
+    c = a.concat(b);
+    assertEquals(pos + 2, c.length);
+    assertEquals("baz", c[123]);
+    assertEquals("undefined", typeof(c[pos - 1]));
+    assertEquals("foo", c[pos]);
+    assertEquals("bar", c[pos + 1]);
+
+    // When we take the number off the prototype it disappears from a, but
+    // the concat put it in c itself.
+    Array.prototype["123"] = undefined;
+    assertEquals("undefined", typeof(a[123]));
+    assertEquals("baz", c[123]);
+
+    // If the element of prototype is shadowed, the element on the instance
+    // should be copied, but not the one on the prototype.
+    Array.prototype[123] = 'baz';
+    a[123] = 'xyz';
+    assertEquals('xyz', a[123]);
+    c = a.concat(b);
+    assertEquals('xyz', c[123]);
+
+    // Non-numeric properties on the prototype or the array shouldn't get
+    // copied.
+    Array.prototype.moe = 'joe';
+    a.ben = 'jerry';
+    assertEquals(a["moe"], 'joe');
+    assertEquals(a["ben"], 'jerry');
+    c = a.concat(b);
+    // ben was not copied
+    assertEquals("undefined", typeof(c.ben));
+    // moe was not copied, but we can see it through the prototype
+    assertEquals("joe", c.moe);
+
+    // When we take moe off the prototype it disappears from all arrays.
+    Array.prototype.moe = undefined;
+    assertEquals("undefined", typeof(c.moe));
+
+    // Negative indices don't get concated.
+    a[-1] = 'minus1';
+    assertEquals("minus1", a[-1]);
+    assertEquals("undefined", typeof(a[0xffffffff]));
+    c = a.concat(b);
+    assertEquals("undefined", typeof(c[-1]));
+    assertEquals("undefined", typeof(c[0xffffffff]));
+    assertEquals(c.length, a.length + 1);
+
+  }
+
+  a = [];
+  c = a.concat('Hello');
+  assertEquals(1, c.length);
+  assertEquals("Hello", c[0]);
+  assertEquals("Hello", c.toString());
+
+  // Check that concat preserves holes.
+  var holey = [void 0,'a',,'c'].concat(['d',,'f',[0,,2],void 0])
+  assertEquals(9, holey.length);  // hole in embedded array is ignored
+  for (var i = 0; i < holey.length; i++) {
+    if (i == 2 || i == 5) {
+      assertFalse(i in holey);
+    } else {
+      assertTrue(i in holey);
+    }
+  }
+
+  // Polluted prototype from prior tests.
+  delete Array.prototype[123];
+
+  // Check that concat reads getters in the correct order.
+  var arr1 = [,2];
+  var arr2 = [1,3];
+  var r1 = [].concat(arr1, arr2);  // [,2,1,3]
+  assertEquals([,2,1,3], r1);
+
+  // Make first array change length of second array.
+  Object.defineProperty(arr1, 0, {get: function() {
+        arr2.push("X");
+        return undefined;
+      }, configurable: true})
+  var r2 = [].concat(arr1, arr2);  // [undefined,2,1,3,"X"]
+  assertEquals([undefined,2,1,3,"X"], r2);
+
+  // Make first array change length of second array massively.
+  arr2.length = 2;
+  Object.defineProperty(arr1, 0, {get: function() {
+        arr2[500000] = "X";
+        return undefined;
+      }, configurable: true})
+  var r3 = [].concat(arr1, arr2);  // [undefined,2,1,3,"X"]
+  var expected = [undefined,2,1,3];
+  expected[500000 + 2] = "X";
+
+  assertEquals(expected, r3);
+
+  var arr3 = [];
+  var trace = [];
+  var expectedTrace = []
+  function mkGetter(i) { return function() { trace.push(i); }; }
+  arr3.length = 10000;
+  for (var i = 0; i < 100; i++) {
+    Object.defineProperty(arr3, i * i, {get: mkGetter(i)});
+    expectedTrace[i] = i;
+    expectedTrace[100 + i] = i;
+  }
+  var r4 = [0].concat(arr3, arr3);
+  assertEquals(1 + arr3.length * 2, r4.length);
+  assertEquals(expectedTrace, trace);
+})();
diff --git a/test/mjsunit/harmony/array-find.js b/test/mjsunit/harmony/array-find.js
index 9f5750e..eb32082 100644
--- a/test/mjsunit/harmony/array-find.js
+++ b/test/mjsunit/harmony/array-find.js
@@ -237,6 +237,24 @@
     return this.elementAt(key) === val;
   }, thisArg);
   assertEquals("b", found);
+
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].find(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].find(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].find(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 // Test exceptions
diff --git a/test/mjsunit/harmony/array-findindex.js b/test/mjsunit/harmony/array-findindex.js
index a33849d..a5df05a 100644
--- a/test/mjsunit/harmony/array-findindex.js
+++ b/test/mjsunit/harmony/array-findindex.js
@@ -237,6 +237,24 @@
     return this.elementAt(key) === val;
   }, thisArg);
   assertEquals(1, index);
+
+  // Create a new object in each function call when receiver is a
+  // primitive value. See ECMA-262, Annex C.
+  a = [];
+  [1, 2].findIndex(function() { a.push(this) }, "");
+  assertTrue(a[0] !== a[1]);
+
+  // Do not create a new object otherwise.
+  a = [];
+  [1, 2].findIndex(function() { a.push(this) }, {});
+  assertEquals(a[0], a[1]);
+
+  // In strict mode primitive values should not be coerced to an object.
+  a = [];
+  [1, 2].findIndex(function() { 'use strict'; a.push(this); }, "");
+  assertEquals("", a[0]);
+  assertEquals(a[0], a[1]);
+
 })();
 
 // Test exceptions
diff --git a/test/mjsunit/harmony/array-from.js b/test/mjsunit/harmony/array-from.js
new file mode 100644
index 0000000..e7c9fef
--- /dev/null
+++ b/test/mjsunit/harmony/array-from.js
@@ -0,0 +1,123 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-arrays --harmony-generators
+(function() {
+
+assertEquals(1, Array.from.length);
+
+function assertArrayLikeEquals(value, expected, type) {
+  assertInstanceof(value, type);
+  assertEquals(expected.length, value.length);
+  for (var i=0; i<value.length; ++i) {
+    assertEquals(expected[i], value[i]);
+  }
+}
+
+// Assert that constructor is called with "length" for array-like objects
+var myCollectionCalled = false;
+function MyCollection(length) {
+  myCollectionCalled = true;
+  assertEquals(1, arguments.length);
+  assertEquals(5, length);
+}
+
+Array.from.call(MyCollection, {length: 5});
+assertTrue(myCollectionCalled);
+
+// Assert that calling mapfn with / without thisArg in sloppy and strict modes
+// works as expected.
+var global = this;
+function non_strict(){ assertEquals(global, this); }
+function strict(){ "use strict"; assertEquals(void 0, this); }
+function strict_null(){ "use strict"; assertEquals(null, this); }
+Array.from([1], non_strict);
+Array.from([1], non_strict, void 0);
+Array.from([1], non_strict, null);
+Array.from([1], strict);
+Array.from([1], strict, void 0);
+Array.from([1], strict_null, null);
+
+function testArrayFrom(thisArg, constructor) {
+  assertArrayLikeEquals(Array.from.call(thisArg, [], undefined), [],
+      constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, NaN), [], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, Infinity), [], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, 10000000), [], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, 'test'), ['t', 'e', 's', 't'],
+      constructor);
+
+  assertArrayLikeEquals(Array.from.call(thisArg,
+      { length: 1, '0': { 'foo': 'bar' } }), [{'foo': 'bar'}], constructor);
+
+  assertArrayLikeEquals(Array.from.call(thisArg,
+      { length: -1, '0': { 'foo': 'bar' } }), [], constructor);
+
+  assertArrayLikeEquals(Array.from.call(thisArg,
+      [ 'foo', 'bar', 'baz' ]), ['foo', 'bar', 'baz'], constructor);
+
+  var kSet = new Set(['foo', 'bar', 'baz']);
+  assertArrayLikeEquals(Array.from.call(thisArg, kSet), ['foo', 'bar', 'baz'],
+      constructor);
+
+  var kMap = new Map(['foo', 'bar', 'baz'].entries());
+  assertArrayLikeEquals(Array.from.call(thisArg, kMap),
+      [[0, 'foo'], [1, 'bar'], [2, 'baz']], constructor);
+
+
+  function* generator() {
+    yield 'a';
+    yield 'b';
+    yield 'c';
+  }
+
+  assertArrayLikeEquals(Array.from.call(thisArg, generator()),
+                        ['a', 'b', 'c'], constructor);
+
+  // Mozilla:
+  // Array.from on a string handles surrogate pairs correctly.
+  var gclef = "\uD834\uDD1E"; // U+1D11E MUSICAL SYMBOL G CLEF
+  assertArrayLikeEquals(Array.from.call(thisArg, gclef), [gclef], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, gclef + " G"),
+      [gclef, " ", "G"], constructor);
+
+  assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) {
+    return this.filter(x);
+  }, {
+    filter: function(x) { return x.toUpperCase(); }
+  }), ['T', 'E', 'S', 'T'], constructor);
+  assertArrayLikeEquals(Array.from.call(thisArg, 'test', function(x) {
+    return x.toUpperCase();
+  }), ['T', 'E', 'S', 'T'], constructor);
+
+  this.thisArg = thisArg;
+  assertThrows('Array.from.call(thisArg, null)', TypeError);
+  assertThrows('Array.from.call(thisArg, undefined)', TypeError);
+  assertThrows('Array.from.call(thisArg, [], null)', TypeError);
+  assertThrows('Array.from.call(thisArg, [], "noncallable")', TypeError);
+
+  this.nullIterator = {};
+  nullIterator[Symbol.iterator] = null;
+  assertThrows('Array.from.call(thisArg, nullIterator)', TypeError);
+
+  this.nonObjIterator = {};
+  nonObjIterator[Symbol.iterator] = function() { return "nonObject"; };
+  assertThrows('Array.from.call(thisArg, nonObjIterator)', TypeError);
+
+  assertThrows('Array.from.call(thisArg, [], null)', TypeError);
+}
+
+function Other() {}
+
+var boundFn = (function() {}).bind(Array, 27);
+
+testArrayFrom(Array, Array);
+testArrayFrom(null, Array);
+testArrayFrom({}, Array);
+testArrayFrom(Object, Object);
+testArrayFrom(Other, Other);
+testArrayFrom(Math.cos, Array);
+testArrayFrom(boundFn, Array);
+
+})();
diff --git a/test/mjsunit/harmony/array-includes-to-object-sloppy.js b/test/mjsunit/harmony/array-includes-to-object-sloppy.js
new file mode 100644
index 0000000..0f5d731
--- /dev/null
+++ b/test/mjsunit/harmony/array-includes-to-object-sloppy.js
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-array-includes
+
+// Ported from
+// https://github.com/tc39/Array.prototype.includes/blob/master/test/number-this.js
+// using https://www.npmjs.org/package/test262-to-mjsunit
+
+// Array.prototype.includes should use ToObject on this, so that when called
+// with a number, it picks up numeric properties from Number.prototype
+(function() {
+  Number.prototype[0] = "a";
+  Number.prototype[1] = "b";
+
+  Object.defineProperty(Number.prototype, 2, {
+    get: function() {
+      assertEquals("object", typeof this);
+      return "c";
+    }
+  });
+
+  Number.prototype.length = 3;
+  assertTrue(Array.prototype.includes.call(5, "a"));
+  assertTrue(Array.prototype.includes.call(5, "b"));
+  assertTrue(Array.prototype.includes.call(5, "c"));
+  assertFalse(Array.prototype.includes.call(5, "d"));
+})();
diff --git a/test/mjsunit/harmony/array-includes-to-object-strict.js b/test/mjsunit/harmony/array-includes-to-object-strict.js
new file mode 100644
index 0000000..ee87136
--- /dev/null
+++ b/test/mjsunit/harmony/array-includes-to-object-strict.js
@@ -0,0 +1,32 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-array-includes
+
+// Ported from
+// https://github.com/tc39/Array.prototype.includes/blob/master/test/number-this.js
+// using https://www.npmjs.org/package/test262-to-mjsunit
+
+// Array.prototype.includes should use ToObject on this, so that when called
+// with a number, it picks up numeric properties from Number.prototype (even in
+// strict mode)
+(function() {
+  "use strict";
+
+  Number.prototype[0] = "a";
+  Number.prototype[1] = "b";
+
+  Object.defineProperty(Number.prototype, 2, {
+    get: function() {
+      assertEquals("object", typeof this);
+      return "c";
+    }
+  });
+
+  Number.prototype.length = 3;
+  assertTrue(Array.prototype.includes.call(5, "a"));
+  assertTrue(Array.prototype.includes.call(5, "b"));
+  assertTrue(Array.prototype.includes.call(5, "c"));
+  assertFalse(Array.prototype.includes.call(5, "d"));
+})();
diff --git a/test/mjsunit/harmony/array-includes.js b/test/mjsunit/harmony/array-includes.js
new file mode 100644
index 0000000..2cdd112
--- /dev/null
+++ b/test/mjsunit/harmony/array-includes.js
@@ -0,0 +1,677 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-array-includes
+
+// Largely ported from
+// https://github.com/tc39/Array.prototype.includes/tree/master/test
+// using https://www.npmjs.org/package/test262-to-mjsunit with further edits
+
+
+// Array.prototype.includes sees a new element added by a getter that is hit
+// during iteration
+(function() {
+  var arrayLike = {
+    length: 5,
+    0: "a",
+
+    get 1() {
+      this[2] = "c";
+      return "b";
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "c"));
+})();
+
+
+// Array.prototype.includes works on array-like objects
+(function() {
+  var arrayLike1 = {
+    length: 5,
+    0: "a",
+    1: "b"
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike1, "a"));
+  assertFalse(Array.prototype.includes.call(arrayLike1, "c"));
+
+  var arrayLike2 = {
+    length: 2,
+    0: "a",
+    1: "b",
+    2: "c"
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike2, "b"));
+  assertFalse(Array.prototype.includes.call(arrayLike2, "c"));
+})();
+
+
+// Array.prototype.includes should fail if used on a null or undefined this
+(function() {
+  assertThrows(function() {
+    Array.prototype.includes.call(null, "a");
+  }, TypeError);
+
+  assertThrows(function() {
+    Array.prototype.includes.call(undefined, "a");
+  }, TypeError);
+})();
+
+
+// Array.prototype.includes should terminate if getting an index throws an
+// exception
+(function() {
+  function Test262Error() {}
+
+  var trappedZero = {
+    length: 2,
+
+    get 0() {
+      throw new Test262Error();
+    },
+
+    get 1() {
+      assertUnreachable("Should not try to get the first element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(trappedZero, "a");
+  }, Test262Error);
+})();
+
+
+// Array.prototype.includes should terminate if ToNumber ends up being called on
+// a symbol fromIndex
+(function() {
+  var trappedZero = {
+    length: 1,
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(trappedZero, "a", Symbol());
+  }, TypeError);
+})();
+
+
+// Array.prototype.includes should terminate if an exception occurs converting
+// the fromIndex to a number
+(function() {
+  function Test262Error() {}
+
+  var fromIndex = {
+    valueOf: function() {
+      throw new Test262Error();
+    }
+  };
+
+  var trappedZero = {
+    length: 1,
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(trappedZero, "a", fromIndex);
+  }, Test262Error);
+})();
+
+
+// Array.prototype.includes should terminate if an exception occurs getting the
+// length
+(function() {
+  function Test262Error() {}
+
+  var fromIndexTrap = {
+    valueOf: function() {
+      assertUnreachable("Should not try to call ToInteger on valueOf");
+    }
+  };
+
+  var throwingLength = {
+    get length() {
+      throw new Test262Error();
+    },
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(throwingLength, "a", fromIndexTrap);
+  }, Test262Error);
+})();
+
+
+// Array.prototype.includes should terminate if ToLength ends up being called on
+// a symbol length
+(function() {
+  var fromIndexTrap = {
+    valueOf: function() {
+      assertUnreachable("Should not try to call ToInteger on valueOf");
+    }
+  };
+
+  var badLength = {
+    length: Symbol(),
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(badLength, "a", fromIndexTrap);
+  }, TypeError);
+})();
+
+
+// Array.prototype.includes should terminate if an exception occurs converting
+// the length to a number
+(function() {
+  function Test262Error() {}
+
+  var fromIndexTrap = {
+    valueOf: function() {
+      assertUnreachable("Should not try to call ToInteger on valueOf");
+    }
+  };
+
+  var badLength = {
+    length: {
+      valueOf: function() {
+        throw new Test262Error();
+      }
+    },
+
+    get 0() {
+      assertUnreachable("Should not try to get the zeroth element");
+    }
+  };
+
+  assertThrows(function() {
+    Array.prototype.includes.call(badLength, "a", fromIndexTrap);
+  }, Test262Error);
+})();
+
+
+// Array.prototype.includes should search the whole array, as the optional
+// second argument fromIndex defaults to 0
+(function() {
+  assertTrue([10, 11].includes(10));
+  assertTrue([10, 11].includes(11));
+
+  var arrayLike = {
+    length: 2,
+
+    get 0() {
+      return "1";
+    },
+
+    get 1() {
+      return "2";
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "1"));
+  assertTrue(Array.prototype.includes.call(arrayLike, "2"));
+})();
+
+
+// Array.prototype.includes returns false if fromIndex is greater or equal to
+// the length of the array
+(function() {
+  assertFalse([1, 2].includes(2, 3));
+  assertFalse([1, 2].includes(2, 2));
+
+  var arrayLikeWithTrap = {
+    length: 2,
+
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    },
+
+    get 1() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, "c", 2));
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, "c", 3));
+})();
+
+
+// Array.prototype.includes searches the whole array if the computed index from
+// the given negative fromIndex argument is less than 0
+(function() {
+  assertTrue([1, 3].includes(1, -4));
+  assertTrue([1, 3].includes(3, -4));
+
+  var arrayLike = {
+    length: 2,
+    0: "a",
+
+    get 1() {
+      return "b";
+    },
+
+    get "-1"() {
+      assertUnreachable("Should not try to get the element at index -1");
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "a", -4));
+  assertTrue(Array.prototype.includes.call(arrayLike, "b", -4));
+})();
+
+
+// Array.prototype.includes should use a negative value as the offset from the
+// end of the array to compute fromIndex
+(function() {
+  assertTrue([12, 13].includes(13, -1));
+  assertFalse([12, 13].includes(12, -1));
+  assertTrue([12, 13].includes(12, -2));
+
+  var arrayLike = {
+    length: 2,
+
+    get 0() {
+      return "a";
+    },
+
+    get 1() {
+      return "b";
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "b", -1));
+  assertFalse(Array.prototype.includes.call(arrayLike, "a", -1));
+  assertTrue(Array.prototype.includes.call(arrayLike, "a", -2));
+})();
+
+
+// Array.prototype.includes converts its fromIndex parameter to an integer
+(function() {
+  assertFalse(["a", "b"].includes("a", 2.3));
+
+  var arrayLikeWithTraps = {
+    length: 2,
+
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    },
+
+    get 1() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "c", 2.1));
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "c", +Infinity));
+  assertTrue(["a", "b", "c"].includes("a", -Infinity));
+  assertTrue(["a", "b", "c"].includes("c", 2.9));
+  assertTrue(["a", "b", "c"].includes("c", NaN));
+
+  var arrayLikeWithTrapAfterZero = {
+    length: 2,
+
+    get 0() {
+      return "a";
+    },
+
+    get 1() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(arrayLikeWithTrapAfterZero, "a", NaN));
+
+  var numberLike = {
+    valueOf: function() {
+      return 2;
+    }
+  };
+
+  assertFalse(["a", "b", "c"].includes("a", numberLike));
+  assertFalse(["a", "b", "c"].includes("a", "2"));
+  assertTrue(["a", "b", "c"].includes("c", numberLike));
+  assertTrue(["a", "b", "c"].includes("c", "2"));
+})();
+
+
+// Array.prototype.includes should have length 1
+(function() {
+  assertEquals(1, Array.prototype.includes.length);
+})();
+
+
+// Array.prototype.includes should have name property with value 'includes'
+(function() {
+  assertEquals("includes", Array.prototype.includes.name);
+})();
+
+
+// !!! Test failed to convert:
+// Cannot convert tests with includes.
+// !!!
+
+
+// Array.prototype.includes does not skip holes; if the array has a prototype it
+// gets from that
+(function() {
+  var holesEverywhere = [,,,];
+
+  holesEverywhere.__proto__ = {
+    1: "a"
+  };
+
+  holesEverywhere.__proto__.__proto__ = Array.prototype;
+  assertTrue(holesEverywhere.includes("a"));
+  var oneHole = ["a", "b",, "d"];
+
+  oneHole.__proto__ = {
+    get 2() {
+      return "c";
+    }
+  };
+
+  assertTrue(Array.prototype.includes.call(oneHole, "c"));
+})();
+
+
+// Array.prototype.includes does not skip holes; instead it treates them as
+// undefined
+(function() {
+  assertTrue([,,,].includes(undefined));
+  assertTrue(["a", "b",, "d"].includes(undefined));
+})();
+
+
+// Array.prototype.includes gets length property from the prototype if it's
+// available
+(function() {
+  var proto = {
+    length: 1
+  };
+
+  var arrayLike = Object.create(proto);
+  arrayLike[0] = "a";
+
+  Object.defineProperty(arrayLike, "1", {
+    get: function() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  });
+
+  assertTrue(Array.prototype.includes.call(arrayLike, "a"));
+})();
+
+
+// Array.prototype.includes treats a missing length property as zero
+(function() {
+  var arrayLikeWithTraps = {
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    },
+
+    get 1() {
+      assertUnreachable("Getter for 1 was called");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTraps, "a"));
+})();
+
+
+// Array.prototype.includes should always return false on negative-length
+// objects
+(function() {
+  assertFalse(Array.prototype.includes.call({
+    length: -1
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -2
+  }));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -Infinity
+  }, undefined));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -Math.pow(2, 53)
+  }, NaN));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -1,
+    "-1": 2
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -3,
+    "-1": 2
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: -Infinity,
+    "-1": 2
+  }, 2));
+
+  var arrayLikeWithTrap = {
+    length: -1,
+
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLikeWithTrap, 2));
+})();
+
+
+// Array.prototype.includes should clamp positive lengths to 2^53 - 1
+(function() {
+  var fromIndexForLargeIndexTests = 9007199254740990;
+
+  assertFalse(Array.prototype.includes.call({
+    length: 1
+  }, 2));
+
+  assertTrue(Array.prototype.includes.call({
+    length: 1,
+    0: "a"
+  }, "a"));
+
+  assertTrue(Array.prototype.includes.call({
+    length: +Infinity,
+    0: "a"
+  }, "a"));
+
+  assertFalse(Array.prototype.includes.call({
+    length: +Infinity
+  }, "a", fromIndexForLargeIndexTests));
+
+  var arrayLikeWithTrap = {
+    length: +Infinity,
+
+    get 9007199254740992() {
+      assertUnreachable("Getter for 9007199254740992 (i.e. 2^53) was called");
+    },
+
+    "9007199254740993": "a"
+  };
+
+  assertFalse(
+    Array.prototype.includes.call(arrayLikeWithTrap, "a", fromIndexForLargeIndexTests)
+  );
+
+  var arrayLikeWithTooBigLength = {
+    length: 9007199254740996,
+    "9007199254740992": "a"
+  };
+
+  assertFalse(
+    Array.prototype.includes.call(arrayLikeWithTooBigLength, "a", fromIndexForLargeIndexTests)
+  );
+})();
+
+
+// Array.prototype.includes should always return false on zero-length objects
+(function() {
+  assertFalse([].includes(2));
+  assertFalse([].includes());
+  assertFalse([].includes(undefined));
+  assertFalse([].includes(NaN));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0
+  }));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0
+  }, undefined));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0
+  }, NaN));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0,
+    0: 2
+  }, 2));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0,
+    0: undefined
+  }));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0,
+    0: undefined
+  }, undefined));
+
+  assertFalse(Array.prototype.includes.call({
+    length: 0,
+    0: NaN
+  }, NaN));
+
+  var arrayLikeWithTrap = {
+    length: 0,
+
+    get 0() {
+      assertUnreachable("Getter for 0 was called");
+    }
+  };
+
+  Array.prototype.includes.call(arrayLikeWithTrap);
+
+  var trappedFromIndex = {
+    valueOf: function() {
+      assertUnreachable("Should not try to convert fromIndex to a number on a zero-length array");
+    }
+  };
+
+  [].includes("a", trappedFromIndex);
+
+  Array.prototype.includes.call({
+    length: 0
+  }, trappedFromIndex);
+})();
+
+
+// Array.prototype.includes works on objects
+(function() {
+  assertFalse(["a", "b", "c"].includes({}));
+  assertFalse([{}, {}].includes({}));
+  var obj = {};
+  assertTrue([obj].includes(obj));
+  assertFalse([obj].includes(obj, 1));
+  assertTrue([obj, obj].includes(obj, 1));
+
+  var stringyObject = {
+    toString: function() {
+      return "a";
+    }
+  };
+
+  assertFalse(["a", "b", obj].includes(stringyObject));
+})();
+
+
+// Array.prototype.includes does not see an element removed by a getter that is
+// hit during iteration
+(function() {
+  var arrayLike = {
+    length: 5,
+    0: "a",
+
+    get 1() {
+      delete this[2];
+      return "b";
+    },
+
+    2: "c"
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLike, "c"));
+})();
+
+
+// Array.prototype.includes should use the SameValueZero algorithm to compare
+(function() {
+  assertTrue([1, 2, 3].includes(2));
+  assertFalse([1, 2, 3].includes(4));
+  assertTrue([1, 2, NaN].includes(NaN));
+  assertTrue([1, 2, -0].includes(+0));
+  assertTrue([1, 2, -0].includes(-0));
+  assertTrue([1, 2, +0].includes(-0));
+  assertTrue([1, 2, +0].includes(+0));
+  assertFalse([1, 2, -Infinity].includes(+Infinity));
+  assertTrue([1, 2, -Infinity].includes(-Infinity));
+  assertFalse([1, 2, +Infinity].includes(-Infinity));
+  assertTrue([1, 2, +Infinity].includes(+Infinity));
+})();
+
+
+// Array.prototype.includes stops once it hits the length of an array-like, even
+// if there are more after
+(function() {
+  var arrayLike = {
+    length: 2,
+    0: "a",
+    1: "b",
+
+    get 2() {
+      assertUnreachable("Should not try to get the second element");
+    }
+  };
+
+  assertFalse(Array.prototype.includes.call(arrayLike, "c"));
+})();
+
+
+// Array.prototype.includes works on typed arrays
+(function() {
+  assertTrue(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 2));
+
+  assertTrue(
+    Array.prototype.includes.call(new Float32Array([2.5, 3.14, Math.PI]), 3.1415927410125732)
+  );
+
+  assertFalse(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 4));
+  assertFalse(Array.prototype.includes.call(new Uint8Array([1, 2, 3]), 2, 2));
+})();
diff --git a/test/mjsunit/harmony/block-conflicts.js b/test/mjsunit/harmony/block-conflicts.js
index 1eedb68..d19a34a 100644
--- a/test/mjsunit/harmony/block-conflicts.js
+++ b/test/mjsunit/harmony/block-conflicts.js
@@ -1,30 +1,7 @@
 // Copyright 2011 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 //
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 // Flags: --harmony-scoping
 
 // Test for conflicting variable bindings.
@@ -175,7 +152,7 @@
 
 // Test conflicting catch/var bindings.
 for (var v = 0; v < varbinds.length; ++v) {
-  TestConflict('try {} catch(x) {' + varbinds[v] + '}');
+  TestNoConflict('try {} catch(x) {' + varbinds[v] + '}');
 }
 
 // Test conflicting parameter/var bindings.
diff --git a/test/mjsunit/harmony/block-const-assign.js b/test/mjsunit/harmony/block-const-assign.js
index b71729e..c21a0a3 100644
--- a/test/mjsunit/harmony/block-const-assign.js
+++ b/test/mjsunit/harmony/block-const-assign.js
@@ -35,61 +35,61 @@
 
 // Function local const.
 function constDecl0(use) {
-  return "(function() { const constvar = 1; " + use + "; });";
+  return "(function() { const constvar = 1; " + use + "; })();";
 }
 
 
 function constDecl1(use) {
-  return "(function() { " + use + "; const constvar = 1; });";
+  return "(function() { " + use + "; const constvar = 1; })();";
 }
 
 
 // Function local const, assign from eval.
 function constDecl2(use) {
-  use = "eval('(function() { " + use + " })')";
+  use = "eval('(function() { " + use + " })')()";
   return "(function() { const constvar = 1; " + use + "; })();";
 }
 
 
 function constDecl3(use) {
-  use = "eval('(function() { " + use + " })')";
+  use = "eval('(function() { " + use + " })')()";
   return "(function() { " + use + "; const constvar = 1; })();";
 }
 
 
 // Block local const.
 function constDecl4(use) {
-  return "(function() { { const constvar = 1; " + use + "; } });";
+  return "(function() { { const constvar = 1; " + use + "; } })();";
 }
 
 
 function constDecl5(use) {
-  return "(function() { { " + use + "; const constvar = 1; } });";
+  return "(function() { { " + use + "; const constvar = 1; } })();";
 }
 
 
 // Block local const, assign from eval.
 function constDecl6(use) {
-  use = "eval('(function() {" + use + "})')";
+  use = "eval('(function() {" + use + "})')()";
   return "(function() { { const constvar = 1; " + use + "; } })();";
 }
 
 
 function constDecl7(use) {
-  use = "eval('(function() {" + use + "})')";
+  use = "eval('(function() {" + use + "})')()";
   return "(function() { { " + use + "; const constvar = 1; } })();";
 }
 
 
 // Function expression name.
 function constDecl8(use) {
-  return "(function constvar() { " + use + "; });";
+  return "(function constvar() { " + use + "; })();";
 }
 
 
 // Function expression name, assign from eval.
 function constDecl9(use) {
-  use = "eval('(function(){" + use + "})')";
+  use = "eval('(function(){" + use + "})')()";
   return "(function constvar() { " + use + "; })();";
 }
 
@@ -104,6 +104,7 @@
               constDecl8,
               constDecl9
               ];
+let declsForTDZ = new Set([constDecl1, constDecl3, constDecl5, constDecl7]);
 let uses = [ 'constvar = 1;',
              'constvar += 1;',
              '++constvar;',
@@ -116,7 +117,13 @@
     print(d(u));
     eval(d(u));
   } catch (e) {
-    assertInstanceof(e, SyntaxError);
+    if (declsForTDZ.has(d) && u !== uses[0]) {
+      // In these cases, read of a const variable occurs
+      // before a write to it, so TDZ kicks in before const check.
+      assertInstanceof(e, ReferenceError);
+      return;
+    }
+    assertInstanceof(e, TypeError);
     assertTrue(e.toString().indexOf("Assignment to constant variable") >= 0);
     return;
   }
diff --git a/test/mjsunit/harmony/block-non-strict-errors.js b/test/mjsunit/harmony/block-non-strict-errors.js
new file mode 100644
index 0000000..11fa5c6
--- /dev/null
+++ b/test/mjsunit/harmony/block-non-strict-errors.js
@@ -0,0 +1,41 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-scoping --harmony-classes
+
+function CheckError(source) {
+  var exception = null;
+  try {
+    eval(source);
+  } catch (e) {
+    exception = e;
+  }
+  assertNotNull(exception);
+  assertEquals(
+      "Block-scoped declarations (let, const, function, class) not yet supported outside strict mode",
+      exception.message);
+}
+
+
+function CheckOk(source) {
+  eval(source);
+}
+
+CheckError("let x = 1;");
+CheckError("{ let x = 1; }");
+CheckError("function f() { let x = 1; }");
+CheckError("for (let x = 1; x < 1; x++) {}");
+CheckError("for (let x of []) {}");
+CheckError("for (let x in []) {}");
+CheckError("class C {}");
+CheckError("class C extends Array {}");
+CheckError("(class {});");
+CheckError("(class extends Array {});");
+CheckError("(class C {});");
+CheckError("(class C exends Array {});");
+
+CheckOk("let = 1;");
+CheckOk("{ let = 1; }");
+CheckOk("function f() { let = 1; }");
+CheckOk("for (let = 1; let < 1; let++) {}");
diff --git a/test/mjsunit/harmony/classes.js b/test/mjsunit/harmony/classes.js
new file mode 100644
index 0000000..29ffbf8
--- /dev/null
+++ b/test/mjsunit/harmony/classes.js
@@ -0,0 +1,879 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-classes --harmony-sloppy
+
+(function TestBasics() {
+  var C = class C {}
+  assertEquals(typeof C, 'function');
+  assertEquals(C.__proto__, Function.prototype);
+  assertEquals(Object.prototype, Object.getPrototypeOf(C.prototype));
+  assertEquals(Function.prototype, Object.getPrototypeOf(C));
+  assertEquals('C', C.name);
+
+  class D {}
+  assertEquals(typeof D, 'function');
+  assertEquals(D.__proto__, Function.prototype);
+  assertEquals(Object.prototype, Object.getPrototypeOf(D.prototype));
+  assertEquals(Function.prototype, Object.getPrototypeOf(D));
+  assertEquals('D', D.name);
+
+  class D2 { constructor() {} }
+  assertEquals('D2', D2.name);
+
+  // TODO(arv): The logic for the name of anonymous functions in ES6 requires
+  // the below to be 'E';
+  var E = class {}
+  assertEquals('', E.name);  // Should be 'E'.
+
+  var F = class { constructor() {} };
+  assertEquals('', F.name);  // Should be 'F'.
+})();
+
+
+(function TestBasicsExtends() {
+  class C extends null {}
+  assertEquals(typeof C, 'function');
+  assertEquals(C.__proto__, Function.prototype);
+  assertEquals(null, Object.getPrototypeOf(C.prototype));
+
+  class D extends C {}
+  assertEquals(typeof D, 'function');
+  assertEquals(D.__proto__, C);
+  assertEquals(C.prototype, Object.getPrototypeOf(D.prototype));
+})();
+
+
+(function TestSideEffectInExtends() {
+  var calls = 0;
+  class C {}
+  class D extends (calls++, C) {}
+  assertEquals(1, calls);
+  assertEquals(typeof D, 'function');
+  assertEquals(D.__proto__, C);
+  assertEquals(C.prototype, Object.getPrototypeOf(D.prototype));
+})();
+
+
+(function TestInvalidExtends() {
+  assertThrows(function() {
+    class C extends 42 {}
+  }, TypeError);
+
+  assertThrows(function() {
+    // Function but its .prototype is not null or a function.
+    class C extends Math.abs {}
+  }, TypeError);
+
+  assertThrows(function() {
+    Math.abs.prototype = 42;
+    class C extends Math.abs {}
+  }, TypeError);
+  delete Math.abs.prototype;
+})();
+
+
+(function TestConstructorProperty() {
+  class C {}
+  assertEquals(C, C.prototype.constructor);
+  var descr = Object.getOwnPropertyDescriptor(C.prototype, 'constructor');
+  assertTrue(descr.configurable);
+  assertFalse(descr.enumerable);
+  assertTrue(descr.writable);
+})();
+
+
+(function TestPrototypeProperty() {
+  class C {}
+  var descr = Object.getOwnPropertyDescriptor(C, 'prototype');
+  assertFalse(descr.configurable);
+  assertFalse(descr.enumerable);
+  assertFalse(descr.writable);
+})();
+
+
+(function TestConstructor() {
+  var count = 0;
+  class C {
+    constructor() {
+      assertEquals(Object.getPrototypeOf(this), C.prototype);
+      count++;
+    }
+  }
+  assertEquals(C, C.prototype.constructor);
+  var descr = Object.getOwnPropertyDescriptor(C.prototype, 'constructor');
+  assertTrue(descr.configurable);
+  assertFalse(descr.enumerable);
+  assertTrue(descr.writable);
+
+  var c = new C();
+  assertEquals(1, count);
+  assertEquals(Object.getPrototypeOf(c), C.prototype);
+})();
+
+
+(function TestImplicitConstructor() {
+  class C {}
+  var c = new C();
+  assertEquals(Object.getPrototypeOf(c), C.prototype);
+})();
+
+
+(function TestConstructorStrict() {
+  class C {
+    constructor() {
+      assertThrows(function() {
+        nonExistingBinding = 42;
+      }, ReferenceError);
+    }
+  }
+  new C();
+})();
+
+
+(function TestSuperInConstructor() {
+  var calls = 0;
+  class B {}
+  B.prototype.x = 42;
+
+  class C extends B {
+    constructor() {
+      calls++;
+      assertEquals(42, super.x);
+    }
+  }
+
+  new C;
+  assertEquals(1, calls);
+})();
+
+
+(function TestStrictMode() {
+  class C {}
+
+  with ({a: 1}) {
+    assertEquals(1, a);
+  }
+
+  assertThrows('class C extends function B() { with ({}); return B; }() {}',
+               SyntaxError);
+
+  var D = class extends function() {
+    arguments.caller;
+  } {};
+  assertThrows(function() {
+    Object.getPrototypeOf(D).arguments;
+  }, TypeError);
+  assertThrows(function() {
+    new D;
+  }, TypeError);
+})();
+
+
+(function TestToString() {
+  class C {}
+  assertEquals('class C {}', C.toString());
+
+  class D { constructor() { 42; } }
+  assertEquals('class D { constructor() { 42; } }', D.toString());
+
+  class E { x() { 42; } }
+  assertEquals('class E { x() { 42; } }', E.toString());
+})();
+
+
+function assertMethodDescriptor(object, name) {
+  var descr = Object.getOwnPropertyDescriptor(object, name);
+  assertTrue(descr.configurable);
+  assertTrue(descr.enumerable);
+  assertTrue(descr.writable);
+  assertEquals('function', typeof descr.value);
+  assertFalse('prototype' in descr.value);
+}
+
+
+function assertGetterDescriptor(object, name) {
+  var descr = Object.getOwnPropertyDescriptor(object, name);
+  assertTrue(descr.configurable);
+  assertTrue(descr.enumerable);
+  assertEquals('function', typeof descr.get);
+  assertEquals(undefined, descr.set);
+}
+
+
+function assertSetterDescriptor(object, name) {
+  var descr = Object.getOwnPropertyDescriptor(object, name);
+  assertTrue(descr.configurable);
+  assertTrue(descr.enumerable);
+  assertEquals(undefined, descr.get);
+  assertEquals('function', typeof descr.set);
+}
+
+
+function assertAccessorDescriptor(object, name) {
+  var descr = Object.getOwnPropertyDescriptor(object, name);
+  assertTrue(descr.configurable);
+  assertTrue(descr.enumerable);
+  assertEquals('function', typeof descr.get);
+  assertEquals('function', typeof descr.set);
+}
+
+
+(function TestMethods() {
+  class C {
+    method() { return 1; }
+    static staticMethod() { return 2; }
+    method2() { return 3; }
+    static staticMethod2() { return 4; }
+  }
+
+  assertMethodDescriptor(C.prototype, 'method');
+  assertMethodDescriptor(C.prototype, 'method2');
+  assertMethodDescriptor(C, 'staticMethod');
+  assertMethodDescriptor(C, 'staticMethod2');
+
+  assertEquals(1, new C().method());
+  assertEquals(2, C.staticMethod());
+  assertEquals(3, new C().method2());
+  assertEquals(4, C.staticMethod2());
+})();
+
+
+(function TestGetters() {
+  class C {
+    get x() { return 1; }
+    static get staticX() { return 2; }
+    get y() { return 3; }
+    static get staticY() { return 4; }
+  }
+
+  assertGetterDescriptor(C.prototype, 'x');
+  assertGetterDescriptor(C.prototype, 'y');
+  assertGetterDescriptor(C, 'staticX');
+  assertGetterDescriptor(C, 'staticY');
+
+  assertEquals(1, new C().x);
+  assertEquals(2, C.staticX);
+  assertEquals(3, new C().y);
+  assertEquals(4, C.staticY);
+})();
+
+
+
+(function TestSetters() {
+  var x, staticX, y, staticY;
+  class C {
+    set x(v) { x = v; }
+    static set staticX(v) { staticX = v; }
+    set y(v) { y = v; }
+    static set staticY(v) { staticY = v; }
+  }
+
+  assertSetterDescriptor(C.prototype, 'x');
+  assertSetterDescriptor(C.prototype, 'y');
+  assertSetterDescriptor(C, 'staticX');
+  assertSetterDescriptor(C, 'staticY');
+
+  assertEquals(1, new C().x = 1);
+  assertEquals(1, x);
+  assertEquals(2, C.staticX = 2);
+  assertEquals(2, staticX);
+  assertEquals(3, new C().y = 3);
+  assertEquals(3, y);
+  assertEquals(4, C.staticY = 4);
+  assertEquals(4, staticY);
+})();
+
+
+(function TestSideEffectsInPropertyDefine() {
+  function B() {}
+  B.prototype = {
+    constructor: B,
+    set m(v) {
+      throw Error();
+    }
+  };
+
+  class C extends B {
+    m() { return 1; }
+  }
+
+  assertEquals(1, new C().m());
+})();
+
+
+(function TestAccessors() {
+  class C {
+    constructor(x) {
+      this._x = x;
+    }
+
+    get x() { return this._x; }
+    set x(v) { this._x = v; }
+
+    static get staticX() { return this._x; }
+    static set staticX(v) { this._x = v; }
+  }
+
+  assertAccessorDescriptor(C.prototype, 'x');
+  assertAccessorDescriptor(C, 'staticX');
+
+  var c = new C(1);
+  c._x = 1;
+  assertEquals(1, c.x);
+  c.x = 2;
+  assertEquals(2, c._x);
+
+  C._x = 3;
+  assertEquals(3, C.staticX);
+  C._x = 4;
+  assertEquals(4, C.staticX );
+})();
+
+
+(function TestProto() {
+  class C {
+    __proto__() { return 1; }
+  }
+  assertMethodDescriptor(C.prototype, '__proto__');
+  assertEquals(1, new C().__proto__());
+})();
+
+
+(function TestProtoStatic() {
+  class C {
+    static __proto__() { return 1; }
+  }
+  assertMethodDescriptor(C, '__proto__');
+  assertEquals(1, C.__proto__());
+})();
+
+
+(function TestProtoAccessor() {
+  class C {
+    get __proto__() { return this._p; }
+    set __proto__(v) { this._p = v; }
+  }
+  assertAccessorDescriptor(C.prototype, '__proto__');
+  var c = new C();
+  c._p = 1;
+  assertEquals(1, c.__proto__);
+  c.__proto__ = 2;
+  assertEquals(2, c.__proto__);
+})();
+
+
+(function TestStaticProtoAccessor() {
+  class C {
+    static get __proto__() { return this._p; }
+    static set __proto__(v) { this._p = v; }
+  }
+  assertAccessorDescriptor(C, '__proto__');
+  C._p = 1;
+  assertEquals(1, C.__proto__);
+  C.__proto__ = 2;
+  assertEquals(2, C.__proto__);
+})();
+
+
+(function TestSettersOnProto() {
+  function Base() {}
+  Base.prototype = {
+    set constructor(_) {
+      assertUnreachable();
+    },
+    set m(_) {
+      assertUnreachable();
+    }
+  };
+  Object.defineProperty(Base, 'staticM', {
+    set: function() {
+      assertUnreachable();
+    }
+  });
+
+  class C extends Base {
+    m() {
+      return 1;
+    }
+    static staticM() {
+      return 2;
+    }
+  }
+
+  assertEquals(1, new C().m());
+  assertEquals(2, C.staticM());
+})();
+
+
+(function TestConstructableButNoPrototype() {
+  var Base = function() {}.bind();
+  assertThrows(function() {
+    class C extends Base {}
+  }, TypeError);
+})();
+
+
+(function TestPrototypeGetter() {
+  var calls = 0;
+  var Base = function() {}.bind();
+  Object.defineProperty(Base, 'prototype', {
+    get: function() {
+      calls++;
+      return null;
+    },
+    configurable: true
+  });
+  class C extends Base {}
+  assertEquals(1, calls);
+
+  calls = 0;
+  Object.defineProperty(Base, 'prototype', {
+    get: function() {
+      calls++;
+      return 42;
+    },
+    configurable: true
+  });
+  assertThrows(function() {
+    class C extends Base {}
+  }, TypeError);
+  assertEquals(1, calls);
+})();
+
+
+(function TestPrototypeSetter() {
+  var Base = function() {}.bind();
+  Object.defineProperty(Base, 'prototype', {
+    set: function() {
+      assertUnreachable();
+    }
+  });
+  assertThrows(function() {
+    class C extends Base {}
+  }, TypeError);
+})();
+
+
+(function TestSuperInMethods() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    method() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, new C().method());
+})();
+
+
+(function TestSuperInGetter() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    get y() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, new C().y);
+})();
+
+
+(function TestSuperInSetter() {
+  class B {
+    method() {
+      return 1;
+    }
+    get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    set y(v) {
+      assertEquals(3, v);
+      assertEquals(2, super.x);
+      assertEquals(1, super.method());
+    }
+  }
+  assertEquals(3, new C().y = 3);
+})();
+
+
+(function TestSuperInStaticMethods() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static method() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, C.method());
+})();
+
+
+(function TestSuperInStaticGetter() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static get x() {
+      assertEquals(2, super.x);
+      return super.method();
+    }
+  }
+  assertEquals(1, C.x);
+})();
+
+
+(function TestSuperInStaticSetter() {
+  class B {
+    static method() {
+      return 1;
+    }
+    static get x() {
+      return 2;
+    }
+  }
+  class C extends B {
+    static set x(v) {
+      assertEquals(3, v);
+      assertEquals(2, super.x);
+      assertEquals(1, super.method());
+    }
+  }
+  assertEquals(3, C.x = 3);
+})();
+
+
+(function TestNumericPropertyNames() {
+  class B {
+    1() { return 1; }
+    get 2() { return 2; }
+    set 3(_) {}
+
+    static 4() { return 4; }
+    static get 5() { return 5; }
+    static set 6(_) {}
+  }
+
+  assertMethodDescriptor(B.prototype, '1');
+  assertGetterDescriptor(B.prototype, '2');
+  assertSetterDescriptor(B.prototype, '3');
+
+  assertMethodDescriptor(B, '4');
+  assertGetterDescriptor(B, '5');
+  assertSetterDescriptor(B, '6');
+
+  class C extends B {
+    1() { return super[1](); }
+    get 2() { return super[2]; }
+
+    static 4() { return super[4](); }
+    static get 5() { return super[5]; }
+  }
+
+  assertEquals(1, new C()[1]());
+  assertEquals(2, new C()[2]);
+  assertEquals(4, C[4]());
+  assertEquals(5, C[5]);
+})();
+
+
+(function TestDefaultConstructorNoCrash() {
+  // Regression test for https://code.google.com/p/v8/issues/detail?id=3661
+  class C {}
+  assertEquals(undefined, C());
+  assertEquals(undefined, C(1));
+  assertTrue(new C() instanceof C);
+  assertTrue(new C(1) instanceof C);
+})();
+
+
+(function TestDefaultConstructor() {
+  var calls = 0;
+  class Base {
+    constructor() {
+      calls++;
+    }
+  }
+  class Derived extends Base {}
+  var object = new Derived;
+  assertEquals(1, calls);
+
+  calls = 0;
+  Derived();
+  assertEquals(1, calls);
+})();
+
+
+(function TestDefaultConstructorArguments() {
+  var args, self;
+  class Base {
+    constructor() {
+      self = this;
+      args = arguments;
+    }
+  }
+  class Derived extends Base {}
+
+  new Derived;
+  assertEquals(0, args.length);
+
+  new Derived(0, 1, 2);
+  assertEquals(3, args.length);
+  assertTrue(self instanceof Derived);
+
+  var arr = new Array(100);
+  var obj = {};
+  Derived.apply(obj, arr);
+  assertEquals(100, args.length);
+  assertEquals(obj, self);
+})();
+
+
+(function TestDefaultConstructorArguments2() {
+  var args;
+  class Base {
+    constructor(x, y) {
+      args = arguments;
+    }
+  }
+  class Derived extends Base {}
+
+  new Derived;
+  assertEquals(0, args.length);
+
+  new Derived(1);
+  assertEquals(1, args.length);
+  assertEquals(1, args[0]);
+
+  new Derived(1, 2, 3);
+  assertEquals(3, args.length);
+  assertEquals(1, args[0]);
+  assertEquals(2, args[1]);
+  assertEquals(3, args[2]);
+})();
+
+
+(function TestNameBindingConst() {
+  assertThrows('class C { constructor() { C = 42; } }; new C();', TypeError);
+  assertThrows('new (class C { constructor() { C = 42; } })', TypeError);
+  assertThrows('class C { m() { C = 42; } }; new C().m()', TypeError);
+  assertThrows('new (class C { m() { C = 42; } }).m()', TypeError);
+  assertThrows('class C { get x() { C = 42; } }; new C().x', TypeError);
+  assertThrows('(new (class C { get x() { C = 42; } })).x', TypeError);
+  assertThrows('class C { set x(_) { C = 42; } }; new C().x = 15;', TypeError);
+  assertThrows('(new (class C { set x(_) { C = 42; } })).x = 15;', TypeError);
+})();
+
+
+(function TestNameBinding() {
+  var C2;
+  class C {
+    constructor() {
+      C2 = C;
+    }
+    m() {
+      C2 = C;
+    }
+    get x() {
+      C2 = C;
+    }
+    set x(_) {
+      C2 = C;
+    }
+  }
+  new C();
+  assertEquals(C, C2);
+
+  C2 = undefined;
+  new C().m();
+  assertEquals(C, C2);
+
+  C2 = undefined;
+  new C().x;
+  assertEquals(C, C2);
+
+  C2 = undefined;
+  new C().x = 1;
+  assertEquals(C, C2);
+})();
+
+
+(function TestNameBindingExpression() {
+  var C3;
+  var C = class C2 {
+    constructor() {
+      assertEquals(C2, C);
+      C3 = C2;
+    }
+    m() {
+      assertEquals(C2, C);
+      C3 = C2;
+    }
+    get x() {
+      assertEquals(C2, C);
+      C3 = C2;
+    }
+    set x(_) {
+      assertEquals(C2, C);
+      C3 = C2;
+    }
+  }
+  new C();
+  assertEquals(C, C3);
+
+  C3 = undefined;
+  new C().m();
+  assertEquals(C, C3);
+
+  C3 = undefined;
+  new C().x;
+  assertEquals(C, C3);
+
+  C3 = undefined;
+  new C().x = 1;
+  assertEquals(C, C3);
+})();
+
+
+(function TestNameBindingInExtendsExpression() {
+  assertThrows(function() {
+    class x extends x {}
+  }, ReferenceError);
+
+  assertThrows(function() {
+    (class x extends x {});
+  }, ReferenceError);
+
+  assertThrows(function() {
+    var x = (class x extends x {});
+  }, ReferenceError);
+})();
+
+
+(function TestSuperCallSyntacticRestriction() {
+  assertThrows(function() {
+    class C {
+      constructor() {
+        var y;
+        super();
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(this.x);
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(this);
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super.method();
+        super(this);
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(super.method());
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(super());
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(1, 2, Object.getPrototypeOf(this));
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        { super(1, 2); }
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        if (1) super();
+      }
+    }; new C();
+  }, TypeError);
+
+  class C1 extends Object {
+    constructor() {
+      'use strict';
+      super();
+    }
+  };
+  new C1();
+
+  class C2 extends Object {
+    constructor() {
+      ; 'use strict';;;;;
+      super();
+    }
+  };
+  new C2();
+
+  class C3 extends Object {
+    constructor() {
+      ; 'use strict';;;;;
+      // This is a comment.
+      super();
+    }
+  };
+  new C3();
+
+  class C4 extends Object {
+    constructor() {
+      super(new super());
+    }
+  }; new C4();
+}());
diff --git a/test/mjsunit/harmony/debug-blockscopes.js b/test/mjsunit/harmony/debug-blockscopes.js
index 2db4942..8180377 100644
--- a/test/mjsunit/harmony/debug-blockscopes.js
+++ b/test/mjsunit/harmony/debug-blockscopes.js
@@ -73,7 +73,7 @@
 // Check result of a test.
 function EndTest() {
   assertTrue(listener_called, "listerner not called for " + test_name);
-  assertNull(exception, test_name);
+  assertNull(exception, test_name, exception);
   end_test_count++;
 }
 
@@ -108,6 +108,7 @@
     assertEquals(i, response.body.scopes[i].index);
     assertEquals(scopes[i], response.body.scopes[i].type);
     if (scopes[i] == debug.ScopeType.Local ||
+        scopes[i] == debug.ScopeType.Script ||
         scopes[i] == debug.ScopeType.Closure) {
       assertTrue(response.body.scopes[i].object.ref < 0);
     } else {
@@ -197,6 +198,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
 };
@@ -215,6 +217,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1}, 0, exec_state);
 };
@@ -232,6 +235,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,x:3}, 0, exec_state);
 };
@@ -250,6 +254,7 @@
 
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state);
 };
@@ -270,6 +275,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:5}, 0, exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
@@ -292,6 +298,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:6,y:7}, 0, exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
@@ -315,6 +322,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:8}, 0, exec_state);
   CheckScopeContent({a:1}, 1, exec_state);
@@ -344,6 +352,7 @@
   CheckScopeChain([debug.ScopeType.Local,
                    debug.ScopeType.Block,
                    debug.ScopeType.Closure,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({}, 0, exec_state);
   CheckScopeContent({a:1,x:2,y:3}, 2, exec_state);
@@ -364,6 +373,7 @@
 listener_delegate = function(exec_state) {
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:'y'}, 0, exec_state);
   // The function scope contains a temporary iteration variable, but it is
@@ -389,6 +399,7 @@
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:3}, 0, exec_state);
   CheckScopeContent({x:'y'}, 1, exec_state);
@@ -413,6 +424,7 @@
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:3}, 0, exec_state);
   CheckScopeContent({x:3}, 1, exec_state);
@@ -437,6 +449,7 @@
                    debug.ScopeType.Block,
                    debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:5}, 0, exec_state);
   CheckScopeContent({x:3}, 1, exec_state);
@@ -460,6 +473,7 @@
   CheckScopeChain([debug.ScopeType.Block,
                    debug.ScopeType.Block,
                    debug.ScopeType.Local,
+                   debug.ScopeType.Script,
                    debug.ScopeType.Global], exec_state);
   CheckScopeContent({x:3,y:5}, 0, exec_state);
   CheckScopeContent({x:3,y:5}, 1, exec_state);
@@ -467,3 +481,24 @@
 };
 for_loop_5();
 EndTest();
+
+
+// Uninitialized variables
+BeginTest("Uninitialized 1");
+
+function uninitialized_1() {
+  {
+    debugger;
+    let x = 1;
+  }
+}
+
+listener_delegate = function(exec_state) {
+  CheckScopeChain([debug.ScopeType.Block,
+                   debug.ScopeType.Local,
+                   debug.ScopeType.Script,
+                   debug.ScopeType.Global], exec_state);
+  CheckScopeContent({}, 0, exec_state);
+};
+uninitialized_1();
+EndTest();
diff --git a/test/mjsunit/harmony/debug-evaluate-blockscopes.js b/test/mjsunit/harmony/debug-evaluate-blockscopes.js
index 16885d0..d133cc0 100644
--- a/test/mjsunit/harmony/debug-evaluate-blockscopes.js
+++ b/test/mjsunit/harmony/debug-evaluate-blockscopes.js
@@ -67,3 +67,43 @@
 Debug.clearBreakPoint(bp);
 // Get rid of the debug event listener.
 Debug.setListener(null);
+
+
+function f1() {
+  {
+    let i = 1;
+    debugger;
+    assertEquals(2, i);
+  }
+}
+
+function f2() {
+  {
+    let i = 1;
+    debugger;
+    assertEquals(2, i);
+    return function() { return i++; }
+  }
+}
+
+var exception;
+Debug.setListener(function (event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      var frame = exec_state.frame();
+      assertEquals(1, frame.evaluate("i").value());
+      var allScopes = frame.allScopes();
+      assertEquals(1, allScopes[0].scopeObject().value().i);
+      allScopes[0].setVariableValue("i", 2);
+    }
+  } catch (e) {
+    exception = e;
+  }
+});
+
+exception = null;
+f1();
+assertEquals(null, exception, exception);
+exception = null;
+f2();
+assertEquals(null, exception, exception);
diff --git a/test/mjsunit/harmony/debug-function-scopes.js b/test/mjsunit/harmony/debug-function-scopes.js
index 0113be6..1b380c2 100644
--- a/test/mjsunit/harmony/debug-function-scopes.js
+++ b/test/mjsunit/harmony/debug-function-scopes.js
@@ -28,6 +28,7 @@
 // Flags: --expose-debug-as debug --harmony-scoping
 
 "use strict";
+let top_level_let = 255;
 
 // Get the Debug object exposed from the debug context global object.
 var Debug = debug.Debug;
@@ -50,7 +51,8 @@
                   With: 2,
                   Closure: 3,
                   Catch: 4,
-                  Block: 5 };
+                  Block: 5,
+                  Script: 6};
 
 var f1 = (function F1(x) {
   function F2(y) {
@@ -72,12 +74,13 @@
 
 var mirror = Debug.MakeMirror(f1);
 
-assertEquals(4, mirror.scopeCount());
+assertEquals(5, mirror.scopeCount());
 
 CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
 CheckScope(mirror.scope(1), { z: 22, w: 5, v: "Capybara" }, ScopeType.Closure);
 CheckScope(mirror.scope(2), { x: 5 }, ScopeType.Closure);
-CheckScope(mirror.scope(3), {}, ScopeType.Global);
+CheckScope(mirror.scope(3), { top_level_let: 255 }, ScopeType.Script);
+CheckScope(mirror.scope(4), {}, ScopeType.Global);
 
 var f2 = (function() {
   var v1 = 3;
@@ -104,7 +107,7 @@
 
 var mirror = Debug.MakeMirror(f2);
 
-assertEquals(5, mirror.scopeCount());
+assertEquals(6, mirror.scopeCount());
 
 // Implementation artifact: l4 isn't used in closure, but still it is saved.
 CheckScope(mirror.scope(0), { l4: 11 }, ScopeType.Block);
@@ -112,4 +115,5 @@
 CheckScope(mirror.scope(1), { l3: 9 }, ScopeType.Block);
 CheckScope(mirror.scope(2), { l1: 6, l2: 7 }, ScopeType.Block);
 CheckScope(mirror.scope(3), { v1:3, l0: 0, v3: 5, v6: 11 }, ScopeType.Closure);
-CheckScope(mirror.scope(4), {}, ScopeType.Global);
+CheckScope(mirror.scope(4), { top_level_let: 255 }, ScopeType.Script);
+CheckScope(mirror.scope(5), {}, ScopeType.Global);
diff --git a/test/mjsunit/harmony/debug-step-into-class-extends.js b/test/mjsunit/harmony/debug-step-into-class-extends.js
new file mode 100644
index 0000000..ffc6fda
--- /dev/null
+++ b/test/mjsunit/harmony/debug-step-into-class-extends.js
@@ -0,0 +1,42 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --harmony-classes
+
+'use strict';
+
+var Debug = debug.Debug
+
+var done = false;
+var stepCount = 0;
+
+function listener(event, execState, eventData, data) {
+  if (event == Debug.DebugEvent.Break) {
+    if (!done) {
+      execState.prepareStep(Debug.StepAction.StepInto);
+      var s = execState.frame().sourceLineText();
+      assertTrue(s.indexOf('// ' + stepCount + '.') !== -1);
+      stepCount++;
+    }
+  }
+};
+
+Debug.setListener(listener);
+
+function GetBase() {
+  var x = 1;   // 1.
+  var y = 2;   // 2.
+  done = true; // 3.
+  return null;
+}
+
+function f() {
+  class Derived extends GetBase() {} // 0.
+}
+
+var bp = Debug.setBreakPoint(f, 0);
+f();
+assertEquals(4, stepCount);
+
+Debug.setListener(null);
diff --git a/test/mjsunit/harmony/debug-step-into-constructor.js b/test/mjsunit/harmony/debug-step-into-constructor.js
new file mode 100644
index 0000000..dbef60f
--- /dev/null
+++ b/test/mjsunit/harmony/debug-step-into-constructor.js
@@ -0,0 +1,113 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --harmony-classes
+
+'use strict';
+
+var Debug = debug.Debug
+var done, stepCount;
+
+function listener(event, execState, eventData, data) {
+  if (event == Debug.DebugEvent.Break) {
+    if (!done) {
+      execState.prepareStep(Debug.StepAction.StepInto);
+      var s = execState.frame().sourceLineText();
+      assertTrue(s.indexOf('// ' + stepCount + '.') !== -1);
+      stepCount++;
+    }
+  }
+};
+
+Debug.setListener(listener);
+
+
+class Base {
+  constructor() {
+    var x = 1;   // 1.
+    var y = 2;   // 2.
+    done = true; // 3.
+  }
+}
+
+class Derived extends Base {}
+
+
+(function TestBreakPointInConstructor() {
+  done = false;
+  stepCount = 1;
+  var bp = Debug.setBreakPoint(Base, 0);
+
+  new Base();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+(function TestDefaultConstructor() {
+  done = false;
+  stepCount = 1;
+
+  var bp = Debug.setBreakPoint(Base, 0);
+  new Derived();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+(function TestStepInto() {
+  done = false;
+  stepCount = 0;
+
+  function f() {
+    new Derived();  // 0.
+  }
+
+  var bp = Debug.setBreakPoint(f, 0);
+  f();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+(function TestExtraIndirection() {
+  done = false;
+  stepCount = 0;
+
+  class Derived2 extends Derived {}
+
+  function f() {
+    new Derived2();  // 0.
+  }
+
+  var bp = Debug.setBreakPoint(f, 0);
+  f();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+(function TestBoundClass() {
+  done = false;
+  stepCount = 0;
+
+  var bound = Derived.bind(null);
+
+  function f() {
+    new bound();  // 0.
+  }
+
+  var bp = Debug.setBreakPoint(f, 0);
+  f();
+  assertEquals(4, stepCount);
+
+  Debug.clearBreakPoint(bp);
+})();
+
+
+Debug.setListener(null);
diff --git a/test/mjsunit/harmony/disable-harmony-string.js b/test/mjsunit/harmony/disable-harmony-string.js
new file mode 100644
index 0000000..0b88ae0
--- /dev/null
+++ b/test/mjsunit/harmony/disable-harmony-string.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --noharmony-strings
+
+assertEquals(undefined, String.prototype.includes);
diff --git a/test/mjsunit/harmony/module-linking.js b/test/mjsunit/harmony/module-linking.js
index 3c0f18c..3a5bc89 100644
--- a/test/mjsunit/harmony/module-linking.js
+++ b/test/mjsunit/harmony/module-linking.js
@@ -109,7 +109,7 @@
   assertThrows(function() { l }, ReferenceError)
   assertThrows(function() { R.l }, ReferenceError)
 
-  assertThrows(function() { eval("c = -1") }, SyntaxError)
+  assertThrows(function() { eval("c = -1") }, TypeError)
   assertThrows(function() { R.c = -2 }, TypeError)
 
   // Initialize first bunch of variables.
@@ -129,7 +129,7 @@
   assertEquals(-4, R.v = -4)
   assertEquals(-3, l = -3)
   assertEquals(-4, R.l = -4)
-  assertThrows(function() { eval("c = -3") }, SyntaxError)
+  assertThrows(function() { eval("c = -3") }, TypeError)
   assertThrows(function() { R.c = -4 }, TypeError)
 
   assertEquals(-4, v)
diff --git a/test/mjsunit/harmony/object-literals-property-shorthand.js b/test/mjsunit/harmony/object-literals-property-shorthand.js
new file mode 100644
index 0000000..2921495
--- /dev/null
+++ b/test/mjsunit/harmony/object-literals-property-shorthand.js
@@ -0,0 +1,51 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-object-literals
+
+
+(function TestBasics() {
+  var x = 1;
+  var object = {x};
+  assertEquals(1, object.x);
+})();
+
+
+(function TestDescriptor() {
+  var x = 1;
+  var object = {x};
+  var descr = Object.getOwnPropertyDescriptor(object, 'x');
+  assertEquals(1, descr.value);
+  assertTrue(descr.enumerable);
+  assertTrue(descr.writable);
+  assertTrue(descr.configurable);
+})();
+
+
+(function TestNotDefined() {
+  'use strict';
+  assertThrows(function() {
+    return {notDefined};
+  }, ReferenceError);
+})();
+
+
+(function TestLet() {
+  var let = 1;
+  var object = {let};
+  assertEquals(1, object.let);
+})();
+
+
+(function TestYieldInFunction() {
+  var yield = 1;
+  var object = {yield};
+  assertEquals(1, object.yield);
+})();
+
+
+(function TestToString() {
+  function f(x) { return {x}; }
+  assertEquals('function f(x) { return {x}; }', f.toString());
+})();
diff --git a/test/mjsunit/harmony/object-literals-super.js b/test/mjsunit/harmony/object-literals-super.js
new file mode 100644
index 0000000..ec22b8a
--- /dev/null
+++ b/test/mjsunit/harmony/object-literals-super.js
@@ -0,0 +1,168 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-classes --allow-natives-syntax
+
+
+(function TestHomeObject() {
+  var object = {
+    method() {
+      return super.method();
+    },
+    get getter() {
+      return super.getter;
+    },
+    set setter(v) {
+      super.setter = v;
+    },
+    get accessor() {
+      return super.accessor;
+    },
+    set accessor(v) {
+      super.accessor = v;
+    },
+    property: function() {
+      super.property();
+    },
+    propertyWithParen: (function() {
+      super.property();
+    }),
+    propertyWithParens: ((function() {
+      super.property();
+    })),
+
+    methodNoSuper() {},
+    get getterNoSuper() {},
+    set setterNoSuper(v) {},
+    get accessorNoSuper() {},
+    set accessorNoSuper(v) {},
+    propertyNoSuper: function() {},
+    propertyWithParenNoSuper: (function() {}),
+    propertyWithParensNoSuper: ((function() {}))
+  };
+
+  assertEquals(object, object.method[%HomeObjectSymbol()]);
+  var desc = Object.getOwnPropertyDescriptor(object, 'getter');
+  assertEquals(object, desc.get[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'setter');
+  assertEquals(object, desc.set[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'accessor');
+  assertEquals(object, desc.get[%HomeObjectSymbol()]);
+  assertEquals(object, desc.set[%HomeObjectSymbol()]);
+  assertEquals(object, object.property[%HomeObjectSymbol()]);
+  assertEquals(object, object.propertyWithParen[%HomeObjectSymbol()]);
+  assertEquals(object, object.propertyWithParens[%HomeObjectSymbol()]);
+
+  assertEquals(undefined, object.methodNoSuper[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'getterNoSuper');
+  assertEquals(undefined, desc.get[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'setterNoSuper');
+  assertEquals(undefined, desc.set[%HomeObjectSymbol()]);
+  desc = Object.getOwnPropertyDescriptor(object, 'accessorNoSuper');
+  assertEquals(undefined, desc.get[%HomeObjectSymbol()]);
+  assertEquals(undefined, desc.set[%HomeObjectSymbol()]);
+  assertEquals(undefined, object.propertyNoSuper[%HomeObjectSymbol()]);
+  assertEquals(undefined, object.propertyWithParenNoSuper[%HomeObjectSymbol()]);
+  assertEquals(undefined,
+               object.propertyWithParensNoSuper[%HomeObjectSymbol()]);
+})();
+
+
+(function TestMethod() {
+  var object = {
+    __proto__: {
+      method(x) {
+        return 'proto' + x;
+      }
+    },
+    method(x) {
+      return super.method(x);
+    }
+  };
+  assertEquals('proto42', object.method(42));
+})();
+
+
+(function TestGetter() {
+  var object = {
+    __proto__: {
+      _x: 42,
+      get x() {
+        return 'proto' + this._x;
+      }
+    },
+    get x() {
+      return super.x;
+    }
+  };
+  assertEquals('proto42', object.x);
+})();
+
+
+(function TestSetter() {
+  var object = {
+    __proto__: {
+      _x: 0,
+      set x(v) {
+        return this._x = v;
+      }
+    },
+    set x(v) {
+      super.x = v;
+    }
+  };
+  assertEquals(1, object.x = 1);
+  assertEquals(1, object._x);
+  assertEquals(0, Object.getPrototypeOf(object)._x);
+})();
+
+
+(function TestMethodAsProperty() {
+  var object = {
+    __proto__: {
+      method: function(x) {
+        return 'proto' + x;
+      }
+    },
+    method: function(x) {
+      return super.method(x);
+    }
+  };
+  assertEquals('proto42', object.method(42));
+})();
+
+
+(function TestOptimized() {
+  // Object literals without any accessors get optimized.
+  var object = {
+    method() {
+      return super.toString;
+    }
+  };
+  assertEquals(Object.prototype.toString, object.method());
+})();
+
+
+(function TestConciseGenerator() {
+  var o = {
+    __proto__: {
+      m() {
+        return 42;
+      }
+    },
+    *g() {
+      yield super.m();
+    },
+    g2: function*() {
+      yield super.m() + 1;
+    },
+    g3: (function*() {
+      yield super.m() + 2;
+    })
+  };
+
+  assertEquals(42, o.g().next().value);
+  assertEquals(43, o.g2().next().value);
+  assertEquals(44, o.g3().next().value);
+})();
diff --git a/test/mjsunit/harmony/proxies-with-unscopables.js b/test/mjsunit/harmony/proxies-with-unscopables.js
index 191bad3..8a03ef4 100644
--- a/test/mjsunit/harmony/proxies-with-unscopables.js
+++ b/test/mjsunit/harmony/proxies-with-unscopables.js
@@ -74,12 +74,17 @@
   var calls = 0;
   var proxy = Proxy.create({
     has: function(key) {
-      calls++;
-      assertEquals('x', key);
-      return calls === 2;
+      assertUnreachable();
     },
     getPropertyDescriptor: function(key) {
-      assertUnreachable();
+      calls++;
+      assertEquals('x', key);
+      return {
+        value: calls === 2 ? true : undefined,
+        configurable: true,
+        enumerable: true,
+        writable: true,
+      };
     }
   });
 
@@ -107,12 +112,12 @@
   var calls = 0;
   var proxy = Proxy.create({
     has: function(key) {
-      if (calls++ === 0) {
-        throw new CustomError();
-      }
       assertUnreachable();
     },
     getPropertyDescriptor: function(key) {
+      if (calls++ === 0) {
+        throw new CustomError();
+      }
       assertUnreachable();
     }
   });
diff --git a/test/mjsunit/harmony/proxies.js b/test/mjsunit/harmony/proxies.js
index b082c06..2b0ec76 100644
--- a/test/mjsunit/harmony/proxies.js
+++ b/test/mjsunit/harmony/proxies.js
@@ -29,7 +29,7 @@
 // test enters an infinite recursion which goes through the runtime and we
 // overflow the system stack before the simulator stack.
 
-// Flags: --harmony-proxies --sim-stack-size=500
+// Flags: --harmony-proxies --sim-stack-size=500 --turbo-deoptimization
 
 
 // Helper.
diff --git a/test/mjsunit/harmony/regexp-flags.js b/test/mjsunit/harmony/regexp-flags.js
new file mode 100644
index 0000000..475fda4
--- /dev/null
+++ b/test/mjsunit/harmony/regexp-flags.js
@@ -0,0 +1,61 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-regexps
+
+RegExp.prototype.flags = 'setter should be undefined';
+
+assertEquals('', RegExp('').flags);
+assertEquals('', /./.flags);
+assertEquals('gimy', RegExp('', 'ygmi').flags);
+assertEquals('gimy', /foo/ymig.flags);
+
+// TODO(dslomov): When support for the `u` flag is added, uncomment the first
+// line below and remove the second line.
+//assertEquals(RegExp('', 'yumig').flags, 'gimuy');
+assertThrows(function() { RegExp('', 'yumig').flags; }, SyntaxError);
+
+var descriptor = Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags');
+assertTrue(descriptor.configurable);
+assertFalse(descriptor.enumerable);
+assertInstanceof(descriptor.get, Function);
+assertEquals(undefined, descriptor.set);
+
+function testGenericFlags(object) {
+  return descriptor.get.call(object);
+}
+
+assertEquals('', testGenericFlags({}));
+assertEquals('i', testGenericFlags({ ignoreCase: true }));
+assertEquals('uy', testGenericFlags({ global: 0, sticky: 1, unicode: 1 }));
+assertEquals('m', testGenericFlags({ __proto__: { multiline: true } }));
+assertThrows(function() { testGenericFlags(); }, TypeError);
+assertThrows(function() { testGenericFlags(undefined); }, TypeError);
+assertThrows(function() { testGenericFlags(null); }, TypeError);
+assertThrows(function() { testGenericFlags(true); }, TypeError);
+assertThrows(function() { testGenericFlags(false); }, TypeError);
+assertThrows(function() { testGenericFlags(''); }, TypeError);
+assertThrows(function() { testGenericFlags(42); }, TypeError);
+
+var counter = 0;
+var map = {};
+var object = {
+  get global() {
+    map.g = counter++;
+  },
+  get ignoreCase() {
+    map.i = counter++;
+  },
+  get multiline() {
+    map.m = counter++;
+  },
+  get unicode() {
+    map.u = counter++;
+  },
+  get sticky() {
+    map.y = counter++;
+  }
+};
+testGenericFlags(object);
+assertEquals({ g: 0, i: 1, m: 2, u: 3, y: 4 }, map);
diff --git a/test/mjsunit/harmony/regress/regress-2243.js b/test/mjsunit/harmony/regress/regress-2243.js
index 31c2e55..e2411d2 100644
--- a/test/mjsunit/harmony/regress/regress-2243.js
+++ b/test/mjsunit/harmony/regress/regress-2243.js
@@ -27,5 +27,5 @@
 
 // Flags: --harmony-scoping
 
-assertThrows("'use strict'; (function f() { f = 123; })", SyntaxError);
-assertThrows("(function f() { 'use strict'; f = 123; })", SyntaxError);
+assertThrows("'use strict'; (function f() { f = 123; })()", TypeError);
+assertThrows("(function f() { 'use strict'; f = 123; })()", TypeError);
diff --git a/test/mjsunit/harmony/regress/regress-2858.js b/test/mjsunit/harmony/regress/regress-2858.js
new file mode 100644
index 0000000..4ce9478
--- /dev/null
+++ b/test/mjsunit/harmony/regress/regress-2858.js
@@ -0,0 +1,27 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-scoping
+"use strict";
+
+function f() {
+    var y = 1;
+    var q1;
+    var q;
+    var z = new Error();
+    try {
+        throw z;
+    } catch (y) {
+      assertTrue(z === y);
+      q1 = function() { return y; }
+      var y = 15;
+      q = function() { return y; }
+      assertSame(15, y);
+    }
+    assertSame(1, y);
+    assertSame(15, q1());
+    assertSame(15, q());
+}
+
+f();
diff --git a/test/mjsunit/harmony/regress/regress-343928.js b/test/mjsunit/harmony/regress/regress-343928.js
index b102ab9..f2ff371 100644
--- a/test/mjsunit/harmony/regress/regress-343928.js
+++ b/test/mjsunit/harmony/regress/regress-343928.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony --expose-debug-as=debug
+// Flags: --harmony-modules --expose-debug-as=debug
 
 (function () {  // Scope for utility functions.
   escaping_function = function(object) {
diff --git a/test/mjsunit/harmony/regress/regress-3683.js b/test/mjsunit/harmony/regress/regress-3683.js
new file mode 100644
index 0000000..a00d82b
--- /dev/null
+++ b/test/mjsunit/harmony/regress/regress-3683.js
@@ -0,0 +1,84 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-scoping
+
+"use strict";
+
+// Simplest case
+var count = 0;
+for (let x = 0; x < 10;) {
+  x++;
+  count++;
+  continue;
+}
+assertEquals(10, count);
+
+// Labeled
+count = 0;
+label: for (let x = 0; x < 10;) {
+  while (true) {
+    x++;
+    count++;
+    continue label;
+  }
+}
+assertEquals(10, count);
+
+// Simple and labeled
+count = 0;
+label: for (let x = 0; x < 10;) {
+  x++;
+  count++;
+  continue label;
+}
+assertEquals(10, count);
+
+// Shadowing loop variable in same scope as continue
+count = 0;
+for (let x = 0; x < 10;) {
+  x++;
+  count++;
+  {
+    let x = "hello";
+    continue;
+  }
+}
+assertEquals(10, count);
+
+// Nested let-bound for loops, inner continue
+count = 0;
+for (let x = 0; x < 10;) {
+  x++;
+  for (let y = 0; y < 2;) {
+    y++;
+    count++;
+    continue;
+  }
+}
+assertEquals(20, count);
+
+// Nested let-bound for loops, outer continue
+count = 0;
+for (let x = 0; x < 10;) {
+  x++;
+  for (let y = 0; y < 2;) {
+    y++;
+    count++;
+  }
+  continue;
+}
+assertEquals(20, count);
+
+// Nested let-bound for loops, labeled continue
+count = 0;
+outer: for (let x = 0; x < 10;) {
+  x++;
+  for (let y = 0; y < 2;) {
+    y++;
+    count++;
+    if (y == 2) continue outer;
+  }
+}
+assertEquals(20, count);
diff --git a/test/mjsunit/harmony/regress/regress-3741.js b/test/mjsunit/harmony/regress/regress-3741.js
new file mode 100644
index 0000000..8a9dd9e
--- /dev/null
+++ b/test/mjsunit/harmony/regress/regress-3741.js
@@ -0,0 +1,26 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-scoping --allow-natives-syntax
+'use strict';
+function f24(deopt) {
+  let x = 1;
+  {
+    let x = 2;
+    {
+      let x = 3;
+      assertEquals(3, x);
+    }
+    deopt + 1;
+    assertEquals(2, x);
+  }
+  assertEquals(1, x);
+}
+
+
+for (var j = 0; j < 10; ++j) {
+  f24(12);
+}
+%OptimizeFunctionOnNextCall(f24);
+f24({});
diff --git a/test/mjsunit/harmony/regress/regress-3750.js b/test/mjsunit/harmony/regress/regress-3750.js
new file mode 100644
index 0000000..d1f21f9
--- /dev/null
+++ b/test/mjsunit/harmony/regress/regress-3750.js
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-classes
+'use strict';
+class Example { }
+Object.observe(Example.prototype, function(){});
diff --git a/test/mjsunit/harmony/string-contains.js b/test/mjsunit/harmony/string-contains.js
deleted file mode 100644
index b853ed9..0000000
--- a/test/mjsunit/harmony/string-contains.js
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Flags: --harmony-strings
-
-assertEquals(1, String.prototype.contains.length);
-
-var reString = "asdf[a-z]+(asdf)?";
-assertTrue(reString.contains("[a-z]+"));
-assertTrue(reString.contains("(asdf)?"));
-
-// Random greek letters
-var twoByteString = "\u039a\u0391\u03a3\u03a3\u0395";
-
-// Test single char pattern
-assertTrue(twoByteString.contains("\u039a"), "Lamda");
-assertTrue(twoByteString.contains("\u0391"), "Alpha");
-assertTrue(twoByteString.contains("\u03a3"), "First Sigma");
-assertTrue(twoByteString.contains("\u03a3",3), "Second Sigma");
-assertTrue(twoByteString.contains("\u0395"), "Epsilon");
-assertFalse(twoByteString.contains("\u0392"), "Not beta");
-
-// Test multi-char pattern
-assertTrue(twoByteString.contains("\u039a\u0391"), "lambda Alpha");
-assertTrue(twoByteString.contains("\u0391\u03a3"), "Alpha Sigma");
-assertTrue(twoByteString.contains("\u03a3\u03a3"), "Sigma Sigma");
-assertTrue(twoByteString.contains("\u03a3\u0395"), "Sigma Epsilon");
-
-assertFalse(twoByteString.contains("\u0391\u03a3\u0395"),
-    "Not Alpha Sigma Epsilon");
-
-//single char pattern
-assertTrue(twoByteString.contains("\u0395"));
-
-assertThrows("String.prototype.contains.call(null, 'test')", TypeError);
-assertThrows("String.prototype.contains.call(null, null)", TypeError);
-assertThrows("String.prototype.contains.call(undefined, undefined)", TypeError);
-
-assertThrows("String.prototype.contains.apply(null, ['test'])", TypeError);
-assertThrows("String.prototype.contains.apply(null, [null])", TypeError);
-assertThrows("String.prototype.contains.apply(undefined, [undefined])", TypeError);
-
-var TEST_INPUT = [{
-  msg: "Empty string", val: ""
-}, {
-  msg: "Number 1234.34", val: 1234.34
-}, {
-  msg: "Integer number 0", val: 0
-}, {
-  msg: "Negative number -1", val: -1
-}, {
-  msg: "Boolean true", val: true
-}, {
-  msg: "Boolean false", val: false
-}, {
-  msg: "Empty array []", val: []
-}, {
-  msg: "Empty object {}", val: {}
-}, {
-  msg: "Array of size 3", val: new Array(3)
-}];
-
-var i = 0;
-var l = TEST_INPUT.length;
-
-for (; i < l; i++) {
-  var e = TEST_INPUT[i];
-  var v = e.val;
-  var s = String(v);
-  assertTrue(s.contains(v), e.msg);
-  assertTrue(String.prototype.contains.call(v, v), e.msg);
-  assertTrue(String.prototype.contains.apply(v, [v]), e.msg);
-}
-
-// Test cases found in FF
-assertTrue("abc".contains("a"));
-assertTrue("abc".contains("b"));
-assertTrue("abc".contains("abc"));
-assertTrue("abc".contains("bc"));
-assertFalse("abc".contains("d"));
-assertFalse("abc".contains("abcd"));
-assertFalse("abc".contains("ac"));
-assertTrue("abc".contains("abc", 0));
-assertTrue("abc".contains("bc", 0));
-assertFalse("abc".contains("de", 0));
-assertTrue("abc".contains("bc", 1));
-assertTrue("abc".contains("c", 1));
-assertFalse("abc".contains("a", 1));
-assertFalse("abc".contains("abc", 1));
-assertTrue("abc".contains("c", 2));
-assertFalse("abc".contains("d", 2));
-assertFalse("abc".contains("dcd", 2));
-assertFalse("abc".contains("a", 42));
-assertFalse("abc".contains("a", Infinity));
-assertTrue("abc".contains("ab", -43));
-assertFalse("abc".contains("cd", -42));
-assertTrue("abc".contains("ab", -Infinity));
-assertFalse("abc".contains("cd", -Infinity));
-assertTrue("abc".contains("ab", NaN));
-assertFalse("abc".contains("cd", NaN));
-assertFalse("xyzzy".contains("zy\0", 2));
-
-var dots = Array(10000).join(".");
-assertFalse(dots.contains("\x01", 10000));
-assertFalse(dots.contains("\0", 10000));
-
-var myobj = {
-  toString: function () {
-    return "abc";
-  },
-  contains: String.prototype.contains
-};
-assertTrue(myobj.contains("abc"));
-assertFalse(myobj.contains("cd"));
-
-var gotStr = false;
-var gotPos = false;
-myobj = {
-  toString: function () {
-    assertFalse(gotPos);
-    gotStr = true;
-    return "xyz";
-  },
-  contains: String.prototype.contains
-};
-
-assertEquals("foo[a-z]+(bar)?".contains("[a-z]+"), true);
-assertThrows("'foo[a-z]+(bar)?'.contains(/[a-z]+/)", TypeError);
-assertThrows("'foo/[a-z]+/(bar)?'.contains(/[a-z]+/)", TypeError);
-assertEquals("foo[a-z]+(bar)?".contains("(bar)?"), true);
-assertThrows("'foo[a-z]+(bar)?'.contains(/(bar)?/)", TypeError);
-assertThrows("'foo[a-z]+/(bar)?/'.contains(/(bar)?/)", TypeError);
-
-assertThrows("String.prototype.contains.call({ 'toString': function() { " +
-  "throw RangeError(); } }, /./)", RangeError);
-assertThrows("String.prototype.contains.call({ 'toString': function() { " +
-  "return 'abc'; } }, /./)", TypeError);
-
-assertThrows("String.prototype.contains.apply({ 'toString': function() { " +
-  "throw RangeError(); } }, [/./])", RangeError);
-assertThrows("String.prototype.contains.apply({ 'toString': function() { " +
-  "return 'abc'; } }, [/./])", TypeError);
diff --git a/test/mjsunit/harmony/string-includes.js b/test/mjsunit/harmony/string-includes.js
new file mode 100644
index 0000000..33ed8ea
--- /dev/null
+++ b/test/mjsunit/harmony/string-includes.js
@@ -0,0 +1,166 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-strings
+
+assertEquals(1, String.prototype.includes.length);
+
+var reString = "asdf[a-z]+(asdf)?";
+assertTrue(reString.includes("[a-z]+"));
+assertTrue(reString.includes("(asdf)?"));
+
+// Random greek letters
+var twoByteString = "\u039a\u0391\u03a3\u03a3\u0395";
+
+// Test single char pattern
+assertTrue(twoByteString.includes("\u039a"), "Lamda");
+assertTrue(twoByteString.includes("\u0391"), "Alpha");
+assertTrue(twoByteString.includes("\u03a3"), "First Sigma");
+assertTrue(twoByteString.includes("\u03a3",3), "Second Sigma");
+assertTrue(twoByteString.includes("\u0395"), "Epsilon");
+assertFalse(twoByteString.includes("\u0392"), "Not beta");
+
+// Test multi-char pattern
+assertTrue(twoByteString.includes("\u039a\u0391"), "lambda Alpha");
+assertTrue(twoByteString.includes("\u0391\u03a3"), "Alpha Sigma");
+assertTrue(twoByteString.includes("\u03a3\u03a3"), "Sigma Sigma");
+assertTrue(twoByteString.includes("\u03a3\u0395"), "Sigma Epsilon");
+
+assertFalse(twoByteString.includes("\u0391\u03a3\u0395"),
+    "Not Alpha Sigma Epsilon");
+
+//single char pattern
+assertTrue(twoByteString.includes("\u0395"));
+
+assertThrows("String.prototype.includes.call(null, 'test')", TypeError);
+assertThrows("String.prototype.includes.call(null, null)", TypeError);
+assertThrows("String.prototype.includes.call(undefined, undefined)", TypeError);
+
+assertThrows("String.prototype.includes.apply(null, ['test'])", TypeError);
+assertThrows("String.prototype.includes.apply(null, [null])", TypeError);
+assertThrows("String.prototype.includes.apply(undefined, [undefined])", TypeError);
+
+var TEST_INPUT = [{
+  msg: "Empty string", val: ""
+}, {
+  msg: "Number 1234.34", val: 1234.34
+}, {
+  msg: "Integer number 0", val: 0
+}, {
+  msg: "Negative number -1", val: -1
+}, {
+  msg: "Boolean true", val: true
+}, {
+  msg: "Boolean false", val: false
+}, {
+  msg: "Empty array []", val: []
+}, {
+  msg: "Empty object {}", val: {}
+}, {
+  msg: "Array of size 3", val: new Array(3)
+}];
+
+var i = 0;
+var l = TEST_INPUT.length;
+
+for (; i < l; i++) {
+  var e = TEST_INPUT[i];
+  var v = e.val;
+  var s = String(v);
+  assertTrue(s.includes(v), e.msg);
+  assertTrue(String.prototype.includes.call(v, v), e.msg);
+  assertTrue(String.prototype.includes.apply(v, [v]), e.msg);
+}
+
+// Test cases found in FF
+assertTrue("abc".includes("a"));
+assertTrue("abc".includes("b"));
+assertTrue("abc".includes("abc"));
+assertTrue("abc".includes("bc"));
+assertFalse("abc".includes("d"));
+assertFalse("abc".includes("abcd"));
+assertFalse("abc".includes("ac"));
+assertTrue("abc".includes("abc", 0));
+assertTrue("abc".includes("bc", 0));
+assertFalse("abc".includes("de", 0));
+assertTrue("abc".includes("bc", 1));
+assertTrue("abc".includes("c", 1));
+assertFalse("abc".includes("a", 1));
+assertFalse("abc".includes("abc", 1));
+assertTrue("abc".includes("c", 2));
+assertFalse("abc".includes("d", 2));
+assertFalse("abc".includes("dcd", 2));
+assertFalse("abc".includes("a", 42));
+assertFalse("abc".includes("a", Infinity));
+assertTrue("abc".includes("ab", -43));
+assertFalse("abc".includes("cd", -42));
+assertTrue("abc".includes("ab", -Infinity));
+assertFalse("abc".includes("cd", -Infinity));
+assertTrue("abc".includes("ab", NaN));
+assertFalse("abc".includes("cd", NaN));
+assertFalse("xyzzy".includes("zy\0", 2));
+
+var dots = Array(10000).join(".");
+assertFalse(dots.includes("\x01", 10000));
+assertFalse(dots.includes("\0", 10000));
+
+var myobj = {
+  toString: function () {
+    return "abc";
+  },
+  includes: String.prototype.includes
+};
+assertTrue(myobj.includes("abc"));
+assertFalse(myobj.includes("cd"));
+
+var gotStr = false;
+var gotPos = false;
+myobj = {
+  toString: function () {
+    assertFalse(gotPos);
+    gotStr = true;
+    return "xyz";
+  },
+  includes: String.prototype.includes
+};
+
+assertEquals("foo[a-z]+(bar)?".includes("[a-z]+"), true);
+assertThrows("'foo[a-z]+(bar)?'.includes(/[a-z]+/)", TypeError);
+assertThrows("'foo/[a-z]+/(bar)?'.includes(/[a-z]+/)", TypeError);
+assertEquals("foo[a-z]+(bar)?".includes("(bar)?"), true);
+assertThrows("'foo[a-z]+(bar)?'.includes(/(bar)?/)", TypeError);
+assertThrows("'foo[a-z]+/(bar)?/'.includes(/(bar)?/)", TypeError);
+
+assertThrows("String.prototype.includes.call({ 'toString': function() { " +
+  "throw RangeError(); } }, /./)", RangeError);
+assertThrows("String.prototype.includes.call({ 'toString': function() { " +
+  "return 'abc'; } }, /./)", TypeError);
+
+assertThrows("String.prototype.includes.apply({ 'toString': function() { " +
+  "throw RangeError(); } }, [/./])", RangeError);
+assertThrows("String.prototype.includes.apply({ 'toString': function() { " +
+  "return 'abc'; } }, [/./])", TypeError);
diff --git a/test/mjsunit/harmony/string-raw.js b/test/mjsunit/harmony/string-raw.js
new file mode 100644
index 0000000..28e2af9
--- /dev/null
+++ b/test/mjsunit/harmony/string-raw.js
@@ -0,0 +1,258 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-templates
+
+(function testStringRawArity() {
+  assertEquals(1, String.raw.length);
+})();
+
+
+(function testStringRawCallSiteToObject() {
+  assertThrows("String.raw()", TypeError);
+})();
+
+
+(function testStringRawCallSiteRawToObject() {
+  assertThrows("String.raw([])", TypeError);
+})();
+
+
+(function testStringRawUndefinedLength() {
+  var callSiteObj = [];
+  callSiteObj.raw = {};
+  assertEquals("", String.raw(callSiteObj));
+
+  callSiteObj.raw = { lengt: 0 };
+  assertEquals("", String.raw(callSiteObj));
+})();
+
+
+(function testStringRawZeroLength() {
+  var callSiteObj = [];
+  callSiteObj.raw = { length: 0 };
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+
+  callSiteObj.raw = [];
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+})();
+
+
+(function testStringRawNegativeLength() {
+  var callSiteObj = [];
+  callSiteObj.raw = { length: -85 };
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+
+  callSiteObj.raw = [];
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+})();
+
+
+(function testStringRawNaNLength() {
+  var callSiteObj = [];
+  callSiteObj.raw = { length: NaN };
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+
+  callSiteObj.raw = [];
+  assertEquals("", String.raw(callSiteObj));
+  assertEquals("", String.raw(callSiteObj, "a", "b", "c"));
+})();
+
+
+(function testStringRawBasic() {
+  var callSiteObj = [];
+  callSiteObj.raw = ["a"];
+  assertEquals("a", String.raw(callSiteObj));
+})();
+
+
+(function testStringRawNoSubst() {
+  var callSiteObj = [];
+  callSiteObj.raw = ["a", "b"];
+  assertEquals("ab", String.raw(callSiteObj));
+})();
+
+
+(function testStringRawSubst() {
+  var callSiteObj = [];
+  callSiteObj.raw = ["a", "b"];
+  assertEquals("a!b", String.raw(callSiteObj, "!"));
+
+  callSiteObj.raw = ["a", "b", "c"];
+  assertEquals("abc", String.raw(callSiteObj));
+
+  callSiteObj.raw = ["a", "b", "c"];
+  assertEquals("a!bc", String.raw(callSiteObj, "!"));
+
+  callSiteObj.raw = ["a", "b", "c"];
+  assertEquals("a!b?c", String.raw(callSiteObj, "!", "?"));
+
+  callSiteObj.raw = ["\n", "\r\n", "\r"];
+  assertEquals("\nx\r\ny\r", String.raw(callSiteObj, "x", "y"));
+
+  callSiteObj.raw = ["\n", "\r\n", "\r"];
+  assertEquals("\n\r\r\r\n\n\r", String.raw(callSiteObj, "\r\r", "\n"));
+})();
+
+
+(function testStringRawArrayLikeSubst() {
+  var callSiteObj = [];
+  callSiteObj.raw = {"length": 2, "0": "a", "1": "b", "2": "c"};
+  assertEquals("axb", String.raw(callSiteObj, "x", "y"));
+
+  callSiteObj.raw = {"length": 4, "0": "a", "1": "b", "2": "c"};
+  assertEquals("axbycundefined", String.raw(callSiteObj, "x", "y"));
+})();
+
+
+(function testStringRawAccessors() {
+  var callSiteObj = {};
+  callSiteObj.raw = {};
+  Object.defineProperties(callSiteObj, {
+    "length": {
+      get: function() { assertUnreachable(); },
+      set: function(v) { assertUnreachable(); }
+    },
+    "0": {
+      get: function() { assertUnreachable(); },
+      set: function(v) { assertUnreachable(); }
+    },
+    "1": {
+      get: function() { assertUnreachable(); },
+      set: function(v) { assertUnreachable(); }
+    }
+  });
+  Object.defineProperties(callSiteObj.raw, {
+    "length": {
+      get: function() { return 2; },
+      set: function(v) { assertUnreachable(); }
+    },
+    "0": {
+      get: function() { return "getter values"; },
+      set: function(v) { assertUnreachable(); }
+    },
+    "1": {
+      get: function() { return "are nice"; },
+      set: function(v) { assertUnreachable(); }
+    }
+  });
+  assertEquals("getter values are nice", String.raw(callSiteObj, " "));
+})();
+
+
+(function testStringRawHoleyArray() {
+  var callSiteObj = [];
+  callSiteObj.raw = ["1."];
+  callSiteObj.raw[2] = ".2";
+  assertEquals("1.undefined.2", String.raw(callSiteObj));
+})();
+
+
+(function testStringRawAccessorThrows() {
+  var callSiteObj = [];
+  callSiteObj.raw = [1];
+  function MyError() {}
+  Object.defineProperty(callSiteObj.raw, "0", {
+    get: function() { throw new MyError(); }
+  });
+  assertThrows(function() { String.raw(callSiteObj); }, MyError);
+})();
+
+
+(function testStringRawToStringSafe() {
+  var callSiteObj = [];
+  callSiteObj.raw = [null, undefined, 1, "str", true, false, NaN, Infinity, {}];
+  assertEquals("nullundefined1strtruefalseNaNInfinity[object Object]",
+               String.raw(callSiteObj));
+
+  callSiteObj.raw = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
+  assertEquals("0null1undefined213str4true5false6NaN7Infinity8[object Object]9",
+               String.raw(callSiteObj, null, void 0, 1, "str", true, false,
+               NaN, Infinity, {}));
+})();
+
+
+(function testStringRawToStringSymbolThrows() {
+  var callSiteObj = [];
+  callSiteObj.raw = [Symbol("foo")];
+  assertThrows(function() {
+    String.raw(callSiteObj);
+  }, TypeError);
+
+  callSiteObj.raw = ["1", "2"];
+  assertThrows(function() {
+    String.raw(callSiteObj, Symbol("foo"));
+  }, TypeError);
+})();
+
+
+(function testStringRawToStringThrows() {
+  var callSiteObj = [];
+  var thrower = {};
+  function MyError() {}
+  thrower.toString = function() {
+    throw new MyError();
+  }
+
+  callSiteObj.raw = [thrower];
+  assertThrows(function() {
+    String.raw(callSiteObj);
+  }, MyError);
+
+  callSiteObj.raw = ["1", "2"];
+  assertThrows(function() {
+    String.raw(callSiteObj, thrower);
+  }, MyError);
+})();
+
+
+(function testStringRawToStringValueOfThrows() {
+  var callSiteObj = [];
+  var thrower = {};
+  function MyError() {}
+  thrower.toString = null;
+  thrower.valueOf = function() {
+    throw new MyError();
+  }
+
+  callSiteObj.raw = [thrower];
+  assertThrows(function() {
+    String.raw(callSiteObj);
+  }, MyError);
+
+  callSiteObj.raw = ["1", "2"];
+  assertThrows(function() {
+    String.raw(callSiteObj, thrower);
+  }, MyError);
+})();
+
+
+(function testStringRawOrder() {
+  var order = [];
+  var callSiteObj = [];
+  callSiteObj.raw = {};
+  function arg(v) {
+    var result = {};
+    result.toString = null;
+    result.valueOf = function() { order.push("arg" + v); return v; }
+    return result;
+  }
+
+  Object.defineProperty(callSiteObj.raw, "length", {
+    get: function() { order.push("length"); return 3; }
+  });
+  [1, 3, 5].forEach(function(v, i) {
+    Object.defineProperty(callSiteObj.raw, i, {
+      get: function() { order.push("raw" + v); return v; }
+    });
+  });
+
+  assertEquals("12345", String.raw(callSiteObj, arg(2), arg(4), arg(6)));
+  assertEquals(["length", "raw1", "arg2", "raw3", "arg4", "raw5"], order);
+})();
diff --git a/test/mjsunit/harmony/string-repeat.js b/test/mjsunit/harmony/string-repeat.js
index 761089b..0af7448 100644
--- a/test/mjsunit/harmony/string-repeat.js
+++ b/test/mjsunit/harmony/string-repeat.js
@@ -61,8 +61,11 @@
 assertEquals("", "abc".repeat(0));
 assertEquals("abcabc", "abc".repeat(2.0));
 
+assertEquals("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "a".repeat(37));
 assertThrows('"a".repeat(-1)', RangeError);
 assertThrows('"a".repeat(Number.POSITIVE_INFINITY)', RangeError);
+assertThrows('"a".repeat(Math.pow(2, 30))', RangeError);
+assertThrows('"a".repeat(Math.pow(2, 40))', RangeError);
 
 var myobj = {
   toString: function() {
diff --git a/test/mjsunit/harmony/super.js b/test/mjsunit/harmony/super.js
index 89fb4b1..6dcc393 100644
--- a/test/mjsunit/harmony/super.js
+++ b/test/mjsunit/harmony/super.js
@@ -18,6 +18,8 @@
 
   function fDerived() {
      assertEquals("Base this is Derived", super.f());
+     var a = super.x;
+     assertEquals(15, a);
      assertEquals(15, super.x);
      assertEquals(27, this.x);
 
@@ -34,6 +36,77 @@
   assertEquals("Derived", new Derived().f());
 }());
 
+
+(function TestSuperKeyedLoads() {
+  var x = 'x';
+  var derivedDataProperty = 'derivedDataProperty';
+  var f = 'f';
+  function Base() { }
+  function Derived() {
+    this[derivedDataProperty] = 'xxx';
+  }
+  Derived.prototype = Object.create(Base.prototype);
+
+  function fBase() { return "Base " + this.toString(); }
+
+  Base.prototype[f] = fBase.toMethod(Base.prototype);
+
+  function fDerived() {
+     assertEquals("Base this is Derived", super[f]());
+     var a = super[x];
+     assertEquals(15, a);
+     assertEquals(15, super[x]);
+     assertEquals(27, this[x]);
+
+     return "Derived"
+  }
+
+  Base.prototype[x] = 15;
+  Base.prototype.toString = function() { return "this is Base"; };
+  Derived.prototype.toString = function() { return "this is Derived"; };
+  Derived.prototype[x] = 27;
+  Derived.prototype[f] = fDerived.toMethod(Derived.prototype);
+
+  assertEquals("Base this is Base", new Base().f());
+  assertEquals("Derived", new Derived().f());
+}());
+
+
+(function TestSuperNumericKeyedLoads() {
+  var x = 1;
+  var derivedDataProperty = 2;
+  var f = 3;
+  function Base() { }
+  function Derived() {
+    this[derivedDataProperty] = 'xxx';
+  }
+  Derived.prototype = Object.create(Base.prototype);
+
+  function fBase() { return "Base " + this.toString(); }
+
+  Base.prototype[f] = fBase.toMethod(Base.prototype);
+
+  function fDerived() {
+     assertEquals("Base this is Derived", super[f]());
+     var a = super[x];
+     assertEquals(15, a);
+     assertEquals(15, super[x]);
+     assertEquals(27, this[x]);
+
+     return "Derived"
+  }
+
+  Base.prototype[x] = 15;
+  Base.prototype.toString = function() { return "this is Base"; };
+  Derived.prototype.toString = function() { return "this is Derived"; };
+  Derived.prototype[x] = 27;
+  Derived.prototype[f] = fDerived.toMethod(Derived.prototype);
+
+  assertEquals("Base this is Base", new Base()[f]());
+  assertEquals("Derived", new Derived()[f]());
+}());
+
+
 (function TestSuperKeywordNonMethod() {
   function f() {
     super.unknown();
@@ -65,12 +138,149 @@
   Derived.prototype.testGetter = function() {
     return super.x;
   }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterStrict = function() {
+    'use strict';
+    return super.x;
+  }.toMethod(Derived.prototype);
   derived = new Derived();
   assertEquals('derived', derived.testGetter());
+  derived = new Derived();
+  assertEquals('derived', derived.testGetterStrict());
 }());
 
-/*
- * TODO[dslomov]: named stores and keyed loads/stores not implemented yet.
+
+(function TestGetterKeyed() {
+  var x = 'x';
+  function Base() {}
+  var derived;
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      assertSame(this, derived);
+      return this._x;
+    },
+    _x: 'base'
+  };
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 'derived'
+  };
+  Derived.prototype.testGetter = function() {
+    return super[x];
+  }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterStrict = function() {
+    'use strict';
+    return super[x];
+  }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterWithToString = function() {
+    var toStringCalled;
+    var o = { toString: function() {
+      toStringCalled++;
+      return 'x';
+    } };
+
+    toStringCalled = 0;
+    assertEquals('derived', super[o]);
+    assertEquals(1, toStringCalled);
+
+    var eToThrow = new Error();
+    var oThrowsInToString = { toString: function() {
+      throw eToThrow;
+    } };
+
+    var ex = null;
+    try {
+      super[oThrowsInToString];
+    } catch(e) { ex = e }
+    assertEquals(eToThrow, ex);
+
+    var oReturnsNumericString = { toString: function() {
+      return "1";
+    } };
+
+    assertEquals(undefined, super[oReturnsNumericString]);
+    assertEquals(undefined, super[1]);
+  }.toMethod(Derived.prototype);
+  derived = new Derived();
+  assertEquals('derived', derived.testGetter());
+  derived = new Derived();
+  assertEquals('derived', derived.testGetterStrict());
+  derived = new Derived();
+  derived.testGetterWithToString();
+}());
+
+
+(function TestGetterNumericKeyed() {
+  var x = 42;
+  function Base() {}
+  var derived;
+  Base.prototype = {
+    constructor: Base,
+    _x: 'base'
+  };
+
+  Object.defineProperty(Base.prototype, x, { get: function() {
+      assertSame(this, derived);
+      return this._x;
+  }});
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 'derived'
+  };
+  Derived.prototype.testGetter = function() {
+    return super[x];
+  }.toMethod(Derived.prototype);
+  Derived.prototype.testGetterStrict = function() {
+    'use strict';
+    return super[x];
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testGetterWithToString = function() {
+    var toStringCalled;
+    var o = { toString: function() {
+      toStringCalled++;
+      return '42';
+    } };
+
+    toStringCalled = 0;
+    assertEquals('derived', super[o]);
+    assertEquals(1, toStringCalled);
+
+    var eToThrow = new Error();
+    var oThrowsInToString = { toString: function() {
+      throw eToThrow;
+    } };
+
+    var ex = null;
+    try {
+      super[oThrowsInToString];
+    } catch(e) { ex = e }
+    assertEquals(eToThrow, ex);
+
+    var oReturnsNumericString = { toString: function() {
+      return "42";
+    } };
+
+    assertEquals('derived', super[oReturnsNumericString]);
+    assertEquals('derived', super[42]);
+  }.toMethod(Derived.prototype);
+  derived = new Derived();
+  assertEquals('derived', derived.testGetter());
+  derived = new Derived();
+  assertEquals('derived', derived.testGetterStrict());
+  derived = new Derived();
+  derived.testGetterWithToString();
+}());
+
+
 (function TestSetter() {
   function Base() {}
   Base.prototype = {
@@ -92,24 +302,37 @@
     _x: 'derived'
   };
   Derived.prototype.testSetter = function() {
-      super.x = 'foobar';
-    }.toMethod(Derived.prototype);
+    assertEquals('foobar', super.x = 'foobar');
+    assertEquals('foobarabc', super.x += 'abc');
+  }.toMethod(Derived.prototype);
   var d = new Derived();
   d.testSetter();
   assertEquals('base', Base.prototype._x);
-  assertEquals('foobar', d._x);
+  assertEquals('foobarabc', d._x);
+  d._x = '';
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    assertEquals('foobar', super.x = 'foobar');
+    assertEquals('foobarabc', super.x += 'abc');
+  }.toMethod(Derived.prototype);
+  d.testSetterStrict();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
 }());
 
 
-(function TestKeyedGetter() {
+(function TestSetterNumericKeyed() {
+  var x = 42;
   function Base() {}
   Base.prototype = {
     constructor: Base,
     _x: 'base'
   };
 
-  Object.defineProperty(Base.prototype, '0',
-        { get: function() { return this._x; } });
+  Object.defineProperty(Base.prototype, x,
+    { get: function() { return this._x; },
+      set: function(v) { this._x = v; }
+    });
 
   function Derived() {}
   Derived.__proto__ = Base;
@@ -118,10 +341,1581 @@
     constructor: Derived,
     _x: 'derived'
   };
-  Derived.prototype.testGetter = function() {
-      return super[0];
-    }.toMethod(Derived.prototype);
-  assertEquals('derived', new Derived()[0]);
-  // assertEquals('derived', new Derived().testGetter());
+  Derived.prototype.testSetter = function() {
+    assertEquals('foobar', super[x] = 'foobar');
+    assertEquals('foobarabc', super[x] += 'abc');
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.testSetter();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
+  d._x = '';
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    assertEquals('foobar', super[x] = 'foobar');
+    assertEquals('foobarabc', super[x] += 'abc');
+  }.toMethod(Derived.prototype);
+  d.testSetterStrict();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
+
+
+  Derived.prototype.testSetterWithToString = function() {
+    var toStringCalled;
+    var o = { toString: function() {
+      toStringCalled++;
+      return x;
+    } };
+
+    toStringCalled = 0;
+    super[o] = 'set';
+    assertEquals(1, toStringCalled);
+    assertEquals('set', this._x);
+
+    var eToThrow = new Error();
+    var oThrowsInToString = { toString: function() {
+      throw eToThrow;
+    } };
+
+    var ex = null;
+    try {
+      super[oThrowsInToString] = 'xyz';
+    } catch(e) { ex = e }
+    assertEquals(eToThrow, ex);
+    assertEquals('set', this._x);
+  }.toMethod(Derived.prototype);
+  d = new Derived();
+  d.testSetterWithToString();
 }());
-*/
+
+
+(function TestSetterKeyed() {
+  var x = 'x';
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      return this._x;
+    },
+    set x(v) {
+      this._x = v;
+    },
+    _x: 'base'
+  };
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 'derived'
+  };
+  Derived.prototype.testSetter = function() {
+    assertEquals('foobar', super[x] = 'foobar');
+    assertEquals('foobarabc', super[x] += 'abc');
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.testSetter();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
+  d._x = '';
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    assertEquals('foobar', super[x] = 'foobar');
+    assertEquals('foobarabc', super[x] += 'abc');
+  }.toMethod(Derived.prototype);
+  d.testSetterStrict();
+  assertEquals('base', Base.prototype._x);
+  assertEquals('foobarabc', d._x);
+
+
+  Derived.prototype.testSetterWithToString = function() {
+    var toStringCalled;
+    var o = { toString: function() {
+      toStringCalled++;
+      return 'x';
+    } };
+
+    toStringCalled = 0;
+    super[o] = 'set';
+    assertEquals(1, toStringCalled);
+    assertEquals('set', this._x);
+
+    var eToThrow = new Error();
+    var oThrowsInToString = { toString: function() {
+      throw eToThrow;
+    } };
+
+    var ex = null;
+    try {
+      super[oThrowsInToString] = 'xyz';
+    } catch(e) { ex = e }
+    assertEquals(eToThrow, ex);
+    assertEquals('set', this._x);
+
+    var oReturnsNumericString = { toString: function() {
+      return "1";
+    } };
+
+    assertEquals('abc', super[oReturnsNumericString] = 'abc');
+
+    assertEquals('set', this._x);
+
+    assertEquals(10,  super[1] = 10);
+  }.toMethod(Derived.prototype);
+  d = new Derived();
+  d.testSetterWithToString();
+}());
+
+
+(function TestSetterDataProperties() {
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    x: 'x from Base'
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testSetter = function() {
+    assertEquals('x from Base', super.x);
+    super.x = 'data property';
+    assertEquals('x from Base', super.x);
+    assertEquals('data property', this.x);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testSetter();
+}());
+
+
+(function TestKeyedSetterDataProperties() {
+  var x = 'x';
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    x: 'x from Base'
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testSetter = function() {
+    assertEquals('x from Base', super[x]);
+    super[x] = 'data property';
+    assertEquals('x from Base', super[x]);
+    assertEquals('data property', this[x]);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testSetter();
+}());
+
+
+(function TestKeyedNumericSetterDataProperties() {
+  var x = 42;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    42: 'x from Base'
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testSetter = function() {
+    assertEquals('x from Base', super[x]);
+    super[x] = 'data property';
+    assertEquals('x from Base', super[x]);
+    assertEquals('data property', this[x]);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testSetter();
+}());
+
+
+(function TestAccessorsOnPrimitives() {
+  var getCalled = 0;
+  var setCalled = 0;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      getCalled++;
+      return 1;
+    },
+    set x(v) {
+      setCalled++;
+      return v;
+    },
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+  Derived.prototype.testSetter = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals('object', typeof this);
+    assertTrue(this instanceof Number)
+    assertEquals(42, this.valueOf());
+    assertEquals(1, super.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super.x = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super.x += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    super.newProperty = 15;
+    assertEquals(15, this.newProperty);
+    assertEquals(undefined, super.newProperty);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    getCalled = 0;
+    setCalled = 0;
+    assertTrue(42 === this);
+
+    assertEquals(1, super.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super.x = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super.x += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    var ex;
+    try {
+      super.newProperty = 15;
+    } catch (e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetter.call(42);
+  Derived.prototype.testSetterStrict.call(42);
+
+  function DerivedFromString() {}
+  DerivedFromString.prototype = Object.create(String.prototype);
+
+  function f() {
+    'use strict';
+    assertTrue(42 === this);
+    assertEquals(String.prototype.toString, super.toString);
+    var ex;
+    try {
+      super.toString();
+    } catch(e) { ex = e; }
+
+    assertTrue(ex instanceof TypeError);
+  }
+  f.toMethod(DerivedFromString.prototype).call(42);
+}());
+
+
+(function TestKeyedAccessorsOnPrimitives() {
+  var x = 'x';
+  var newProperty = 'newProperty';
+  var toString = 'toString';
+  var getCalled = 0;
+  var setCalled = 0;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      getCalled++;
+      return 1;
+    },
+    set x(v) {
+      setCalled++;
+      return v;
+    },
+  };
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+  Derived.prototype.testSetter = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals('object', typeof this);
+    assertTrue(this instanceof Number)
+    assertEquals(42, this.valueOf());
+    assertEquals(1, super[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super[x] = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super[x] += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    super[newProperty] = 15;
+    assertEquals(15, this[newProperty]);
+    assertEquals(undefined, super[newProperty]);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    getCalled = 0;
+    setCalled = 0;
+    assertTrue(42 === this);
+
+    assertEquals(1, super[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super[x] = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super[x] += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    var ex;
+    try {
+      super[newProperty] = 15;
+    } catch (e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetter.call(42);
+  Derived.prototype.testSetterStrict.call(42);
+
+  function DerivedFromString() {}
+  DerivedFromString.prototype = Object.create(String.prototype);
+
+  function f() {
+    'use strict';
+    assertTrue(42 === this);
+    assertEquals(String.prototype.toString, super[toString]);
+    var ex;
+    try {
+      super[toString]();
+    } catch(e) { ex = e; }
+
+    assertTrue(ex instanceof TypeError);
+  }
+  f.toMethod(DerivedFromString.prototype).call(42);
+}());
+
+
+(function TestNumericKeyedAccessorsOnPrimitives() {
+  var x = 42;
+  var newProperty = 43;
+  var getCalled = 0;
+  var setCalled = 0;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+  };
+
+  Object.defineProperty(Base.prototype, x, {
+    get: function() {
+      getCalled++;
+      return 1;
+    },
+    set: function(v) {
+      setCalled++;
+      return v;
+    }
+  });
+
+  function Derived() {}
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+  Derived.prototype.testSetter = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals('object', typeof this);
+    assertTrue(this instanceof Number)
+    assertEquals(42, this.valueOf());
+    assertEquals(1, super[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super[x] = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super[x] += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    super[newProperty] = 15;
+    assertEquals(15, this[newProperty]);
+    assertEquals(undefined, super[newProperty]);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetterStrict = function() {
+    'use strict';
+    getCalled = 0;
+    setCalled = 0;
+    assertTrue(42 === this);
+
+    assertEquals(1, super[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    assertEquals(5, super[x] = 5);
+    assertEquals(1, getCalled);
+    assertEquals(1, setCalled);
+
+    assertEquals(6, super[x] += 5);
+    assertEquals(2, getCalled);
+    assertEquals(2, setCalled);
+
+    var ex;
+    try {
+      super[newProperty] = 15;
+    } catch (e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.testSetter.call(42);
+  Derived.prototype.testSetterStrict.call(42);
+}());
+
+
+(function TestKeyedNumericSetterOnExotics() {
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__: Base.prototype };
+
+  Derived.prototype.callSetterOnArray = function() {
+    super[42] = 1;
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.callStrictSetterOnString = function() {
+    'use strict';
+    assertEquals('string', typeof this);
+    assertTrue('abcdef' === this);
+    var ex = null;
+    try {
+      super[5] = 'q';
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+
+    ex = null;
+    try {
+      super[1024] = 'q';
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+  }.toMethod(Derived.prototype);
+
+  var x = [];
+  assertEquals(0, x.length);
+  Derived.prototype.callSetterOnArray.call(x);
+  assertEquals(43, x.length);
+  assertEquals(1, x[42]);
+
+  var s = 'abcdef';
+  Derived.prototype.callStrictSetterOnString.call(s)
+}());
+
+
+(function TestSetterUndefinedProperties() {
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  Derived.prototype.mSloppy = function () {
+    assertEquals(undefined, super.x);
+    assertEquals(undefined, this.x);
+    super.x = 10;
+    assertEquals(10, this.x);
+    assertEquals(undefined, super.x);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function () {
+    'use strict';
+    assertEquals(undefined, super.x);
+    assertEquals(undefined, this.x);
+    super.x = 10;
+    assertEquals(10, this.x);
+    assertEquals(undefined, super.x);
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.mSloppy();
+  assertEquals(10, d.x);
+  var d1 = new Derived();
+  d1.mStrict();
+  assertEquals(10, d.x);
+}());
+
+
+(function TestKeyedSetterUndefinedProperties() {
+  var x = 'x';
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  Derived.prototype.mSloppy = function () {
+    assertEquals(undefined, super[x]);
+    assertEquals(undefined, this[x]);
+    super[x] = 10;
+    assertEquals(10, this[x]);
+    assertEquals(undefined, super[x]);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function () {
+    'use strict';
+    assertEquals(undefined, super[x]);
+    assertEquals(undefined, this[x]);
+    super[x] = 10;
+    assertEquals(10, this[x]);
+    assertEquals(undefined, super[x]);
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.mSloppy();
+  assertEquals(10, d.x);
+  var d1 = new Derived();
+  d1.mStrict();
+  assertEquals(10, d.x);
+}());
+
+
+(function TestKeyedNumericSetterUndefinedProperties() {
+  var x = 42;
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  Derived.prototype.mSloppy = function () {
+    assertEquals(undefined, super[x]);
+    assertEquals(undefined, this[x]);
+    super[x] = 10;
+    assertEquals(10, this[x]);
+    assertEquals(undefined, super[x]);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function () {
+    'use strict';
+    assertEquals(undefined, super[x]);
+    assertEquals(undefined, this[x]);
+    super[x] = 10;
+    assertEquals(10, this[x]);
+    assertEquals(undefined, super[x]);
+  }.toMethod(Derived.prototype);
+  var d = new Derived();
+  d.mSloppy();
+  assertEquals(10, d[x]);
+  var d1 = new Derived();
+  d1.mStrict();
+  assertEquals(10, d[x]);
+}());
+
+
+(function TestSetterCreatingOwnProperties() {
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  var setterCalled;
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(42, this.ownReadOnly);
+    super.ownReadOnly = 55;
+    assertEquals(42, this.ownReadOnly);
+
+    assertEquals(15, this.ownReadonlyAccessor);
+    super.ownReadonlyAccessor = 55;
+    assertEquals(15, this.ownReadonlyAccessor);
+
+    setterCalled = 0;
+    super.ownSetter = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(42, this.ownReadOnly);
+    var ex;
+    try {
+      super.ownReadOnly = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(42, this.ownReadOnly);
+
+    assertEquals(15, this.ownReadonlyAccessor);
+    ex = null;
+    try {
+      super.ownReadonlyAccessor = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(15, this.ownReadonlyAccessor);
+
+    setterCalled = 0;
+    super.ownSetter = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false });
+  Object.defineProperty(d, 'ownSetter',
+      { set : function() { setterCalled++; } });
+  Object.defineProperty(d, 'ownReadonlyAccessor',
+      { get : function() { return 15; }});
+  d.mSloppy();
+  d.mStrict();
+}());
+
+
+(function TestSetterInForIn() {
+  var setCalled = 0;
+  var getCalled = 0;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      getCalled++;
+      return 1;
+    },
+    set x(v) {
+      setCalled++;
+      this.x_.push(v);
+    },
+  };
+
+  function Derived() {
+    this.x_ = [];
+  }
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+  };
+
+  Derived.prototype.testIter = function() {
+    setCalled = 0;
+    getCalled = 0;
+    for (super.x in [1,2,3]) {}
+    assertEquals(0, getCalled);
+    assertEquals(3, setCalled);
+    assertEquals(["0","1","2"], this.x_);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testIter();
+
+  var x = 'x';
+  Derived.prototype.testIterKeyed = function() {
+    setCalled = 0;
+    getCalled = 0;
+    for (super[x] in [1,2,3]) {}
+    assertEquals(0, getCalled);
+    assertEquals(3, setCalled);
+    assertEquals(["0","1","2"], this.x_);
+
+    this.x_ = [];
+    setCalled = 0;
+    getCalled = 0;
+    var toStringCalled = 0;
+    var o = {toString: function () { toStringCalled++; return x }};
+    for (super[o] in [1,2,3]) {}
+    assertEquals(0, getCalled);
+    assertEquals(3, setCalled);
+    assertEquals(3, toStringCalled);
+    assertEquals(["0","1","2"], this.x_);
+  }.toMethod(Derived.prototype);
+
+  new Derived().testIterKeyed();
+}());
+
+
+(function TestKeyedSetterCreatingOwnProperties() {
+  var ownReadOnly = 'ownReadOnly';
+  var ownReadonlyAccessor = 'ownReadonlyAccessor';
+  var ownSetter = 'ownSetter';
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  var setterCalled;
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(42, this[ownReadOnly]);
+    super[ownReadOnly] = 55;
+    assertEquals(42, this[ownReadOnly]);
+
+    assertEquals(15, this[ownReadonlyAccessor]);
+    super[ownReadonlyAccessor] = 55;
+    assertEquals(15, this[ownReadonlyAccessor]);
+
+    setterCalled = 0;
+    super[ownSetter] = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(42, this[ownReadOnly]);
+    var ex;
+    try {
+      super[ownReadOnly] = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(42, this[ownReadOnly]);
+
+    assertEquals(15, this[ownReadonlyAccessor]);
+    ex = null;
+    try {
+      super[ownReadonlyAccessor] = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(15, this[ownReadonlyAccessor]);
+
+    setterCalled = 0;
+    super[ownSetter] = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false });
+  Object.defineProperty(d, 'ownSetter',
+      { set : function() { setterCalled++; } });
+  Object.defineProperty(d, 'ownReadonlyAccessor',
+      { get : function() { return 15; }});
+  d.mSloppy();
+  d.mStrict();
+}());
+
+
+(function TestKeyedNumericSetterCreatingOwnProperties() {
+  var ownReadOnly = 42;
+  var ownReadonlyAccessor = 43;
+  var ownSetter = 44;
+  function Base() {}
+  function Derived() {}
+  Derived.prototype = { __proto__ : Base.prototype };
+  var setterCalled;
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(42, this[ownReadOnly]);
+    super[ownReadOnly] = 55;
+    assertEquals(42, this[ownReadOnly]);
+
+    assertEquals(15, this[ownReadonlyAccessor]);
+    super[ownReadonlyAccessor] = 55;
+    assertEquals(15, this[ownReadonlyAccessor]);
+
+    setterCalled = 0;
+    super[ownSetter] = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(42, this[ownReadOnly]);
+    var ex;
+    try {
+      super[ownReadOnly] = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(42, this[ownReadOnly]);
+
+    assertEquals(15, this[ownReadonlyAccessor]);
+    ex = null;
+    try {
+      super[ownReadonlyAccessor] = 55;
+    } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(15, this[ownReadonlyAccessor]);
+
+    setterCalled = 0;
+    super[ownSetter] = 42;
+    assertEquals(1, setterCalled);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, ownReadOnly, { value : 42, writable : false });
+  Object.defineProperty(d, ownSetter,
+      { set : function() { setterCalled++; } });
+  Object.defineProperty(d, ownReadonlyAccessor,
+      { get : function() { return 15; }});
+  d.mSloppy();
+  d.mStrict();
+}());
+
+
+(function TestSetterNoProtoWalk() {
+  function Base() {}
+  function Derived() {}
+  var getCalled;
+  var setCalled;
+  Derived.prototype = {
+    __proto__ : Base.prototype,
+    get x() { getCalled++; return 42; },
+    set x(v) { setCalled++; }
+  };
+
+  Derived.prototype.mSloppy = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this.x = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super.x = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this.x);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this.x);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this.x = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super.x = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this.x);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestKeyedSetterNoProtoWalk() {
+  var x = 'x';
+  function Base() {}
+  function Derived() {}
+  var getCalled;
+  var setCalled;
+  Derived.prototype = {
+    __proto__ : Base.prototype,
+    get x() { getCalled++; return 42; },
+    set x(v) { setCalled++; }
+  };
+
+  Derived.prototype.mSloppy = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this[x] = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super[x] = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this[x]);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this[x] = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super[x] = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this[x]);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestKeyedNumericSetterNoProtoWalk() {
+  var x = 42;
+  function Base() {}
+  function Derived() {}
+  var getCalled;
+  var setCalled;
+  Derived.prototype = {
+    __proto__ : Base.prototype,
+  };
+
+  Object.defineProperty(Derived.prototype, x, {
+    get: function() { getCalled++; return 42; },
+    set: function(v) { setCalled++; }
+  });
+
+  Derived.prototype.mSloppy = function() {
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this[x] = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super[x] = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this[x]);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    setCalled = 0;
+    getCalled = 0;
+    assertEquals(42, this[x]);
+    assertEquals(1, getCalled);
+    assertEquals(0, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    this[x] = 43;
+    assertEquals(0, getCalled);
+    assertEquals(1, setCalled);
+
+    getCalled = 0;
+    setCalled = 0;
+    super[x] = 15;
+    assertEquals(0, setCalled);
+    assertEquals(0, getCalled);
+
+    assertEquals(15, this[x]);
+    assertEquals(0, getCalled);
+    assertEquals(0, setCalled);
+
+  }.toMethod(Derived.prototype);
+
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestSetterDoesNotReconfigure() {
+  function Base() {}
+  function Derived() {}
+
+  Derived.prototype.mStrict = function (){
+    'use strict';
+    super.nonEnumConfig = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
+    assertEquals(5, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super.nonEnumNonConfig = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
+    assertEquals(5, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mSloppy = function (){
+    super.nonEnumConfig = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
+    assertEquals(42, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super.nonEnumNonConfig = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
+    assertEquals(42, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, 'nonEnumConfig',
+      { value : 0, enumerable : false, configurable : true, writable : true });
+  Object.defineProperty(d, 'nonEnumNonConfig',
+      { value : 0, enumerable : false, configurable : false, writable : true });
+  d.mStrict();
+  d.mSloppy();
+}());
+
+
+(function TestKeyedSetterDoesNotReconfigure() {
+  var nonEnumConfig = 'nonEnumConfig';
+  var nonEnumNonConfig = 'nonEnumNonConfig';
+  function Base() {}
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype };
+
+  Derived.prototype.mStrict = function (){
+    'use strict';
+    super[nonEnumConfig] = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+    assertEquals(5, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super[nonEnumNonConfig] = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+    assertEquals(5, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mSloppy = function (){
+    super[nonEnumConfig] = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+    assertEquals(42, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super[nonEnumNonConfig] = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+    assertEquals(42, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, nonEnumConfig,
+      { value : 0, enumerable : false, configurable : true, writable : true });
+  Object.defineProperty(d, nonEnumNonConfig,
+      { value : 0, enumerable : false, configurable : false, writable : true });
+  d.mStrict();
+  d.mSloppy();
+}());
+
+
+(function TestKeyedNumericSetterDoesNotReconfigure() {
+  var nonEnumConfig = 42;
+  var nonEnumNonConfig = 43;
+  function Base() {}
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype };
+
+  Derived.prototype.mStrict = function (){
+    'use strict';
+    super[nonEnumConfig] = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+    assertEquals(5, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super[nonEnumNonConfig] = 5;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+    assertEquals(5, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  Derived.prototype.mSloppy = function (){
+    super[nonEnumConfig] = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+    assertEquals(42, d1.value);
+    assertTrue(d1.configurable);
+    assertFalse(d1.enumerable);
+
+    super[nonEnumNonConfig] = 42;
+    var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+    assertEquals(42, d1.value);
+    assertFalse(d1.configurable);
+    assertFalse(d1.enumerable);
+  }.toMethod(Derived.prototype);
+
+  var d = new Derived();
+  Object.defineProperty(d, nonEnumConfig,
+      { value : 0, enumerable : false, configurable : true, writable : true });
+  Object.defineProperty(d, nonEnumNonConfig,
+      { value : 0, enumerable : false, configurable : false, writable : true });
+  d.mStrict();
+  d.mSloppy();
+}());
+
+
+(function TestCountOperations() {
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      return this._x;
+    },
+    set x(v) {
+      this._x = v;
+    },
+    _x: 1
+  };
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 2
+  };
+
+  Derived.prototype.testCounts = function() {
+    assertEquals(2, this._x);
+    assertEquals(2, super.x);
+    super.x++;
+    assertEquals(3, super.x);
+    ++super.x;
+    assertEquals(4, super.x);
+    assertEquals(4, super.x++);
+    assertEquals(5, super.x);
+    assertEquals(6, ++super.x);
+    assertEquals(6, super.x);
+    assertEquals(6, this._x);
+
+    super.x--;
+    assertEquals(5, super.x);
+    --super.x;
+    assertEquals(4, super.x);
+    assertEquals(4, super.x--);
+    assertEquals(3, super.x);
+    assertEquals(2, --super.x);
+    assertEquals(2, super.x);
+    assertEquals(2, this._x);
+  }.toMethod(Derived.prototype);
+  new Derived().testCounts();
+}());
+
+
+(function TestKeyedCountOperations() {
+  var x = 'x';
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    get x() {
+      return this._x;
+    },
+    set x(v) {
+      this._x = v;
+    },
+    _x: 1
+  };
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 2
+  };
+
+  Derived.prototype.testCounts = function() {
+    assertEquals(2, this._x);
+    assertEquals(2, super[x]);
+    super[x]++;
+    assertEquals(3, super[x]);
+    ++super[x];
+    assertEquals(4, super[x]);
+    assertEquals(4, super[x]++);
+    assertEquals(5, super[x]);
+    assertEquals(6, ++super[x]);
+    assertEquals(6, super[x]);
+    assertEquals(6, this._x);
+
+    super[x]--;
+    assertEquals(5, super[x]);
+    --super[x];
+    assertEquals(4, super[x]);
+    assertEquals(4, super[x]--);
+    assertEquals(3, super[x]);
+    assertEquals(2, --super[x]);
+    assertEquals(2, super[x]);
+    assertEquals(2, this._x);
+  }.toMethod(Derived.prototype);
+  new Derived().testCounts();
+}());
+
+
+(function TestKeyedNumericCountOperations() {
+  var x = 42;
+  function Base() {}
+  Base.prototype = {
+    constructor: Base,
+    _x: 1
+  };
+
+  Object.defineProperty(Base.prototype, x, {
+    get: function() { return this._x; },
+    set: function(v) { this._x = v;; }
+  });
+
+  function Derived() {}
+  Derived.__proto__ = Base;
+  Derived.prototype = {
+    __proto__: Base.prototype,
+    constructor: Derived,
+    _x: 2
+  };
+
+  Derived.prototype.testCounts = function() {
+    assertEquals(2, this._x);
+    assertEquals(2, super[x]);
+    super[x]++;
+    assertEquals(3, super[x]);
+    ++super[x];
+    assertEquals(4, super[x]);
+    assertEquals(4, super[x]++);
+    assertEquals(5, super[x]);
+    assertEquals(6, ++super[x]);
+    assertEquals(6, super[x]);
+    assertEquals(6, this._x);
+
+    super[x]--;
+    assertEquals(5, super[x]);
+    --super[x];
+    assertEquals(4, super[x]);
+    assertEquals(4, super[x]--);
+    assertEquals(3, super[x]);
+    assertEquals(2, --super[x]);
+    assertEquals(2, super[x]);
+    assertEquals(2, this._x);
+  }.toMethod(Derived.prototype);
+  new Derived().testCounts();
+}());
+
+
+(function TestSetterSuperNonWritable() {
+  function Base() {}
+  Object.defineProperty(Base.prototype, 'x', { value : 27, writable: false });
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(27, super.x);
+    assertEquals(27, this.x);
+    super.x = 10;
+    assertEquals(27, super.x);
+    assertEquals(27, this.x);
+  }.toMethod(Derived.prototype);
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(27, super.x);
+    assertEquals(27, this.x);
+    var ex = null;
+    try { super.x = 10; } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(27, super.x);
+    assertEquals(27, this.x);
+  }.toMethod(Derived.prototype);
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestSetterKeyedSuperNonWritable() {
+  var x = 'xyz';
+  function Base() {}
+  Object.defineProperty(Base.prototype, x, { value : 27, writable: false });
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+    super[x] = 10;
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+  }.toMethod(Derived.prototype);
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+    var ex = null;
+    try { super[x] = 10; } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+  }.toMethod(Derived.prototype);
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+(function TestSetterKeyedNumericSuperNonWritable() {
+  var x = 42;
+  function Base() {}
+  Object.defineProperty(Base.prototype, x, { value : 27, writable: false });
+  function Derived() {}
+
+  Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+  Derived.prototype.mSloppy = function() {
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+    super[x] = 10;
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+  }.toMethod(Derived.prototype);
+  Derived.prototype.mStrict = function() {
+    'use strict';
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+    var ex = null;
+    try { super[x] = 10; } catch(e) { ex = e; }
+    assertTrue(ex instanceof TypeError);
+    assertEquals(27, super[x]);
+    assertEquals(27, this[x]);
+  }.toMethod(Derived.prototype);
+  new Derived().mSloppy();
+  new Derived().mStrict();
+}());
+
+
+function Subclass(base, constructor) {
+  var homeObject = {
+    __proto__: base.prototype,
+    constructor: constructor
+  };
+  constructor.__proto__ = base;
+  constructor.prototype = homeObject;
+  // not doing toMethod: home object is not required for
+  // super constructor calls.
+  return constructor;
+}
+
+(function TestSuperCall() {
+  var baseCalled = 0;
+  var derivedCalled = 0;
+  var derivedDerivedCalled = 0;
+
+  function Base() {
+    baseCalled++;
+  }
+
+  var Derived = Subclass(Base, function () {
+    super();
+    derivedCalled++;
+  });
+
+  assertEquals(Base, Base.prototype.constructor);
+  assertEquals(Base.prototype, Derived.prototype.__proto__);
+
+  baseCalled = 0;
+  derivedCalled = 0;
+  new Derived();
+  assertEquals(1, baseCalled);
+  assertEquals(1, derivedCalled);
+
+  var DerivedDerived = Subclass(Derived, function () {
+    super();
+    derivedDerivedCalled++;
+  });
+
+  baseCalled = 0;
+  derivedCalled = 0;
+  derivedDerivedCalled = 0;
+  new DerivedDerived();
+  assertEquals(1, baseCalled);
+  assertEquals(1, derivedCalled);
+  assertEquals(1, derivedDerivedCalled);
+
+  function Base2(v) {
+    this.fromBase = v;
+  }
+  var Derived2 = Subclass(Base2, function (v1, v2) {
+    super(v1);
+    this.fromDerived = v2;
+  });
+
+  var d = new Derived2("base", "derived");
+  assertEquals("base", d.fromBase);
+  assertEquals("derived", d.fromDerived);
+
+  function ImplicitSubclassOfFunction() {
+    super();
+    this.x = 123;
+  }
+
+  var o = new ImplicitSubclassOfFunction();
+  assertEquals(123, o.x);
+
+  var calls = 0;
+  function G() {
+    calls++;
+  }
+  function F() {
+    super();
+  }
+  F.__proto__ = G;
+  new F();
+  assertEquals(1, calls);
+  F.__proto__ = function() {};
+  new F();
+  assertEquals(1, calls);
+}());
+
+
+(function TestNewSuper() {
+  var baseCalled = 0;
+  var derivedCalled = 0;
+
+  function Base() {
+    baseCalled++;
+    this.x = 15;
+  }
+
+
+  var Derived = Subclass(Base, function() {
+    baseCalled = 0;
+    var b = new super();
+    assertEquals(1, baseCalled)
+    assertEquals(Base.prototype, b.__proto__);
+    assertEquals(15, b.x);
+    assertEquals(undefined, this.x);
+    derivedCalled++;
+  });
+
+  derivedCalled = 0;
+  new Derived();
+  assertEquals(1, derivedCalled);
+}());
+
+
+(function TestSuperCallErrorCases() {
+  function T() {
+    super();
+  }
+  T.__proto__ = null;
+  // Spec says ReferenceError here, but for other IsCallable failures
+  // we throw TypeError.
+  // Filed https://bugs.ecmascript.org/show_bug.cgi?id=3282
+  assertThrows(function() { new T(); }, TypeError);
+
+  function T1() {
+    var b = new super();
+  }
+  T1.__proto = null;
+  assertThrows(function() { new T1(); }, TypeError);
+}());
+
+
+(function TestSuperCallSyntacticRestriction() {
+  assertThrows(function() {
+    function C() {
+        var y;
+        super();
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(this.x);
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(this);
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(1, 2, Object.getPrototypeOf(this));
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      { super(1, 2); }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      if (1) super();
+    }; new C();
+  }, TypeError);
+
+  function C1() {
+    'use strict';
+    super();
+  };
+  new C1();
+
+  function C2() {
+    ; 'use strict';;;;;
+    super();
+  };
+  new C2();
+
+  function C3() {
+    ; 'use strict';;;;;
+    // This is a comment.
+    super();
+  }
+  new C3();
+}());
diff --git a/test/mjsunit/harmony/templates.js b/test/mjsunit/harmony/templates.js
new file mode 100644
index 0000000..c339bb8
--- /dev/null
+++ b/test/mjsunit/harmony/templates.js
@@ -0,0 +1,507 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-templates --harmony-unicode
+
+var num = 5;
+var str = "str";
+function fn() { return "result"; }
+var obj = {
+  num: num,
+  str: str,
+  fn: function() { return "result"; }
+};
+
+(function testBasicExpressions() {
+  assertEquals("foo 5 bar", `foo ${num} bar`);
+  assertEquals("foo str bar", `foo ${str} bar`);
+  assertEquals("foo [object Object] bar", `foo ${obj} bar`);
+  assertEquals("foo result bar", `foo ${fn()} bar`);
+  assertEquals("foo 5 bar", `foo ${obj.num} bar`);
+  assertEquals("foo str bar", `foo ${obj.str} bar`);
+  assertEquals("foo result bar", `foo ${obj.fn()} bar`);
+})();
+
+(function testExpressionsContainingTemplates() {
+  assertEquals("foo bar 5", `foo ${`bar ${num}`}`);
+})();
+
+(function testMultilineTemplates() {
+  assertEquals("foo\n    bar\n    baz", `foo
+    bar
+    baz`);
+
+  assertEquals("foo\n  bar\n  baz", eval("`foo\r\n  bar\r  baz`"));
+})();
+
+(function testLineContinuation() {
+  assertEquals("\n", `\
+
+`);
+})();
+
+(function testTaggedTemplates() {
+  var calls = 0;
+  (function(s) {
+    calls++;
+  })`test`;
+  assertEquals(1, calls);
+
+  calls = 0;
+  // assert tag is invoked in right context
+  obj = {
+    fn: function() {
+      calls++;
+      assertEquals(obj, this);
+    }
+  };
+
+  obj.fn`test`;
+  assertEquals(1, calls);
+
+  calls = 0;
+  // Simple templates only have a callSiteObj
+  (function(s) {
+    calls++;
+    assertEquals(1, arguments.length);
+  })`test`;
+  assertEquals(1, calls);
+
+  // Templates containing expressions have the values of evaluated expressions
+  calls = 0;
+  (function(site, n, s, o, f, r) {
+    calls++;
+    assertEquals(6, arguments.length);
+    assertEquals("number", typeof n);
+    assertEquals("string", typeof s);
+    assertEquals("object", typeof o);
+    assertEquals("function", typeof f);
+    assertEquals("result", r);
+  })`${num}${str}${obj}${fn}${fn()}`;
+  assertEquals(1, calls);
+
+  // The TV and TRV of NoSubstitutionTemplate :: `` is the empty code unit
+  // sequence.
+  calls = 0;
+  (function(s) {
+    calls++;
+    assertEquals(1, s.length);
+    assertEquals(1, s.raw.length);
+    assertEquals("", s[0]);
+
+    // Failure: expected <""> found <"foo  barfoo  barfoo foo foo foo testtest">
+    assertEquals("", s.raw[0]);
+  })``;
+  assertEquals(1, calls);
+
+  // The TV and TRV of TemplateHead :: `${ is the empty code unit sequence.
+  calls = 0;
+  (function(s) {
+    calls++;
+    assertEquals(2, s.length);
+    assertEquals(2, s.raw.length);
+    assertEquals("", s[0]);
+    assertEquals("", s.raw[0]);
+  })`${1}`;
+  assertEquals(1, calls);
+
+  // The TV and TRV of TemplateMiddle :: }${ is the empty code unit sequence.
+  calls = 0;
+  (function(s) {
+    calls++;
+    assertEquals(3, s.length);
+    assertEquals(3, s.raw.length);
+    assertEquals("", s[1]);
+    assertEquals("", s.raw[1]);
+  })`${1}${2}`;
+  assertEquals(1, calls);
+
+  // The TV and TRV of TemplateTail :: }` is the empty code unit sequence.
+  calls = 0;
+  (function(s) {
+    calls++;
+    assertEquals(2, s.length);
+    assertEquals(2, s.raw.length);
+    assertEquals("", s[1]);
+    assertEquals("", s.raw[1]);
+  })`${1}`;
+  assertEquals(1, calls);
+
+  // The TV of NoSubstitutionTemplate :: ` TemplateCharacters ` is the TV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("foo", s[0]); })`foo`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateHead :: ` TemplateCharacters ${ is the TV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("foo", s[0]); })`foo${1}`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateMiddle :: } TemplateCharacters ${ is the TV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("foo", s[1]); })`${1}foo${2}`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateTail :: } TemplateCharacters ` is the TV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("foo", s[1]); })`${1}foo`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateCharacters :: TemplateCharacter is the TV of
+  // TemplateCharacter.
+  calls = 0;
+  (function(s) { calls++; assertEquals("f", s[0]); })`f`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateCharacter :: $ is the code unit value 0x0024.
+  calls = 0;
+  (function(s) { calls++; assertEquals("$", s[0]); })`$`;
+  assertEquals(1, calls);
+
+  // The TV of TemplateCharacter :: \ EscapeSequence is the CV of
+  // EscapeSequence.
+  calls = 0;
+  (function(s) { calls++; assertEquals("안녕", s[0]); })`\uc548\uB155`;
+  (function(s) { calls++; assertEquals("\xff", s[0]); })`\xff`;
+  (function(s) { calls++; assertEquals("\n", s[0]); })`\n`;
+  assertEquals(3, calls);
+
+  // The TV of TemplateCharacter :: LineContinuation is the TV of
+  // LineContinuation. The TV of LineContinuation :: \ LineTerminatorSequence is
+  // the empty code unit sequence.
+  calls = 0;
+  (function(s) { calls++; assertEquals("", s[0]); })`\
+`;
+  assertEquals(1, calls);
+
+  // The TRV of NoSubstitutionTemplate :: ` TemplateCharacters ` is the TRV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("test", s.raw[0]); })`test`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateHead :: ` TemplateCharacters ${ is the TRV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("test", s.raw[0]); })`test${1}`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateMiddle :: } TemplateCharacters ${ is the TRV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("test", s.raw[1]); })`${1}test${2}`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateTail :: } TemplateCharacters ` is the TRV of
+  // TemplateCharacters.
+  calls = 0;
+  (function(s) { calls++; assertEquals("test", s.raw[1]); })`${1}test`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateCharacters :: TemplateCharacter is the TRV of
+  // TemplateCharacter.
+  calls = 0;
+  (function(s) { calls++; assertEquals("f", s.raw[0]); })`f`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateCharacter :: $ is the code unit value 0x0024.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u0024", s.raw[0]); })`$`;
+  assertEquals(1, calls);
+
+  // The TRV of EscapeSequence :: 0 is the code unit value 0x0030.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005C\u0030", s.raw[0]); })`\0`;
+  assertEquals(1, calls);
+
+  // The TRV of TemplateCharacter :: \ EscapeSequence is the sequence consisting
+  // of the code unit value 0x005C followed by the code units of TRV of
+  // EscapeSequence.
+
+  //   The TRV of EscapeSequence :: HexEscapeSequence is the TRV of the
+  //   HexEscapeSequence.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005Cxff", s.raw[0]); })`\xff`;
+  assertEquals(1, calls);
+
+  //   The TRV of EscapeSequence :: UnicodeEscapeSequence is the TRV of the
+  //   UnicodeEscapeSequence.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005Cuc548", s.raw[0]); })`\uc548`;
+  assertEquals(1, calls);
+
+  //   The TRV of CharacterEscapeSequence :: SingleEscapeCharacter is the TRV of
+  //   the SingleEscapeCharacter.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005C\u0027", s.raw[0]); })`\'`;
+  (function(s) { calls++; assertEquals("\u005C\u0022", s.raw[0]); })`\"`;
+  (function(s) { calls++; assertEquals("\u005C\u005C", s.raw[0]); })`\\`;
+  (function(s) { calls++; assertEquals("\u005Cb", s.raw[0]); })`\b`;
+  (function(s) { calls++; assertEquals("\u005Cf", s.raw[0]); })`\f`;
+  (function(s) { calls++; assertEquals("\u005Cn", s.raw[0]); })`\n`;
+  (function(s) { calls++; assertEquals("\u005Cr", s.raw[0]); })`\r`;
+  (function(s) { calls++; assertEquals("\u005Ct", s.raw[0]); })`\t`;
+  (function(s) { calls++; assertEquals("\u005Cv", s.raw[0]); })`\v`;
+  (function(s) { calls++; assertEquals("\u005C`", s.raw[0]); })`\``;
+  assertEquals(10, calls);
+
+  //   The TRV of CharacterEscapeSequence :: NonEscapeCharacter is the CV of the
+  //   NonEscapeCharacter.
+  calls = 0;
+  (function(s) { calls++; assertEquals("\u005Cz", s.raw[0]); })`\z`;
+  assertEquals(1, calls);
+
+  // The TRV of LineTerminatorSequence :: <LF> is the code unit value 0x000A.
+  // The TRV of LineTerminatorSequence :: <CR> is the code unit value 0x000A.
+  // The TRV of LineTerminatorSequence :: <CR><LF> is the sequence consisting of
+  // the code unit value 0x000A.
+  calls = 0;
+  function testRawLineNormalization(cs) {
+    calls++;
+    assertEquals(cs.raw[0], "\n\n\n");
+    assertEquals(cs.raw[1], "\n\n\n");
+  }
+  eval("testRawLineNormalization`\r\n\n\r${1}\r\n\n\r`");
+  assertEquals(1, calls);
+
+  // The TRV of LineContinuation :: \ LineTerminatorSequence is the sequence
+  // consisting of the code unit value 0x005C followed by the code units of TRV
+  // of LineTerminatorSequence.
+  calls = 0;
+  function testRawLineContinuation(cs) {
+    calls++;
+    assertEquals(cs.raw[0], "\u005C\n\u005C\n\u005C\n");
+    assertEquals(cs.raw[1], "\u005C\n\u005C\n\u005C\n");
+  }
+  eval("testRawLineContinuation`\\\r\n\\\n\\\r${1}\\\r\n\\\n\\\r`");
+  assertEquals(1, calls);
+})();
+
+
+(function testCallSiteObj() {
+  var calls = 0;
+  function tag(cs) {
+    calls++;
+    assertTrue(cs.hasOwnProperty("raw"));
+    assertTrue(Object.isFrozen(cs));
+    assertTrue(Object.isFrozen(cs.raw));
+    var raw = Object.getOwnPropertyDescriptor(cs, "raw");
+    assertFalse(raw.writable);
+    assertFalse(raw.configurable);
+    assertFalse(raw.enumerable);
+    assertEquals(Array.prototype, Object.getPrototypeOf(cs.raw));
+    assertTrue(Array.isArray(cs.raw));
+    assertEquals(Array.prototype, Object.getPrototypeOf(cs));
+    assertTrue(Array.isArray(cs));
+
+    var cooked0 = Object.getOwnPropertyDescriptor(cs, "0");
+    assertFalse(cooked0.writable);
+    assertFalse(cooked0.configurable);
+    assertTrue(cooked0.enumerable);
+
+    var raw0 = Object.getOwnPropertyDescriptor(cs.raw, "0");
+    assertFalse(cooked0.writable);
+    assertFalse(cooked0.configurable);
+    assertTrue(cooked0.enumerable);
+
+    var length = Object.getOwnPropertyDescriptor(cs, "length");
+    assertFalse(length.writable);
+    assertFalse(length.configurable);
+    assertFalse(length.enumerable);
+
+    length = Object.getOwnPropertyDescriptor(cs.raw, "length");
+    assertFalse(length.writable);
+    assertFalse(length.configurable);
+    assertFalse(length.enumerable);
+  }
+  tag`${1}`;
+  assertEquals(1, calls);
+})();
+
+
+(function testUTF16ByteOrderMark() {
+  assertEquals("\uFEFFtest", `\uFEFFtest`);
+  assertEquals("\uFEFFtest", eval("`\uFEFFtest`"));
+})();
+
+
+(function testStringRawAsTagFn() {
+  assertEquals("\\u0065\\`\\r\\r\\n\\ntestcheck",
+               String.raw`\u0065\`\r\r\n\n${"test"}check`);
+  assertEquals("\\\n\\\n\\\n", eval("String.raw`\\\r\\\r\n\\\n`"));
+  assertEquals("", String.raw``);
+})();
+
+
+(function testCallSiteCaching() {
+  var callSites = [];
+  function tag(cs) { callSites.push(cs); }
+  var a = 1;
+  var b = 2;
+
+  tag`head${a}tail`;
+  tag`head${b}tail`;
+
+  assertEquals(2, callSites.length);
+  assertSame(callSites[0], callSites[1]);
+
+  eval("tag`head${a}tail`");
+  assertEquals(3, callSites.length);
+  assertSame(callSites[1], callSites[2]);
+
+  eval("tag`head${b}tail`");
+  assertEquals(4, callSites.length);
+  assertSame(callSites[2], callSites[3]);
+
+  (new Function("tag", "a", "b", "return tag`head${a}tail`;"))(tag, 1, 2);
+  assertEquals(5, callSites.length);
+  assertSame(callSites[3], callSites[4]);
+
+  (new Function("tag", "a", "b", "return tag`head${b}tail`;"))(tag, 1, 2);
+  assertEquals(6, callSites.length);
+  assertSame(callSites[4], callSites[5]);
+
+  callSites = [];
+
+  tag`foo${a}bar`;
+  tag`foo\${.}bar`;
+  assertEquals(2, callSites.length);
+  assertEquals(2, callSites[0].length);
+  assertEquals(1, callSites[1].length);
+
+  callSites = [];
+
+  eval("tag`\\\r\n\\\n\\\r`");
+  eval("tag`\\\r\n\\\n\\\r`");
+  assertEquals(2, callSites.length);
+  assertSame(callSites[0], callSites[1]);
+  assertEquals("", callSites[0][0]);
+  assertEquals("\\\n\\\n\\\n", callSites[0].raw[0]);
+
+  callSites = [];
+
+  tag`\uc548\ub155`;
+  tag`\uc548\ub155`;
+  assertEquals(2, callSites.length);
+  assertSame(callSites[0], callSites[1]);
+  assertEquals("안녕", callSites[0][0]);
+  assertEquals("\\uc548\\ub155", callSites[0].raw[0]);
+
+  callSites = [];
+
+  tag`\uc548\ub155`;
+  tag`안녕`;
+  assertEquals(2, callSites.length);
+  assertTrue(callSites[0] !== callSites[1]);
+  assertEquals("안녕", callSites[0][0]);
+  assertEquals("\\uc548\\ub155", callSites[0].raw[0]);
+  assertEquals("안녕", callSites[1][0]);
+  assertEquals("안녕", callSites[1].raw[0]);
+
+  // Extra-thorough UTF8 decoding test.
+  callSites = [];
+
+  tag`Iñtërnâtiônàlizætiøn\u2603\uD83D\uDCA9`;
+  tag`Iñtërnâtiônàlizætiøn☃💩`;
+
+  assertEquals(2, callSites.length);
+  assertTrue(callSites[0] !== callSites[1]);
+  assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[0][0]);
+  assertEquals(
+      "Iñtërnâtiônàlizætiøn\\u2603\\uD83D\\uDCA9", callSites[0].raw[0]);
+  assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[1][0]);
+  assertEquals("Iñtërnâtiônàlizætiøn☃💩", callSites[1].raw[0]);
+})();
+
+
+(function testExtendedArrayPrototype() {
+  Object.defineProperty(Array.prototype, 0, {
+    set: function() {
+      assertUnreachable();
+    }
+  });
+  function tag(){}
+  tag`a${1}b`;
+})();
+
+
+(function testRawLineNormalization() {
+  function raw0(callSiteObj) {
+    return callSiteObj.raw[0];
+  }
+  assertEquals(eval("raw0`\r`"), "\n");
+  assertEquals(eval("raw0`\r\n`"), "\n");
+  assertEquals(eval("raw0`\r\r\n`"), "\n\n");
+  assertEquals(eval("raw0`\r\n\r\n`"), "\n\n");
+  assertEquals(eval("raw0`\r\r\r\n`"), "\n\n\n");
+})();
+
+
+(function testHarmonyUnicode() {
+  function raw0(callSiteObj) {
+    return callSiteObj.raw[0];
+  }
+  assertEquals(raw0`a\u{62}c`, "a\\u{62}c");
+  assertEquals(raw0`a\u{000062}c`, "a\\u{000062}c");
+  assertEquals(raw0`a\u{0}c`, "a\\u{0}c");
+
+  assertEquals(`a\u{62}c`, "abc");
+  assertEquals(`a\u{000062}c`, "abc");
+})();
+
+
+(function testLiteralAfterRightBrace() {
+  // Regression test for https://code.google.com/p/v8/issues/detail?id=3734
+  function f() {}
+  `abc`;
+
+  function g() {}`def`;
+
+  {
+    // block
+  }
+  `ghi`;
+
+  {
+    // block
+  }`jkl`;
+})();
+
+
+(function testLegacyOctal() {
+  assertEquals('\u0000', `\0`);
+  assertEquals('\u0000a', `\0a`);
+  for (var i = 0; i < 8; i++) {
+    var code = "`\\0" + i + "`";
+    assertThrows(code, SyntaxError);
+    code = "(function(){})" + code;
+    assertThrows(code, SyntaxError);
+  }
+
+  assertEquals('\\0', String.raw`\0`);
+})();
+
+
+(function testSyntaxErrorsNonEscapeCharacter() {
+  assertThrows("`\\x`", SyntaxError);
+  assertThrows("`\\u`", SyntaxError);
+  for (var i = 1; i < 8; i++) {
+    var code = "`\\" + i + "`";
+    assertThrows(code, SyntaxError);
+    code = "(function(){})" + code;
+    assertThrows(code, SyntaxError);
+  }
+})();
+
+
+(function testValidNumericEscapes() {
+  assertEquals("8", `\8`);
+  assertEquals("9", `\9`);
+  assertEquals("\u00008", `\08`);
+  assertEquals("\u00009", `\09`);
+})();
diff --git a/test/mjsunit/harmony/typedarrays-foreach.js b/test/mjsunit/harmony/typedarrays-foreach.js
new file mode 100644
index 0000000..4bfa655
--- /dev/null
+++ b/test/mjsunit/harmony/typedarrays-foreach.js
@@ -0,0 +1,140 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-arrays --allow-natives-syntax
+
+var typedArrayConstructors = [
+  Uint8Array,
+  Int8Array,
+  Uint16Array,
+  Int16Array,
+  Uint32Array,
+  Int32Array,
+  Uint8ClampedArray,
+  Float32Array,
+  Float64Array];
+
+function CheckTypedArrayIsNeutered(array) {
+  assertEquals(0, array.byteLength);
+  assertEquals(0, array.byteOffset);
+  assertEquals(0, array.length);
+}
+
+function TestTypedArrayForEach(constructor) {
+  assertEquals(1, constructor.prototype.forEach.length);
+
+  var a = new constructor(2);
+  a[0] = 0;
+  a[1] = 1;
+
+  var count = 0;
+  a.forEach(function (n) { count++; });
+  assertEquals(2, count);
+
+  // Use specified object as this object when calling the function.
+  var o = { value: 42 };
+  var result = [];
+  a.forEach(function (n, index, array) { result.push(this.value); }, o);
+  assertArrayEquals([42, 42], result);
+
+  // Modify the original array.
+  count = 0;
+  a.forEach(function (n, index, array) { array[index] = n + 1; count++ });
+  assertEquals(2, count);
+  assertArrayEquals([1, 2], a);
+
+  // Check that values passed as second argument are wrapped into
+  // objects when calling into sloppy mode functions.
+  function CheckWrapping(value, wrapper) {
+    var wrappedValue = new wrapper(value);
+
+    a.forEach(function () {
+      assertEquals("object", typeof this);
+      assertEquals(wrappedValue, this);
+    }, value);
+
+    a.forEach(function () {
+      "use strict";
+      assertEquals(typeof value, typeof this);
+      assertEquals(value, this);
+    }, value);
+  }
+  CheckWrapping(true, Boolean);
+  CheckWrapping(false, Boolean);
+  CheckWrapping("xxx", String);
+  CheckWrapping(42, Number);
+  CheckWrapping(3.14, Number);
+  CheckWrapping({}, Object);
+
+  // Throw before completing iteration, only the first element
+  // should be modified when thorwing mid-way.
+  count = 0;
+  a[0] = 42;
+  a[1] = 42;
+  try {
+    a.forEach(function (n, index, array) {
+      if (count > 0) throw "meh";
+      array[index] = n + 1;
+      count++;
+    });
+  } catch (e) {
+  }
+  assertEquals(1, count);
+  assertEquals(43, a[0]);
+  assertEquals(42, a[1]);
+
+  // Neutering the buffer backing the typed array mid-way should
+  // still make .forEach() finish, and the array should keep being
+  // empty after neutering it.
+  count = 0;
+  a.forEach(function (n, index, array) {
+    if (count > 0) %ArrayBufferNeuter(array.buffer);
+    array[index] = n + 1;
+    count++;
+  });
+  assertEquals(2, count);
+  CheckTypedArrayIsNeutered(a);
+  assertEquals(undefined, a[0]);
+
+  // The method must work for typed arrays created from ArrayBuffer.
+  // The length of the ArrayBuffer is chosen so it is a multiple of
+  // all lengths of the typed array items.
+  a = new constructor(new ArrayBuffer(64));
+  count = 0;
+  a.forEach(function (n) { count++ });
+  assertEquals(a.length, count);
+
+  // Externalizing the array mid-way accessing the .buffer property
+  // should work.
+  a = new constructor(2);
+  count = 0;
+  var buffer = undefined;
+  a.forEach(function (n, index, array) {
+    if (count++ > 0)
+      buffer = array.buffer;
+  });
+  assertEquals(2, count);
+  assertTrue(!!buffer);
+  assertEquals("ArrayBuffer", %_ClassOf(buffer));
+  assertSame(buffer, a.buffer);
+
+  // The %TypedArray%.forEach() method should not work when
+  // transplanted to objects that are not typed arrays.
+  assertThrows(function () { constructor.prototype.forEach.call([1, 2, 3], function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.forEach.call("abc", function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.forEach.call({}, function (x) {}) }, TypeError);
+  assertThrows(function () { constructor.prototype.forEach.call(0, function (x) {}) }, TypeError);
+
+  // Method must be useable on instances of other typed arrays.
+  for (var i = 0; i < typedArrayConstructors.length; i++) {
+    count = 0;
+    a = new typedArrayConstructors[i](4);
+    constructor.prototype.forEach.call(a, function (x) { count++ });
+    assertEquals(a.length, count);
+  }
+}
+
+for (i = 0; i < typedArrayConstructors.length; i++) {
+  TestTypedArrayForEach(typedArrayConstructors[i]);
+}
diff --git a/test/mjsunit/harmony/typedarrays-of.js b/test/mjsunit/harmony/typedarrays-of.js
new file mode 100644
index 0000000..9df1d30
--- /dev/null
+++ b/test/mjsunit/harmony/typedarrays-of.js
@@ -0,0 +1,135 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Based on Mozilla Array.of() tests at http://dxr.mozilla.org/mozilla-central/source/js/src/jit-test/tests/collections
+
+// Flags: --harmony-arrays
+
+var typedArrayConstructors = [
+  Uint8Array,
+  Int8Array,
+  Uint16Array,
+  Int16Array,
+  Uint32Array,
+  Int32Array,
+  Uint8ClampedArray,
+  Float32Array,
+  Float64Array];
+
+
+function TestTypedArrayOf(constructor) {
+  // %TypedArray%.of basics.
+  var a = constructor.of();
+  assertEquals(0, a.length);
+  assertEquals(constructor.prototype, Object.getPrototypeOf(a));
+  assertEquals(false, Array.isArray(a));
+
+  // Items are coerced to numerical values.
+  a = constructor.of(undefined, null, [], true, false, 3.14);
+
+  // For typed arrays of floating point values, values are not rounded.
+  if (constructor === Float32Array || constructor === Float64Array) {
+    assertEquals(NaN, a[0]);
+    assertEquals(0, a[1]);
+    assertEquals(0, a[2]);
+    assertEquals(1, a[3]);
+    assertEquals(0, a[4]);
+    assertEquals(true, Math.abs(a[5] - 3.14) < 1e-6);
+  } else {
+    assertEquals(0, a[0]);
+    assertEquals(0, a[1]);
+    assertEquals(0, a[2]);
+    assertEquals(1, a[3]);
+    assertEquals(0, a[4]);
+    assertEquals(3, a[5]);
+  }
+
+  var aux = [];
+  for (var i = 0; i < 100; i++)
+    aux[i] = i;
+
+  a = constructor.of.apply(constructor, aux);
+  assertEquals(aux.length, a.length);
+  assertArrayEquals(aux, a);
+
+  // %TypedArray%.of can be transplanted to other constructors.
+  var hits = 0;
+  function Bag(length) {
+    assertEquals(arguments.length, 1);
+    assertEquals(length, 2);
+    this.length = length;
+    hits++;
+  }
+  Bag.of = constructor.of;
+
+  hits = 0;
+  a = Bag.of("zero", "one");
+  assertEquals(1, hits);
+  assertEquals(2, a.length);
+  assertArrayEquals(["zero", "one"], a);
+  assertEquals(Bag.prototype, a.__proto__);
+
+  hits = 0;
+  actual = constructor.of.call(Bag, "zero", "one");
+  assertEquals(1, hits);
+  assertEquals(2, a.length);
+  assertArrayEquals(["zero", "one"], a);
+  assertEquals(Bag.prototype, a.__proto__);
+
+  // %TypedArray%.of does not trigger prototype setters.
+  // (It defines elements rather than assigning to them.)
+  var status = "pass";
+  Object.defineProperty(constructor.prototype, "0", {
+    set: function(v) { status = "fail"; }
+  });
+  assertEquals(1, constructor.of(1)[0], 1);
+  assertEquals("pass", status);
+
+  // Note that %TypedArray%.of does not trigger "length" setter itself, as
+  // it relies on the constructor to set "length" to the value passed to it.
+  // If the constructor does not assign "length", the setter should not be
+  // invoked.
+
+  // Setter on the newly created object.
+  function Pack() {
+    Object.defineProperty(this, "length", {
+      set: function (v) { status = "fail"; }
+    });
+  }
+  Pack.of = constructor.of;
+  var pack = Pack.of("wolves", "cards", "cigarettes", "lies");
+  assertEquals("pass", status);
+
+  // when the setter is on the new object's prototype
+  function Bevy() {}
+  Object.defineProperty(Bevy.prototype, "length", {
+    set: function (v) { status = "fail"; }
+  });
+  Bevy.of = constructor.of;
+  var bevy = Bevy.of("quail");
+  assertEquals("pass", status);
+
+  // Check superficial features of %TypedArray%.of.
+  var desc = Object.getOwnPropertyDescriptor(constructor, "of");
+
+  assertEquals(desc.configurable, false);
+  assertEquals(desc.enumerable, false);
+  assertEquals(desc.writable, false);
+  assertEquals(constructor.of.length, 0);
+
+  // %TypedArray%.of is not a constructor.
+  assertThrows(function() { new constructor.of(); }, TypeError);
+
+  // For receivers which are not constructors %TypedArray%.of does not
+  // allocate a typed array using a default constructor, but throws an
+  // exception. Note that this is different from Array.of, which uses
+  // Array as default constructor.
+  for (var x of [undefined, null, false, true, "cow", 42, 3.14]) {
+    assertThrows(function () { constructor.of.call(x); }, TypeError);
+  }
+}
+
+for (var constructor of typedArrayConstructors) {
+  TestTypedArrayOf(constructor);
+}
diff --git a/test/mjsunit/harmony/typedarrays.js b/test/mjsunit/harmony/typedarrays.js
index f26b0be..a4d6e79 100644
--- a/test/mjsunit/harmony/typedarrays.js
+++ b/test/mjsunit/harmony/typedarrays.js
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --harmony-tostring
+
 // ArrayBuffer
 
 function TestByteLength(param, expectedByteLength) {
@@ -52,6 +54,8 @@
 
   var ab = new ArrayBuffer();
   assertSame(0, ab.byteLength);
+  assertEquals("[object ArrayBuffer]",
+      Object.prototype.toString.call(ab));
 }
 
 TestArrayBufferCreation();
@@ -123,6 +127,9 @@
   var ab = new ArrayBuffer(256*elementSize);
 
   var a0 = new constr(30);
+  assertEquals("[object " + constr.name + "]",
+      Object.prototype.toString.call(a0));
+
   assertTrue(ArrayBuffer.isView(a0));
   assertSame(elementSize, a0.BYTES_PER_ELEMENT);
   assertSame(30, a0.length);
@@ -258,6 +265,17 @@
   assertSame(0, aNoParam.length);
   assertSame(0, aNoParam.byteLength);
   assertSame(0, aNoParam.byteOffset);
+
+  var a = new constr(ab, 64*elementSize, 128);
+  assertEquals("[object " + constr.name + "]",
+      Object.prototype.toString.call(a));
+  var desc = Object.getOwnPropertyDescriptor(
+      constr.prototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.enumerable);
+  assertFalse(!!desc.writable);
+  assertFalse(!!desc.set);
+  assertEquals("function", typeof desc.get);
 }
 
 TestTypedArray(Uint8Array, 1, 0xFF);
@@ -361,14 +379,18 @@
   Float64Array];
 
 function TestPropertyTypeChecks(constructor) {
-  var a = new constructor();
   function CheckProperty(name) {
     var d = Object.getOwnPropertyDescriptor(constructor.prototype, name);
-    var o = {}
+    var o = {};
     assertThrows(function() {d.get.call(o);}, TypeError);
-    d.get.call(a); // shouldn't throw
-    for (var i = 0 ; i < typedArrayConstructors.length; i++) {
-      d.get.call(new typedArrayConstructors[i](10));
+    for (var i = 0; i < typedArrayConstructors.length; i++) {
+      var ctor = typedArrayConstructors[i];
+      var a = new ctor(10);
+      if (ctor === constructor) {
+        d.get.call(a); // shouldn't throw
+      } else {
+        assertThrows(function() {d.get.call(a);}, TypeError);
+      }
     }
   }
 
@@ -378,7 +400,7 @@
   CheckProperty("length");
 }
 
-for(i = 0; i < typedArrayConstructors.lenght; i++) {
+for(i = 0; i < typedArrayConstructors.length; i++) {
   TestPropertyTypeChecks(typedArrayConstructors[i]);
 }
 
@@ -477,6 +499,103 @@
 
 TestTypedArraySet();
 
+function TestTypedArraysWithIllegalIndices() {
+  var a = new Int32Array(100);
+
+  a[-10] = 10;
+  assertEquals(undefined, a[-10]);
+  a["-10"] = 10;
+  assertEquals(undefined, a["-10"]);
+
+  var s = "    -10";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+  var s1 = "    -10   ";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+
+  a["-1e2"] = 10;
+  assertEquals(10, a["-1e2"]);
+  assertEquals(undefined, a[-1e2]);
+
+  a["-0"] = 256;
+  var s2 = "     -0";
+  a[s2] = 255;
+  assertEquals(undefined, a["-0"]);
+  assertEquals(255, a[s2]);
+  assertEquals(0, a[-0]);
+
+  /* Chromium bug: 424619
+   * a[-Infinity] = 50;
+   * assertEquals(undefined, a[-Infinity]);
+   */
+  a[1.5] = 10;
+  assertEquals(undefined, a[1.5]);
+  var nan = Math.sqrt(-1);
+  a[nan] = 5;
+  assertEquals(5, a[nan]);
+
+  var x = 0;
+  var y = -0;
+  assertEquals(Infinity, 1/x);
+  assertEquals(-Infinity, 1/y);
+  a[x] = 5;
+  a[y] = 27;
+  assertEquals(27, a[x]);
+  assertEquals(27, a[y]);
+}
+
+TestTypedArraysWithIllegalIndices();
+
+function TestTypedArraysWithIllegalIndicesStrict() {
+  'use strict';
+  var a = new Int32Array(100);
+
+  a[-10] = 10;
+  assertEquals(undefined, a[-10]);
+  a["-10"] = 10;
+  assertEquals(undefined, a["-10"]);
+
+  var s = "    -10";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+  var s1 = "    -10   ";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+
+  a["-1e2"] = 10;
+  assertEquals(10, a["-1e2"]);
+  assertEquals(undefined, a[-1e2]);
+
+  a["-0"] = 256;
+  var s2 = "     -0";
+  a[s2] = 255;
+  assertEquals(undefined, a["-0"]);
+  assertEquals(255, a[s2]);
+  assertEquals(0, a[-0]);
+
+  /* Chromium bug: 424619
+   * a[-Infinity] = 50;
+   * assertEquals(undefined, a[-Infinity]);
+   */
+  a[1.5] = 10;
+  assertEquals(undefined, a[1.5]);
+  var nan = Math.sqrt(-1);
+  a[nan] = 5;
+  assertEquals(5, a[nan]);
+
+  var x = 0;
+  var y = -0;
+  assertEquals(Infinity, 1/x);
+  assertEquals(-Infinity, 1/y);
+  a[x] = 5;
+  a[y] = 27;
+  assertEquals(27, a[x]);
+  assertEquals(27, a[y]);
+}
+
+TestTypedArraysWithIllegalIndicesStrict();
+
 // DataView
 function TestDataViewConstructor() {
   var ab = new ArrayBuffer(256);
@@ -546,6 +665,19 @@
 
 TestDataViewPropertyTypeChecks();
 
+
+function TestDataViewToStringTag() {
+  var a = new DataView(new ArrayBuffer(10));
+  assertEquals("[object DataView]", Object.prototype.toString.call(a));
+  var desc = Object.getOwnPropertyDescriptor(
+      DataView.prototype, Symbol.toStringTag);
+  assertTrue(desc.configurable);
+  assertFalse(desc.enumerable);
+  assertFalse(desc.writable);
+  assertEquals("DataView", desc.value);
+}
+
+
 // General tests for properties
 
 // Test property attribute [[Enumerable]]
@@ -561,7 +693,7 @@
     assertArrayEquals([], props(obj));
 }
 TestEnumerable(ArrayBuffer, new ArrayBuffer());
-for(i = 0; i < typedArrayConstructors.lenght; i++) {
+for(i = 0; i < typedArrayConstructors.length; i++) {
   TestEnumerable(typedArrayConstructors[i]);
 }
 TestEnumerable(DataView, new DataView(new ArrayBuffer()));
@@ -573,13 +705,13 @@
     assertEquals(value, map[property]);
   }
   for (var i = 0; i < 20; i++) {
-    TestProperty(m, i, 'val' + i);
+    TestProperty(m, 'key' + i, 'val' + i);
     TestProperty(m, 'foo' + i, 'bar' + i);
   }
 }
 TestArbitrary(new ArrayBuffer(256));
-for(i = 0; i < typedArrayConstructors.lenght; i++) {
-  TestArbitary(new typedArrayConstructors[i](10));
+for(i = 0; i < typedArrayConstructors.length; i++) {
+  TestArbitrary(new typedArrayConstructors[i](10));
 }
 TestArbitrary(new DataView(new ArrayBuffer(256)));
 
diff --git a/test/mjsunit/harmony/unicode-escapes.js b/test/mjsunit/harmony/unicode-escapes.js
new file mode 100644
index 0000000..b39ee1a
--- /dev/null
+++ b/test/mjsunit/harmony/unicode-escapes.js
@@ -0,0 +1,46 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ES6 extends the \uxxxx escape and also allows \u{xxxxx}.
+
+// Flags: --harmony-unicode
+
+// Unicode escapes in variable names.
+
+(function TestVariableNames1() {
+  var foobar = 1;
+  assertEquals(foob\u0061r, 1);
+  assertEquals(foob\u{0061}r, 1);
+  assertEquals(foob\u{61}r, 1);
+  assertEquals(foob\u{0000000061}r, 1);
+})();
+
+(function TestVariableNames2() {
+  var foobar = 1;
+  assertEquals(\u0066oobar, 1);
+  assertEquals(\u{0066}oobar, 1);
+  assertEquals(\u{66}oobar, 1);
+  assertEquals(\u{0000000066}oobar, 1);
+})();
+
+// Unicode escapes in strings.
+
+(function TestStrings() {
+  var s1 = "foob\u0061r";
+  assertEquals(s1, "foobar");
+  var s2 = "foob\u{0061}r";
+  assertEquals(s2, "foobar");
+  var s3 = "foob\u{61}r";
+  assertEquals(s3, "foobar");
+  var s4 = "foob\u{0000000061}r";
+  assertEquals(s4, "foobar");
+})();
+
+
+(function TestSurrogates() {
+  // U+10E6D corresponds to the surrogate pair [U+D803, U+DE6D].
+  var s1 = "foo\u{10e6d}";
+  var s2 = "foo\u{d803}\u{de6d}";
+  assertEquals(s1, s2);
+})();
diff --git a/test/mjsunit/harmony/numeric-literals-off.js b/test/mjsunit/keyed-load-with-string-key.js
similarity index 77%
copy from test/mjsunit/harmony/numeric-literals-off.js
copy to test/mjsunit/keyed-load-with-string-key.js
index 37204ed..4388946 100644
--- a/test/mjsunit/harmony/numeric-literals-off.js
+++ b/test/mjsunit/keyed-load-with-string-key.js
@@ -1,4 +1,4 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright 2014 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -25,17 +25,22 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// This is to ensure that we do not support 0b and 0o in Number when
-// the --harmony-numeric-literals flag is not set.
+// Flags: --allow-natives-syntax
 
 
-function TestOctalLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0o0'));
+var o = {
+  "foo": "bar",
 }
-TestOctalLiteralUsingNumberFunction();
 
-
-function TestBinaryLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0b0'));
+function get(obj, key) {
+  return obj[key];
 }
-TestBinaryLiteralUsingNumberFunction();
+
+get(o, "foo");
+get(o, "foo");
+get(o, "foo");
+
+%OptimizeFunctionOnNextCall(get);
+get(o, "foo");
+
+assertOptimized(get);
diff --git a/test/mjsunit/mirror-object.js b/test/mjsunit/mirror-object.js
index 7020338..91d0f82 100644
--- a/test/mjsunit/mirror-object.js
+++ b/test/mjsunit/mirror-object.js
@@ -125,12 +125,7 @@
         // Check that serialized name is correct.
         assertEquals(properties[i].name(), fromJSON.properties[i].name, 'Unexpected serialized name');
 
-        // If property type is normal property type is not serialized.
-        if (properties[i].propertyType() != debug.PropertyType.Normal) {
-          assertEquals(properties[i].propertyType(), fromJSON.properties[i].propertyType, 'Unexpected serialized property type');
-        } else {
-          assertTrue(typeof(fromJSON.properties[i].propertyType) === 'undefined', 'Unexpected serialized property type');
-        }
+        assertEquals(properties[i].propertyType(), fromJSON.properties[i].propertyType, 'Unexpected serialized property type');
 
         // If there are no attributes attributes are not serialized.
         if (properties[i].attributes() != debug.PropertyAttribute.None) {
diff --git a/test/mjsunit/mjsunit.js b/test/mjsunit/mjsunit.js
index 0430279..b360425 100644
--- a/test/mjsunit/mjsunit.js
+++ b/test/mjsunit/mjsunit.js
@@ -231,16 +231,7 @@
     return deepObjectEquals(a, b);
   }
 
-  function checkArity(args, arity, name) {
-    if (args.length < arity) {
-      fail(PrettyPrint(arity), args.length,
-           name + " requires " + arity + " or more arguments");
-    }
-  }
-
   assertSame = function assertSame(expected, found, name_opt) {
-    checkArity(arguments, 2, "assertSame");
-
     // TODO(mstarzinger): We should think about using Harmony's egal operator
     // or the function equivalent Object.is() here.
     if (found === expected) {
@@ -253,8 +244,6 @@
 
 
   assertEquals = function assertEquals(expected, found, name_opt) {
-    checkArity(arguments, 2, "assertEquals");
-
     if (!deepEquals(found, expected)) {
       fail(PrettyPrint(expected), found, name_opt);
     }
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index bba86bd..26ec10b 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -51,9 +51,8 @@
   # Issue 3389: deopt_every_n_garbage_collections is unsafe
   'regress/regress-2653': [SKIP],
 
-  # This test relies on --noopt-safe-uint32-operations, which is broken. See
-  # issue 3487 for details.
-  'compiler/shift-shr': [SKIP],
+  # Issue 3784: setters-on-elements is flaky
+  'setters-on-elements': [PASS, FAIL],
 
   ##############################################################################
   # TurboFan compiler failures.
@@ -63,16 +62,10 @@
   # from the deoptimizer to do that.
   'arguments-indirect': [PASS, NO_VARIANTS],
 
-  # TODO(rossberg): Typer doesn't like contexts very much.
-  'harmony/block-conflicts': [PASS, NO_VARIANTS],
-  'harmony/block-for': [PASS, NO_VARIANTS],
-  'harmony/block-leave': [PASS, NO_VARIANTS],
-  'harmony/block-let-crankshaft': [PASS, NO_VARIANTS],
-  'harmony/empty-for': [PASS, NO_VARIANTS],
-
-  # Some tests are over-restrictive about object layout.
+  # TODO(verwaest): Some tests are over-restrictive about object layout.
   'array-constructor-feedback': [PASS, NO_VARIANTS],
   'array-feedback': [PASS, NO_VARIANTS],
+  'compare-known-objects-slow': [PASS, NO_VARIANTS],
   'elements-kind': [PASS, NO_VARIANTS],
 
   # Some tests are just too slow to run for now.
@@ -84,6 +77,10 @@
   'compiler/osr-assert': [PASS, NO_VARIANTS],
   'regress/regress-2185-2': [PASS, NO_VARIANTS],
 
+  # Issue 3660: Replacing activated TurboFan frames by unoptimized code does
+  # not work, but we expect it to not crash.
+  'debug-step-turbofan': [PASS, FAIL],
+
   # Support for %GetFrameDetails is missing and requires checkpoints.
   'debug-evaluate-bool-constructor': [PASS, NO_VARIANTS],
   'debug-evaluate-const': [PASS, NO_VARIANTS],
@@ -123,6 +120,9 @@
   'regress/regress-crbug-259300': [PASS, NO_VARIANTS],
   'regress/regress-frame-details-null-receiver': [PASS, NO_VARIANTS],
 
+  # TODO(arv): TurboFan does not yet add [[HomeObject]] as needed.
+  'harmony/object-literals-super': [PASS, NO_VARIANTS],
+
   ##############################################################################
   # Too slow in debug mode with --stress-opt mode.
   'compiler/regress-stacktrace-methods': [PASS, ['mode == debug', SKIP]],
@@ -177,7 +177,7 @@
   ##############################################################################
   # Tests verifying CHECK and ASSERT.
   'verify-check-false': [FAIL, NO_VARIANTS],
-  'verify-assert-false': [NO_VARIANTS, ['mode == release', PASS], ['mode == debug', FAIL]],
+  'verify-assert-false': [NO_VARIANTS, ['mode == release and dcheck_always_on == False', PASS], ['mode == debug or dcheck_always_on == True', FAIL]],
 
   ##############################################################################
   # Tests with different versions for release and debug.
@@ -195,8 +195,13 @@
 
   # Skip endain dependent test for mips due to different typed views of the same
   # array buffer.
-  'nans': [PASS, ['arch == mips', SKIP]],
+  'nans': [PASS, ],
 
+  # This test variant makes only sense on arm.
+  'math-floor-of-div-nosudiv': [PASS, SLOW, ['arch not in [arm, arm64, android_arm, android_arm64]', SKIP]],
+
+  # Too slow for slow variants.
+  'asm/embenchen/*': [PASS, SLOW, FAST_VARIANTS],
 }],  # ALWAYS
 
 ##############################################################################
@@ -211,10 +216,12 @@
   'elements-kind': [SKIP],
   'elements-transition-hoisting': [SKIP],
   'fast-prototype': [SKIP],
+  'field-type-tracking': [SKIP],
   'getters-on-elements': [SKIP],
   'harmony/block-let-crankshaft': [SKIP],
   'opt-elements-kind': [SKIP],
   'osr-elements-kind': [SKIP],
+  'regress/regress-crbug-137689': [SKIP],
   'regress/regress-165637': [SKIP],
   'regress/regress-2249': [SKIP],
   # Tests taking too long
@@ -233,6 +240,20 @@
   # TODO(mstarzinger): Takes too long with TF.
   'array-sort': [PASS, NO_VARIANTS],
   'regress/regress-91008': [PASS, NO_VARIANTS],
+  'regress/regress-417709a': [PASS, ['arch == arm64', NO_VARIANTS]],
+  'regress/regress-transcendental': [PASS, ['arch == arm64', NO_VARIANTS]],
+  'compiler/osr-regress-max-locals': [PASS, NO_VARIANTS],
+  'math-floor-of-div': [PASS, NO_VARIANTS],
+  'unicodelctest': [PASS, NO_VARIANTS],
+  'unicodelctest-no-optimization': [PASS, NO_VARIANTS],
+
+  # Too slow for gc stress.
+  'asm/embenchen/box2d': [SKIP],
+
+  # Issue 3723.
+  'regress/regress-3717': [SKIP],
+  # Issue 3776.
+  'debug-stepframe': [SKIP],
 }],  # 'gc_stress == True'
 
 ##############################################################################
@@ -249,6 +270,8 @@
   # Pass but take too long to run. Skip.
   # Some similar tests (with fewer iterations) may be included in arm64-js
   # tests.
+  'asm/embenchen/box2d': [SKIP],
+  'asm/embenchen/lua_binarytrees': [SKIP],
   'big-object-literal': [SKIP],
   'compiler/regress-arguments': [SKIP],
   'compiler/regress-gvn': [SKIP],
@@ -313,11 +336,16 @@
 ['arch == arm64 and mode == debug and simulator_run == True', {
 
   # Pass but take too long with the simulator in debug mode.
+  'array-iterate-backwards': [PASS, TIMEOUT],
   'array-sort': [PASS, TIMEOUT],
   'packed-elements': [SKIP],
   'regexp-global': [SKIP],
   'compiler/alloc-numbers': [SKIP],
   'harmony/symbols': [SKIP],
+  'math-floor-of-div': [PASS, TIMEOUT],
+  'math-floor-of-div-nosudiv': [PASS, TIMEOUT],
+  'unicodelctest': [PASS, TIMEOUT],
+  'unicodelctest-no-optimization': [PASS, TIMEOUT],
   # Issue 3219:
   'getters-on-elements': [PASS, ['gc_stress == True', FAIL]],
 }],  # 'arch == arm64 and mode == debug and simulator_run == True'
@@ -414,6 +442,15 @@
 }],  # 'arch == mipsel or arch == mips'
 
 ##############################################################################
+['arch == mips', {
+  # Flaky with TF.
+  'mirror-script': [PASS, NO_VARIANTS],
+
+  # Emscripten requires little-endian, skip all tests on MIPS EB.
+  'asm/embenchen/*': [SKIP],
+}],  # 'arch == mips'
+
+##############################################################################
 ['arch == mips64el', {
 
   # Slow tests which times out in debug mode.
@@ -472,6 +509,10 @@
 ['system == windows', {
   # TODO(mstarzinger): Too slow with turbo fan.
   'big-object-literal': [PASS, ['mode == debug', SKIP]],
+  'math-floor-of-div': [PASS, ['mode == debug', SKIP]],
+  'math-floor-of-div-nosudiv': [PASS, ['mode == debug', SKIP]],
+  'osr-regress-max-locals': [PASS, ['mode == debug', SKIP]],
+  'unicodelctest': [PASS, ['mode == debug', SKIP]],
 
   # BUG(v8:3435)
   'debug-script-breakpoints': [PASS, FAIL],
diff --git a/test/mjsunit/mod-range.js b/test/mjsunit/mod-range.js
new file mode 100644
index 0000000..0cded89
--- /dev/null
+++ b/test/mjsunit/mod-range.js
@@ -0,0 +1,79 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function g1(i) {
+  var x = i * 1;
+  return (x >>> 0) % 1000000000000;
+}
+
+function g2(i) {
+  var x = i * 1;
+  return ((x >>> 0) % 1000000000000) | 0;
+}
+
+function test1() {
+  assertEquals(2294967296, g1(-2000000000));
+  assertEquals(2294967295, g1(-2000000001));
+  assertEquals(2294967290, g1(-2000000006));
+
+  assertEquals(2147483651, g1(-2147483645));
+  assertEquals(2147483650, g1(-2147483646));
+  assertEquals(2147483649, g1(-2147483647));
+  assertEquals(2147483648, g1(-2147483648));
+  assertEquals(2147483647, g1(-2147483649));
+
+  assertEquals(3000000000, g1(3000000000));
+  assertEquals(3000000001, g1(3000000001));
+  assertEquals(3000000002, g1(3000000002));
+
+  assertEquals(4000000000, g1(4000000000));
+  assertEquals(4000400001, g1(4000400001));
+  assertEquals(4000400002, g1(4000400002));
+
+  assertEquals(3, g1(4294967299));
+  assertEquals(2, g1(4294967298));
+  assertEquals(1, g1(4294967297));
+  assertEquals(0, g1(4294967296));
+  assertEquals(4294967295, g1(4294967295));
+  assertEquals(4294967294, g1(4294967294));
+  assertEquals(4294967293, g1(4294967293));
+  assertEquals(4294967292, g1(4294967292));
+}
+
+%NeverOptimizeFunction(test1);
+test1();
+
+function test2() {
+  assertEquals(-2000000000, g2(-2000000000));
+  assertEquals(-2000000001, g2(-2000000001));
+  assertEquals(-2000000006, g2(-2000000006));
+
+  assertEquals(-2147483645, g2(-2147483645));
+  assertEquals(-2147483646, g2(-2147483646));
+  assertEquals(-2147483647, g2(-2147483647));
+  assertEquals(-2147483648, g2(-2147483648));
+  assertEquals(2147483647, g2(-2147483649));
+
+  assertEquals(-1294967296, g2(3000000000));
+  assertEquals(-1294967295, g2(3000000001));
+  assertEquals(-1294967294, g2(3000000002));
+
+  assertEquals(-294967296, g2(4000000000));
+  assertEquals(-294567295, g2(4000400001));
+  assertEquals(-294567294, g2(4000400002));
+
+  assertEquals(3, g2(4294967299));
+  assertEquals(2, g2(4294967298));
+  assertEquals(1, g2(4294967297));
+  assertEquals(0, g2(4294967296));
+  assertEquals(-1, g2(4294967295));
+  assertEquals(-2, g2(4294967294));
+  assertEquals(-3, g2(4294967293));
+  assertEquals(-4, g2(4294967292));
+}
+
+%NeverOptimizeFunction(test2);
+test2();
diff --git a/test/mjsunit/nans.js b/test/mjsunit/nans.js
index 987ad6e..5630e5b 100644
--- a/test/mjsunit/nans.js
+++ b/test/mjsunit/nans.js
@@ -27,6 +27,11 @@
 
 // Flags: --allow-natives-syntax
 
+// Helper to determine endian - returns true on little endian platforms
+function isLittleEndian() {
+  return ((new Uint32Array((new Uint8Array([4,3,2,1])).buffer))[0])
+           == 0x01020304;
+}
 
 // Test that both kinds of NaNs (signaling or quiet) do not signal
 
@@ -41,7 +46,11 @@
 function TestDoubleSignalingNan() {
   // NaN with signal bit set
   function f() {
-    var bytes = new Uint32Array([1, 0x7FF00000]);
+    if(isLittleEndian()) {
+      var bytes = new Uint32Array([1, 0x7FF00000]);
+    } else {
+      var bytes = new Uint32Array([0x7FF00000, 1]);
+    }
     var doubles = new Float64Array(bytes.buffer);
     assertTrue(isNaN(doubles[0]));
     assertTrue(isNaN(doubles[0]*2.0));
@@ -56,7 +65,11 @@
 function TestDoubleQuietNan() {
   // NaN with signal bit cleared
   function f() {
-    var bytes = new Uint32Array([0, 0x7FF80000]);
+    if(isLittleEndian()) {
+      var bytes = new Uint32Array([0, 0x7FF80000]);
+    } else {
+      var bytes = new Uint32Array([0x7FF80000, 0]);
+    }
     var doubles = new Float64Array(bytes.buffer);
     assertTrue(isNaN(doubles[0]));
     assertTrue(isNaN(doubles[0]*2.0));
diff --git a/test/mjsunit/object-freeze-global.js b/test/mjsunit/object-freeze-global.js
new file mode 100644
index 0000000..8ab5b85
--- /dev/null
+++ b/test/mjsunit/object-freeze-global.js
@@ -0,0 +1,6 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Object.freeze(this);
+assertTrue(Object.isFrozen(this));
diff --git a/test/mjsunit/object-freeze.js b/test/mjsunit/object-freeze.js
index 4144936..5d1f8b7 100644
--- a/test/mjsunit/object-freeze.js
+++ b/test/mjsunit/object-freeze.js
@@ -303,7 +303,7 @@
 
 // Also test a simpler case
 obj = {};
-Object.defineProperty(obj, 'accessor', {
+Object.defineProperty(obj, 'accessor2', {
   get: function() { return 42 },
   set: function() { accessorDidRun = true },
   configurable: true,
@@ -339,3 +339,12 @@
 assertEquals(1, obj[1]);
 Object.freeze(obj);
 assertThrows(function() { obj.unshift(); }, TypeError);
+
+// Sealing and then Freezing should do the right thing.
+var obj = { foo: 'bar', 0: 'element' };
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+Object.freeze(obj);
+assertTrue(Object.isSealed(obj));
+assertTrue(Object.isFrozen(obj));
diff --git a/test/mjsunit/object-get-own-property-names.js b/test/mjsunit/object-get-own-property-names.js
index 64607c6..aee6585 100644
--- a/test/mjsunit/object-get-own-property-names.js
+++ b/test/mjsunit/object-get-own-property-names.js
@@ -87,30 +87,20 @@
 assertSame(Array.prototype, propertyNames.__proto__);
 Array.prototype.concat = savedConcat;
 
-try {
-  Object.getOwnPropertyNames(4);
-  assertTrue(false);
-} catch (e) {
-  assertTrue(/on non-object/.test(e));
-}
-
-try {
-  Object.getOwnPropertyNames("foo");
-  assertTrue(false);
-} catch (e) {
-  assertTrue(/on non-object/.test(e));
-}
+assertEquals(Object.getOwnPropertyNames(4), []);
+assertEquals(Object.getOwnPropertyNames("foo"), ["0", "1", "2", "length"]);
+assertEquals(Object.getOwnPropertyNames(true), []);
 
 try {
   Object.getOwnPropertyNames(undefined);
   assertTrue(false);
 } catch (e) {
-  assertTrue(/on non-object/.test(e));
+  assertTrue(/Cannot convert undefined or null to object/.test(e));
 }
 
 try {
   Object.getOwnPropertyNames(null);
   assertTrue(false);
 } catch (e) {
-  assertTrue(/on non-object/.test(e));
+  assertTrue(/Cannot convert undefined or null to object/.test(e));
 }
diff --git a/test/mjsunit/object-is.js b/test/mjsunit/object-is.js
index b9fdc84..c57542f 100644
--- a/test/mjsunit/object-is.js
+++ b/test/mjsunit/object-is.js
@@ -32,8 +32,8 @@
   assertSame(expected, Object.is(x, y));
 }
 
-var test_set = [ {}, [], 1/0, -1/0, "s", 0, 0/-1, null, undefined ];
-print(test_set);
+var test_set = [ {}, [], Infinity, -Infinity, "s", "ã‚¢", 0, 0/-1, null,
+    undefined, true, false, Symbol("foo"), NaN ];
 for (var i = 0; i < test_set.length; i++) {
   for (var j = 0; j < test_set.length; j++) {
     if (i == j) {
diff --git a/test/mjsunit/object-prevent-extensions.js b/test/mjsunit/object-prevent-extensions.js
index 6b9184d..bde3161 100644
--- a/test/mjsunit/object-prevent-extensions.js
+++ b/test/mjsunit/object-prevent-extensions.js
@@ -27,6 +27,8 @@
 
 // Tests the Object.preventExtensions method - ES 15.2.3.10
 
+// Flags: --allow-natives-syntax
+
 
 var obj1 = {};
 // Extensible defaults to true.
@@ -126,3 +128,35 @@
 var n = o[0] = 100;
 assertEquals(undefined, o[0]);
 assertEquals(100, n);
+
+// Fast properties should remain fast
+obj = { x: 42, y: 'foo' };
+assertTrue(%HasFastProperties(obj));
+Object.preventExtensions(obj);
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isSealed(obj));
+assertTrue(%HasFastProperties(obj));
+
+// Non-extensible objects should share maps where possible
+obj = { prop1: 1, prop2: 2 };
+obj2 = { prop1: 3, prop2: 4 };
+assertTrue(%HaveSameMap(obj, obj2));
+Object.preventExtensions(obj);
+Object.preventExtensions(obj2);
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isExtensible(obj2));
+assertFalse(Object.isSealed(obj));
+assertFalse(Object.isSealed(obj2));
+assertTrue(%HaveSameMap(obj, obj2));
+
+// Non-extensible objects should share maps even when they have elements
+obj = { prop1: 1, prop2: 2, 75: 'foo' };
+obj2 = { prop1: 3, prop2: 4, 150: 'bar' };
+assertTrue(%HaveSameMap(obj, obj2));
+Object.preventExtensions(obj);
+Object.preventExtensions(obj2);
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isExtensible(obj2));
+assertFalse(Object.isSealed(obj));
+assertFalse(Object.isSealed(obj2));
+assertTrue(%HaveSameMap(obj, obj2));
diff --git a/test/mjsunit/object-seal-global.js b/test/mjsunit/object-seal-global.js
new file mode 100644
index 0000000..ec9f82e
--- /dev/null
+++ b/test/mjsunit/object-seal-global.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Object.seal(this);
+assertTrue(Object.isSealed(this));
+assertFalse(Object.isFrozen(this));
diff --git a/test/mjsunit/object-seal.js b/test/mjsunit/object-seal.js
index 3afddb9..3c46ab2 100644
--- a/test/mjsunit/object-seal.js
+++ b/test/mjsunit/object-seal.js
@@ -267,3 +267,132 @@
 assertDoesNotThrow(function() { obj.splice(1,2000,1,2); });
 assertThrows(function() { obj.splice(0,0,1); }, TypeError);
 assertThrows(function() { obj.splice(1,2000,1,2,3); }, TypeError);
+
+// Test that the enumerable attribute is unperturbed by sealing.
+obj = { x: 42, y: 'foo' };
+Object.defineProperty(obj, 'y', {enumerable: false});
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+desc = Object.getOwnPropertyDescriptor(obj, 'x');
+assertTrue(desc.enumerable);
+desc = Object.getOwnPropertyDescriptor(obj, 'y');
+assertFalse(desc.enumerable);
+
+// Fast properties should remain fast
+obj = { x: 42, y: 'foo' };
+assertTrue(%HasFastProperties(obj));
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+assertTrue(%HasFastProperties(obj));
+
+// Sealed objects should share maps where possible
+obj = { prop1: 1, prop2: 2 };
+obj2 = { prop1: 3, prop2: 4 };
+assertTrue(%HaveSameMap(obj, obj2));
+Object.seal(obj);
+Object.seal(obj2);
+assertTrue(Object.isSealed(obj));
+assertTrue(Object.isSealed(obj2));
+assertFalse(Object.isFrozen(obj));
+assertFalse(Object.isFrozen(obj2));
+assertTrue(%HaveSameMap(obj, obj2));
+
+// Sealed objects should share maps even when they have elements
+obj = { prop1: 1, prop2: 2, 75: 'foo' };
+obj2 = { prop1: 3, prop2: 4, 150: 'bar' };
+assertTrue(%HaveSameMap(obj, obj2));
+Object.seal(obj);
+Object.seal(obj2);
+assertTrue(Object.isSealed(obj));
+assertTrue(Object.isSealed(obj2));
+assertFalse(Object.isFrozen(obj));
+assertFalse(Object.isFrozen(obj));
+assertTrue(%HaveSameMap(obj, obj2));
+
+// Setting elements after sealing should not be allowed
+obj = { prop: 'thing' };
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+obj[0] = 'hello';
+assertFalse(obj.hasOwnProperty(0));
+
+// Sealing an object in dictionary mode should work
+// Also testing that getter/setter properties work after sealing
+obj = { };
+for (var i = 0; i < 100; ++i) {
+  obj['x' + i] = i;
+}
+var accessorDidRun = false;
+Object.defineProperty(obj, 'accessor', {
+  get: function() { return 42 },
+  set: function() { accessorDidRun = true },
+  configurable: true,
+  enumerable: true
+});
+
+assertFalse(%HasFastProperties(obj));
+Object.seal(obj);
+assertFalse(%HasFastProperties(obj));
+assertTrue(Object.isSealed(obj));
+assertFalse(Object.isFrozen(obj));
+assertFalse(Object.isExtensible(obj));
+for (var i = 0; i < 100; ++i) {
+  desc = Object.getOwnPropertyDescriptor(obj, 'x' + i);
+  assertFalse(desc.configurable);
+}
+assertEquals(42, obj.accessor);
+assertFalse(accessorDidRun);
+obj.accessor = 'ignored value';
+assertTrue(accessorDidRun);
+
+// Sealing arguments should work
+var func = function(arg) {
+  Object.seal(arguments);
+  assertTrue(Object.isSealed(arguments));
+};
+func('hello', 'world');
+func('goodbye', 'world');
+
+// Sealing sparse arrays
+var sparseArr = [0, 1];
+sparseArr[10000] = 10000;
+Object.seal(sparseArr);
+assertTrue(Object.isSealed(sparseArr));
+
+// Accessors on fast object should behavior properly after sealing
+obj = {};
+Object.defineProperty(obj, 'accessor', {
+  get: function() { return 42 },
+  set: function() { accessorDidRun = true },
+  configurable: true,
+  enumerable: true
+});
+assertTrue(%HasFastProperties(obj));
+Object.seal(obj);
+assertTrue(Object.isSealed(obj));
+assertTrue(%HasFastProperties(obj));
+assertEquals(42, obj.accessor);
+accessorDidRun = false;
+obj.accessor = 'ignored value';
+assertTrue(accessorDidRun);
+
+// Test for regression in mixed accessor/data property objects.
+// The strict function is one such object.
+assertTrue(Object.isSealed(Object.seal(function(){"use strict";})));
+
+// Also test a simpler case
+obj = {};
+Object.defineProperty(obj, 'accessor2', {
+  get: function() { return 42 },
+  set: function() { accessorDidRun = true },
+  configurable: true,
+  enumerable: true
+});
+obj.data = 'foo';
+assertTrue(%HasFastProperties(obj));
+Object.seal(obj);
+assertTrue(%HasFastProperties(obj));
+assertTrue(Object.isSealed(obj));
diff --git a/test/mjsunit/opt-elements-kind.js b/test/mjsunit/opt-elements-kind.js
index be7303b..5f4f437 100644
--- a/test/mjsunit/opt-elements-kind.js
+++ b/test/mjsunit/opt-elements-kind.js
@@ -142,10 +142,16 @@
   assertTrue(%HaveSameMap(smis, doubles));
 }
 
+function clear_ic_state() {
+  %ClearFunctionTypeFeedback(construct_smis);
+  %ClearFunctionTypeFeedback(construct_doubles);
+  %ClearFunctionTypeFeedback(convert_mixed);
+}
+
 test1();
-gc(); // clear IC state
+clear_ic_state();
 test1();
-gc(); // clear IC state
+clear_ic_state();
 %OptimizeFunctionOnNextCall(test1);
 test1();
-gc(); // clear IC state
+clear_ic_state();
diff --git a/test/mjsunit/parse-surrogates.js b/test/mjsunit/parse-surrogates.js
new file mode 100644
index 0000000..5ed9b52
--- /dev/null
+++ b/test/mjsunit/parse-surrogates.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test that the parser throws on unmatched surrogates.
+assertThrows("var \uD801\uABCD;", SyntaxError);
+assertThrows("'\\u000\uD801\uABCD'", SyntaxError);
diff --git a/test/mjsunit/polymorph-arrays.js b/test/mjsunit/polymorph-arrays.js
index 2bb0433..6a05c9f 100644
--- a/test/mjsunit/polymorph-arrays.js
+++ b/test/mjsunit/polymorph-arrays.js
@@ -36,7 +36,7 @@
   for (var i = 0; i < 10; ++i ){
     a[i] = i;
   }
-  a[5000000] = 256;
+  a[200000] = 256;
   return %NormalizeElements(a);
 }
 
@@ -115,7 +115,7 @@
     var sparse_object_array = new Object;
     var js_array = new Array(10);
     var sparse_js_array = [];
-    sparse_js_array.length = 5000001;
+    sparse_js_array.length = 200001;
 
     init_array(object_array);
     init_array(js_array);
@@ -134,7 +134,8 @@
   var sparse_object_array = new Object;
   var js_array = new Array(10);
   var sparse_js_array = %NormalizeElements([]);
-  sparse_js_array.length = 5000001;
+  sparse_js_array.length = 200001;
+  assertTrue(%HasDictionaryElements(sparse_js_array));
 
   init_array(object_array);
   init_array(js_array);
diff --git a/test/mjsunit/regress-ntl.js b/test/mjsunit/regress-ntl.js
new file mode 100644
index 0000000..993599e
--- /dev/null
+++ b/test/mjsunit/regress-ntl.js
@@ -0,0 +1,41 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function mod1() {
+  var v_1 = 1;
+  var v_2 = 1;
+  v_1++;
+  v_2 = {valueOf: function() { throw "gagh"; }};
+
+  function bug1() {
+    for (var i = 0; i < 1; v_2++) {
+      if (v_1 == 1) ;
+    }
+  }
+
+  return bug1;
+}
+
+var f = mod1();
+assertThrows(f);
+%OptimizeFunctionOnNextCall(f);
+assertThrows(f);
+
+
+var v_3 = 1;
+var v_4 = 1;
+v_3++;
+v_4 = {valueOf: function() { throw "gagh"; }};
+
+function bug2() {
+  for (var i = 0; i < 1; v_4++) {
+    if (v_3 == 1) ;
+  }
+}
+
+assertThrows(bug2);
+%OptimizeFunctionOnNextCall(bug2);
+assertThrows(bug2);
diff --git a/test/mjsunit/regress/regress-136048.js b/test/mjsunit/regress/regress-136048.js
index c9972e9..21ae622 100644
--- a/test/mjsunit/regress/regress-136048.js
+++ b/test/mjsunit/regress/regress-136048.js
@@ -26,9 +26,9 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 try {
-  /foo/\u0069
+  eval("/foo/\\u0069")
 } catch (e) {
   assertEquals(
-      "SyntaxError: Invalid flags supplied to RegExp constructor '\\u0069'",
+      "SyntaxError: Invalid regular expression flags",
       e.toString());
 }
diff --git a/test/mjsunit/regress/regress-1757.js b/test/mjsunit/regress/regress-1757.js
index 35e7355..a850f70 100644
--- a/test/mjsunit/regress/regress-1757.js
+++ b/test/mjsunit/regress/regress-1757.js
@@ -27,6 +27,7 @@
 
 // Flags: --string-slices --expose-externalize-string
 
-var a = "abcdefghijklmnopqrstuvqxy"+"z";
+var a = "internalized dummy";
+a = "abcdefghijklmnopqrstuvqxy"+"z";
 externalizeString(a, true);
 assertEquals('b', a.substring(1).charAt(0));
diff --git a/test/mjsunit/regress/regress-2506.js b/test/mjsunit/regress/regress-2506.js
new file mode 100644
index 0000000..0eb2770
--- /dev/null
+++ b/test/mjsunit/regress/regress-2506.js
@@ -0,0 +1,78 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-scoping
+
+'use strict';
+
+// Top-level code
+let s = 0;
+let f = [undefined, undefined, undefined]
+for (const x of [1,2,3]) {
+  s += x;
+  f[x-1] = function() { return x; }
+}
+assertEquals(6, s);
+assertEquals(1, f[0]());
+assertEquals(2, f[1]());
+assertEquals(3, f[2]());
+
+let x = 1;
+s = 0;
+for (const x of [x, x+1, x+2]) {
+  s += x;
+}
+assertEquals(6, s);
+
+s = 0;
+var q = 1;
+for (const q of [q, q+1, q+2]) {
+  s += q;
+}
+assertEquals(6, s);
+
+let z = 1;
+s = 0;
+for (const x = 1; z < 2; z++) {
+  s += x + z;
+}
+assertEquals(2, s);
+
+
+s = "";
+for (const x in [1,2,3]) {
+  s += x;
+}
+assertEquals("012", s);
+
+assertThrows("'use strict'; for (const x in [1,2,3]) { x++ }", TypeError);
+
+// Function scope
+(function() {
+  let s = 0;
+  for (const x of [1,2,3]) {
+    s += x;
+  }
+  assertEquals(6, s);
+
+  let x = 1;
+  s = 0;
+  for (const x of [x, x+1, x+2]) {
+    s += x;
+  }
+  assertEquals(6, s);
+
+  s = 0;
+  var q = 1;
+  for (const q of [q, q+1, q+2]) {
+    s += q;
+  }
+  assertEquals(6, s);
+
+  s = "";
+  for (const x in [1,2,3]) {
+    s += x;
+  }
+  assertEquals("012", s);
+}());
diff --git a/test/mjsunit/bugs/bug-2615.js b/test/mjsunit/regress/regress-2615.js
similarity index 78%
rename from test/mjsunit/bugs/bug-2615.js
rename to test/mjsunit/regress/regress-2615.js
index 51aeaf4..6b277e8 100644
--- a/test/mjsunit/bugs/bug-2615.js
+++ b/test/mjsunit/regress/regress-2615.js
@@ -25,20 +25,6 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-var a = [];
-a[0xfffffffe] = 10;
-assertThrows("a.unshift(1);", RangeError);
-assertEquals(0xffffffff, a.length);
-assertEquals(10, a[0xffffffff]);
-assertEquals(undefined, a[0xfffffffe]);
-
-a = [1,2,3];
-a[0xfffffffe] = 10;
-assertThrows("a.splice(1,1,7,7,7,7,7);", RangeError);
-assertEquals([1,7,7,7,7,7,3], a.slice(0, 7));
-assertEquals(0xffffffff, a.length);
-assertEquals(10, a[0xfffffffe + 5 - 1]);
-
 a = [1];
 Object.defineProperty(a, "1", {writable:false, configurable:false, value: 100});
 assertThrows("a.unshift(4);", TypeError);
@@ -77,7 +63,7 @@
 a = [0,1,2,3,4,5,6];
 Object.defineProperty(a, "3", {configurable:false, writable:false, value:3});
 assertThrows("a.splice(1,4);", TypeError);
-assertEquals([0,5,6,3,,,,,], a);
+assertEquals([0,5,6,3,,,,], a);
 desc = Object.getOwnPropertyDescriptor(a, "3");
 assertEquals(false, desc.configurable);
 assertEquals(false, desc.writable);
@@ -85,7 +71,7 @@
 a = [0,1,2,3,4,5,6];
 Object.defineProperty(a, "5", {configurable:false, value:5});
 assertThrows("a.splice(1,4);", TypeError);
-assertEquals([0,5,6,3,4,5,,,], a);
+assertEquals([0,5,6,3,4,5,,], a);
 desc = Object.getOwnPropertyDescriptor(a, "5");
 assertEquals(false, desc.configurable);
 
@@ -108,19 +94,3 @@
 assertEquals([1,2,3], a);
 desc = Object.getOwnPropertyDescriptor(a, "2");
 assertEquals(false, desc.configurable);
-
-a = [1,2,,,5];
-Object.defineProperty(a, "4", {writable:true, configurable:false, value:5});
-assertThrows("a.sort();", TypeError);
-assertEquals([1,2,5,,5], a);
-desc = Object.getOwnPropertyDescriptor(a, "2");
-assertEquals(true, desc.configurable);
-desc = Object.getOwnPropertyDescriptor(a, "4");
-assertEquals(false, desc.configurable);
-
-a = [1,2,3,,5,6];
-Object.defineProperty(a, "4", {value:5, writable:false});
-assertThrows("a.sort();", TypeError);
-assertEquals([1,2,3,5,5,6], a);
-desc = Object.getOwnPropertyDescriptor(a, "4");
-assertEquals(false, desc.writable);
diff --git a/test/mjsunit/regress/regress-3229.js b/test/mjsunit/regress/regress-3229.js
new file mode 100644
index 0000000..1a0ed64
--- /dev/null
+++ b/test/mjsunit/regress/regress-3229.js
@@ -0,0 +1,26 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Escape '/'.
+function testEscapes(expected, regexp) {
+  assertEquals(expected, regexp.source);
+  assertEquals("/" + expected + "/", regexp.toString());
+}
+
+testEscapes("\\/", /\//);
+testEscapes("\\/\\/", /\/\//);
+testEscapes("\\/", new RegExp("/"));
+testEscapes("\\/", new RegExp("\\/"));
+testEscapes("\\\\/", new RegExp("\\\\/"));
+testEscapes("\\/\\/", new RegExp("\\/\\/"));
+testEscapes("\\/\\/\\/\\/", new RegExp("////"));
+testEscapes("\\/\\/\\/\\/", new RegExp("\\//\\//"));
+testEscapes("(?:)", new RegExp(""));
+testEscapes("(?:)", RegExp.prototype);
+
+// Read-only property.
+var r = /\/\//;
+testEscapes("\\/\\/", r);
+r.source = "garbage";
+testEscapes("\\/\\/", r);
diff --git a/test/mjsunit/harmony/numeric-literals-off.js b/test/mjsunit/regress/regress-3483.js
similarity index 77%
copy from test/mjsunit/harmony/numeric-literals-off.js
copy to test/mjsunit/regress/regress-3483.js
index 37204ed..dec95c4 100644
--- a/test/mjsunit/harmony/numeric-literals-off.js
+++ b/test/mjsunit/regress/regress-3483.js
@@ -1,4 +1,4 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright 2014 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -25,17 +25,6 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// This is to ensure that we do not support 0b and 0o in Number when
-// the --harmony-numeric-literals flag is not set.
-
-
-function TestOctalLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0o0'));
-}
-TestOctalLiteralUsingNumberFunction();
-
-
-function TestBinaryLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0b0'));
-}
-TestBinaryLiteralUsingNumberFunction();
+assertFalse(Object.prototype.isPrototypeOf.call());
+assertFalse(Object.prototype.isPrototypeOf.call(null, 1));
+assertFalse(Object.prototype.isPrototypeOf.call(undefined, 1));
diff --git a/test/mjsunit/regress/regress-3612.js b/test/mjsunit/regress/regress-3612.js
new file mode 100644
index 0000000..8c30ebf
--- /dev/null
+++ b/test/mjsunit/regress/regress-3612.js
@@ -0,0 +1,21 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var a = [1];
+var getterValue = 2;
+var endIndex = 0xffff;
+Object.defineProperty(a, endIndex, {
+  get: function() {
+    this[1] = 3;
+    return getterValue;
+  },
+  set: function(val) {
+    getterValue = val;
+  },
+  configurable: true,
+  enumerable: true
+});
+a.reverse();
+assertFalse(a.hasOwnProperty(1));
+assertEquals(3, a[endIndex-1]);
diff --git a/test/mjsunit/regress/regress-3621.js b/test/mjsunit/regress/regress-3621.js
new file mode 100644
index 0000000..16ddde1
--- /dev/null
+++ b/test/mjsunit/regress/regress-3621.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var a = [];
+var endIndex = 0xffff;
+a[endIndex] = 3;
+Object.defineProperty(a, 0, { get: function() { this[1] = 2; return 1; } });
+assertEquals('123', a.join(''));
+delete a[1];  // reset the array
+assertEquals('1,2,', a.join().slice(0, 4));
diff --git a/test/mjsunit/regress/regress-3643.js b/test/mjsunit/regress/regress-3643.js
new file mode 100644
index 0000000..bbc94fd
--- /dev/null
+++ b/test/mjsunit/regress/regress-3643.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function newArrayWithGetter() {
+  var arr = [1, 2, 3];
+  Object.defineProperty(arr, '1', {
+    get: function() { delete this[1]; return undefined; },
+    configurable: true
+  });
+  return arr;
+}
+
+var a = newArrayWithGetter();
+var s = a.slice(1);
+assertTrue('0' in s);
+
+// Sparse case should hit the same code as above due to presence of the getter.
+a = newArrayWithGetter();
+a[0xffff] = 4;
+s = a.slice(1);
+assertTrue('0' in s);
+
+a = newArrayWithGetter();
+a.shift();
+assertTrue('0' in a);
+
+a = newArrayWithGetter();
+a.unshift(0);
+assertTrue('2' in a);
diff --git a/test/mjsunit/regress/regress-3687.js b/test/mjsunit/regress/regress-3687.js
new file mode 100644
index 0000000..e1df1b4
--- /dev/null
+++ b/test/mjsunit/regress/regress-3687.js
@@ -0,0 +1,22 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+var t1 = { f1: 0 };
+var t2 = { f2: 0 };
+
+var z = {
+  x: {
+    x: t1,
+    y: {
+      x: {},
+      z1: {
+        x: t2,
+        y: 1
+      }
+    }
+  },
+  z2: 0
+};
diff --git a/test/mjsunit/regress/regress-3709.js b/test/mjsunit/regress/regress-3709.js
new file mode 100644
index 0000000..d2de711
--- /dev/null
+++ b/test/mjsunit/regress/regress-3709.js
@@ -0,0 +1,28 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function getobj() {
+  return { bar : function() { return 0}};
+}
+
+function foo() {
+  var obj = getobj();
+  var length = arguments.length;
+  if (length == 0) {
+     obj.bar();
+  } else {
+     obj.bar.apply(obj, arguments);
+  }
+}
+
+foo();
+foo();
+%OptimizeFunctionOnNextCall(foo);
+foo();
+assertOptimized(foo);
+foo(10);
+assertUnoptimized(foo);
+%ClearFunctionTypeFeedback(foo);
diff --git a/test/mjsunit/regress/regress-3717.js b/test/mjsunit/regress/regress-3717.js
new file mode 100644
index 0000000..1f7bc7d
--- /dev/null
+++ b/test/mjsunit/regress/regress-3717.js
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --no-lazy
+
+Debug = debug.Debug;
+var exception = null;
+var break_count = 0;
+
+function f() {
+  function g(p) {
+    return 1;
+  }
+  g(1);
+};
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) break_count++;
+  } catch (e) {
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+var bp = Debug.setBreakPoint(f, 2);
+f();
+Debug.clearBreakPoint(bp);
+Debug.setListener(null);
+
+assertEquals(1, break_count);
+assertNull(exception);
diff --git a/test/mjsunit/regress/regress-3756.js b/test/mjsunit/regress/regress-3756.js
new file mode 100644
index 0000000..6b1f029
--- /dev/null
+++ b/test/mjsunit/regress/regress-3756.js
@@ -0,0 +1,74 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function TestIdentityEscapes() {
+  // \u not followed by 4 hex digits is treated as an identity escape.
+  var r0 = /\u/;
+  assertTrue(r0.test("u"));
+
+  r0 = RegExp("\\u");
+  assertTrue(r0.test("u"));
+
+  var r1 = /\usecond/;
+  assertTrue(r1.test("usecond"));
+
+  r1 = RegExp("\\usecond");
+  assertTrue(r1.test("usecond"));
+
+  var r2 = /first\u/;
+  assertTrue(r2.test("firstu"));
+  // This used to return true (which was a bug).
+  assertFalse(r2.test("first\\u"));
+
+  r2 = RegExp("first\\u");
+  assertTrue(r2.test("firstu"));
+  // This used to return true (which was a bug).
+  assertFalse(r2.test("first\\u"));
+
+  var r3 = /first\usecond/;
+  assertTrue(r3.test("firstusecond"));
+  assertFalse(r3.test("first\\usecond"));
+
+  r3 = RegExp("first\\usecond");
+  assertTrue(r3.test("firstusecond"));
+  assertFalse(r3.test("first\\usecond"));
+
+  var r4 = /first\u123second/;
+  assertTrue(r4.test("firstu123second"));
+  assertFalse(r4.test("first\\u123second"));
+
+  r4 = RegExp("first\\u123second");
+  assertTrue(r4.test("firstu123second"));
+  assertFalse(r4.test("first\\u123second"));
+
+  // \X where X is not a legal escape character is treated as identity escape
+  // too.
+  var r5 = /\a/;
+  assertTrue(r5.test("a"));
+
+  r5 = RegExp("\\a");
+  assertTrue(r5.test("a"));
+
+  var r6 = /\asecond/;
+  assertTrue(r6.test("asecond"));
+
+  r6 = RegExp("\\asecond");
+  assertTrue(r6.test("asecond"));
+
+  var r7 = /first\a/;
+  assertTrue(r7.test("firsta"));
+  assertFalse(r7.test("first\\a"));
+
+  r7 = RegExp("first\\a");
+  assertTrue(r7.test("firsta"));
+  assertFalse(r7.test("first\\a"));
+
+  var r8 = /first\asecond/;
+  assertTrue(r8.test("firstasecond"));
+  assertFalse(r8.test("first\\asecond"));
+
+  r8 = RegExp("first\\asecond");
+  assertTrue(r8.test("firstasecond"));
+  assertFalse(r8.test("first\\asecond"));
+})();
diff --git a/test/mjsunit/regress/regress-385565.js b/test/mjsunit/regress/regress-385565.js
new file mode 100644
index 0000000..d2a0875
--- /dev/null
+++ b/test/mjsunit/regress/regress-385565.js
@@ -0,0 +1,70 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//   * Redistributions of source code must retain the above copyright
+//     notice, this list of conditions and the following disclaimer.
+//   * Redistributions in binary form must reproduce the above
+//     copyright notice, this list of conditions and the following
+//     disclaimer in the documentation and/or other materials provided
+//     with the distribution.
+//   * Neither the name of Google Inc. nor the names of its
+//     contributors may be used to endorse or promote products derived
+//     from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --noalways-opt
+
+var calls = 0;
+
+function callsFReceiver(o) {
+    return [].f.call(new Number(o.m), 1, 2, 3);
+}
+
+// For the HConstant
+Array.prototype.f = function() {
+    calls++;
+    return +this;
+};
+
+
+var o1 = {m: 1};
+var o2 = {a: 0, m:1};
+
+var r1 = callsFReceiver(o1);
+callsFReceiver(o1);
+%OptimizeFunctionOnNextCall(callsFReceiver);
+var r2 = callsFReceiver(o1);
+assertOptimized(callsFReceiver);
+callsFReceiver(o2);
+assertUnoptimized(callsFReceiver);
+var r3 = callsFReceiver(o1);
+
+assertEquals(1, r1);
+assertTrue(r1 === r2);
+assertTrue(r2 === r3);
+
+r1 = callsFReceiver(o1);
+callsFReceiver(o1);
+%OptimizeFunctionOnNextCall(callsFReceiver);
+r2 = callsFReceiver(o1);
+callsFReceiver(o2);
+r3 = callsFReceiver(o1);
+
+assertEquals(1, r1);
+assertTrue(r1 === r2);
+assertTrue(r2 === r3);
+
+assertEquals(10, calls);
diff --git a/test/mjsunit/regress/regress-410030.js b/test/mjsunit/regress/regress-410030.js
new file mode 100644
index 0000000..efd4b1e
--- /dev/null
+++ b/test/mjsunit/regress/regress-410030.js
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+try {
+  throw 0;
+} catch(e) {
+  assertSame(3, eval("delete x; const x=3; x"));
+}
+
+
+try {
+  throw 0;
+} catch(e) {
+  assertSame(3, (1,eval)("delete x1; const x1=3; x1"));
+}
+
+
+try {
+  throw 0;
+} catch(e) {
+  with({}) {
+    assertSame(3, eval("delete x2; const x2=3; x2"));
+  }
+}
+
+
+(function f() {
+  try {
+    throw 0;
+  } catch(e) {
+    assertSame(3, eval("delete x; const x=3; x"));
+  }
+}());
+
+
+(function f() {
+  try {
+    throw 0;
+  } catch(e) {
+    assertSame(3, (1,eval)("delete x4; const x4=3; x4"));
+  }
+}());
diff --git a/test/mjsunit/regress/regress-416730.js b/test/mjsunit/regress/regress-416730.js
new file mode 100644
index 0000000..8d7f207
--- /dev/null
+++ b/test/mjsunit/regress/regress-416730.js
@@ -0,0 +1,24 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+var d = {x: undefined, y: undefined};
+
+function Crash(left, right) {
+  var c = {
+    x: right.x - left.x,
+    y: right.y - left.y
+  };
+  return c.x * c.y;
+}
+
+var a = {x: 0.5, y: 0};
+var b = {x: 1, y: 0};
+
+for (var i = 0; i < 3; i++) Crash(a, b);
+%OptimizeFunctionOnNextCall(Crash);
+Crash(a, b);
+
+Crash({x: 0, y: 0.5}, b);
diff --git a/test/mjsunit/regress/regress-417709a.js b/test/mjsunit/regress/regress-417709a.js
new file mode 100644
index 0000000..7c4d4f7
--- /dev/null
+++ b/test/mjsunit/regress/regress-417709a.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --stack-size=100 --turbo-deoptimization
+
+var a = [];
+
+Object.observe(a, function() {});
+
+function f(a, x) {
+  a.length = x;
+  f(a, x + 1);
+}
+
+assertThrows(function() { f(a, 1); }, RangeError);
diff --git a/test/mjsunit/regress/regress-417709b.js b/test/mjsunit/regress/regress-417709b.js
new file mode 100644
index 0000000..7680543
--- /dev/null
+++ b/test/mjsunit/regress/regress-417709b.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --stack-size=100
+
+var a = [];
+
+Array.observe(a, function() {});
+
+function f(a, x) {
+  a.length = x;
+  f(a, x + 1);
+}
+
+assertThrows(function() { f(a, 1); }, RangeError);
diff --git a/test/mjsunit/regress/regress-419663.js b/test/mjsunit/regress/regress-419663.js
new file mode 100644
index 0000000..6f51741
--- /dev/null
+++ b/test/mjsunit/regress/regress-419663.js
@@ -0,0 +1,37 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+var o = {
+  f: function(x) {
+    var a = x + 1;
+    o = 1;
+  }
+}
+
+function sentinel() {}
+
+var Debug = debug.Debug;
+
+Debug.setListener(function() {});
+
+var script = Debug.findScript(sentinel);
+
+// Used in Debug.setScriptBreakPointById.
+var p = Debug.findScriptSourcePosition(script, 9, 0);
+var q = Debug.setBreakPointByScriptIdAndPosition(script.id, p).actual_position;
+var r = Debug.setBreakPointByScriptIdAndPosition(script.id, q).actual_position;
+
+assertEquals(q, r);
+
+function assertLocation(p, l, c) {
+  var location = script.locationFromPosition(p, false);
+  assertEquals(l, location.line);
+  assertEquals(c, location.column);
+}
+
+assertLocation(p, 9, 0);
+assertLocation(q, 9, 4);
+assertLocation(r, 9, 4);
diff --git a/test/mjsunit/regress/regress-423633.js b/test/mjsunit/regress/regress-423633.js
new file mode 100644
index 0000000..12d2483
--- /dev/null
+++ b/test/mjsunit/regress/regress-423633.js
@@ -0,0 +1,18 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Object.defineProperty(Array.prototype, '0', {
+  get: function() { return false; },
+});
+var a = [1, 2, 3];
+assertEquals(a, a.slice());
+assertEquals([3], a.splice(2, 1));
+
+a = [1, 2, 3];
+a[0xffff] = 4;
+// nulling the prototype lets us stay in the sparse case; otherwise the
+// getter on Array.prototype would force us into the non-sparse code.
+a.__proto__ = null;
+assertEquals(a, Array.prototype.slice.call(a));
+assertEquals([3], Array.prototype.splice.call(a, 2, 1));
diff --git a/test/mjsunit/regress/regress-425551.js b/test/mjsunit/regress/regress-425551.js
new file mode 100644
index 0000000..eee5e32
--- /dev/null
+++ b/test/mjsunit/regress/regress-425551.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var array = new Int8Array(10);
+array[/\u007d\u00fc\u0043/] = 1.499
+assertEquals(1.499, array[/\u007d\u00fc\u0043/]);
diff --git a/test/mjsunit/harmony/numeric-literals-off.js b/test/mjsunit/regress/regress-430201.js
similarity index 77%
copy from test/mjsunit/harmony/numeric-literals-off.js
copy to test/mjsunit/regress/regress-430201.js
index 37204ed..b53383e 100644
--- a/test/mjsunit/harmony/numeric-literals-off.js
+++ b/test/mjsunit/regress/regress-430201.js
@@ -1,4 +1,4 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -25,17 +25,17 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// This is to ensure that we do not support 0b and 0o in Number when
-// the --harmony-numeric-literals flag is not set.
+// Flags: --allow-natives-syntax --expose-gc
 
+var array_1 = [];
 
-function TestOctalLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0o0'));
+%SetFlags("--stress-compaction");
+for (var a = 0; a < 10000; a++) { array_1[a * 100] = 0; }
+
+gc();
+gc();
+
+var array_2 = [];
+for (var i = 0; i < 321361; i++) {
+  array_2[i] = String.fromCharCode(i)[0];
 }
-TestOctalLiteralUsingNumberFunction();
-
-
-function TestBinaryLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0b0'));
-}
-TestBinaryLiteralUsingNumberFunction();
diff --git a/test/mjsunit/regress/regress-435073.js b/test/mjsunit/regress/regress-435073.js
new file mode 100644
index 0000000..dbaa612
--- /dev/null
+++ b/test/mjsunit/regress/regress-435073.js
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --verify-heap
+
+function test(x) { [x,,]; }
+
+test(0);
+test(0);
+%OptimizeFunctionOnNextCall(test);
+test(0);
diff --git a/test/mjsunit/regress/regress-435477.js b/test/mjsunit/regress/regress-435477.js
new file mode 100644
index 0000000..0a15000
--- /dev/null
+++ b/test/mjsunit/regress/regress-435477.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+var a = new Array(128);
+
+function f(a, base) {
+  a[base] = 2;
+}
+
+f(a, undefined);
+f("r12", undefined);
+f(a, 0);
+%OptimizeFunctionOnNextCall(f);
+f(a, 0);
diff --git a/test/mjsunit/harmony/numeric-literals-off.js b/test/mjsunit/regress/regress-436893.js
similarity index 77%
copy from test/mjsunit/harmony/numeric-literals-off.js
copy to test/mjsunit/regress/regress-436893.js
index 37204ed..38e7b5f 100644
--- a/test/mjsunit/harmony/numeric-literals-off.js
+++ b/test/mjsunit/regress/regress-436893.js
@@ -1,4 +1,4 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -25,17 +25,13 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// This is to ensure that we do not support 0b and 0o in Number when
-// the --harmony-numeric-literals flag is not set.
+// Flags: --allow-natives-syntax
 
-
-function TestOctalLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0o0'));
+var x = 11;
+function foo() {
+  return 42;
 }
-TestOctalLiteralUsingNumberFunction();
-
-
-function TestBinaryLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0b0'));
-}
-TestBinaryLiteralUsingNumberFunction();
+// Test passing null or undefined as receiver.
+function g() { return foo.apply(null, x()++); }
+%OptimizeFunctionOnNextCall(g);
+assertThrows(g);
diff --git a/test/mjsunit/regress/regress-436896.js b/test/mjsunit/regress/regress-436896.js
new file mode 100644
index 0000000..344a7a3
--- /dev/null
+++ b/test/mjsunit/regress/regress-436896.js
@@ -0,0 +1,17 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(x) {
+  const x = 0;
+  return x;
+}
+
+function g(x) {
+  return f(x);
+}
+
+%OptimizeFunctionOnNextCall(g);
+assertThrows(function() { g(42); }, TypeError);
diff --git a/test/mjsunit/regress/regress-437765.js b/test/mjsunit/regress/regress-437765.js
new file mode 100644
index 0000000..88d5388
--- /dev/null
+++ b/test/mjsunit/regress/regress-437765.js
@@ -0,0 +1,22 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --no-fold-constants
+
+function foo(x, y) {
+  return Math.floor(x / y);
+}
+
+function bar(x, y) {
+  return foo(x + 1, y + 1);
+}
+
+function baz() {
+  bar(64, 2);
+}
+
+baz();
+baz();
+%OptimizeFunctionOnNextCall(baz);
+baz();
diff --git a/test/mjsunit/regress/regress-441099.js b/test/mjsunit/regress/regress-441099.js
new file mode 100644
index 0000000..63aecfd
--- /dev/null
+++ b/test/mjsunit/regress/regress-441099.js
@@ -0,0 +1,53 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var Module;
+if (!Module) Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
+else if (ENVIRONMENT_IS_SHELL) {
+}
+var Runtime = {
+  stackSave: function () {
+  },
+  alignMemory: function (quantum) { var ret = size = Math.ceil()*(quantum ? quantum : 8); return ret; }}
+function allocate() {
+}
+function callRuntimeCallbacks(callbacks) {
+    var callback = callbacks.shift();
+    var func = callback.func;
+    if (typeof func === 'number') {
+    } else {
+      func();
+    }
+}
+var __ATINIT__    = []; // functions called during startup
+function ensureInitRuntime() {
+  callRuntimeCallbacks(__ATINIT__);
+}
+/* global initializers */ __ATINIT__.push({ func: function() { runPostSets() } });
+    function __formatString() {
+            switch (next) {
+            }
+    }
+  var Browser={mainLoop:{queue:[],pause:function () {
+        }},moduleContextCreatedCallbacks:[],workers:[],init:function () {
+      }};
+var asm = (function() {
+  'use asm';
+function setThrew() {
+}
+function runPostSets() {
+}
+function _main() {
+}
+function _free() {
+}
+  return { runPostSets: runPostSets};
+})
+();
+var runPostSets = Module["runPostSets"] = asm["runPostSets"];
+var i64Math = (function() { // Emscripten wrapper
+  /**
+   */
+})();
+    ensureInitRuntime();
diff --git a/test/mjsunit/regress/regress-447756.js b/test/mjsunit/regress/regress-447756.js
new file mode 100644
index 0000000..1fc7518
--- /dev/null
+++ b/test/mjsunit/regress/regress-447756.js
@@ -0,0 +1,48 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --allow-natives-syntax
+
+function TestConstructor(c) {
+  var a = new c(-0);
+  assertSame(Infinity, 1 / a.length);
+  assertSame(Infinity, 1 / a.byteLength);
+
+  var ab = new ArrayBuffer(-0);
+  assertSame(Infinity, 1 / ab.byteLength);
+
+  var a1 = new c(ab, -0, -0);
+  assertSame(Infinity, 1 / a1.length);
+  assertSame(Infinity, 1 / a1.byteLength);
+  assertSame(Infinity, 1 / a1.byteOffset);
+}
+
+var constructors =
+  [ Uint8Array, Int8Array, Uint8ClampedArray,
+    Uint16Array, Int16Array,
+    Uint32Array, Int32Array,
+    Float32Array, Float64Array ];
+for (var i = 0; i < constructors.length; i++) {
+  TestConstructor(constructors[i]);
+}
+
+
+function TestOptimizedCode() {
+  var a = new Uint8Array(-0);
+  assertSame(Infinity, 1 / a.length);
+  assertSame(Infinity, 1 / a.byteLength);
+
+  var ab = new ArrayBuffer(-0);
+  assertSame(Infinity, 1 / ab.byteLength);
+
+  var a1 = new Uint8Array(ab, -0, -0);
+  assertSame(Infinity, 1 / a1.length);
+  assertSame(Infinity, 1 / a1.byteLength);
+  assertSame(Infinity, 1 / a1.byteOffset);
+}
+
+%OptimizeFunctionOnNextCall(Uint8Array);
+for (var i = 0; i < 1000; i++) {
+  TestOptimizedCode();
+}
diff --git a/test/mjsunit/regress/regress-78270.js b/test/mjsunit/regress/regress-78270.js
index b9ce286..02c4b14 100644
--- a/test/mjsunit/regress/regress-78270.js
+++ b/test/mjsunit/regress/regress-78270.js
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --turbo-deoptimization
+
 for (var i = 0; i < 10000; i++) {
   try {
     var object = { };
diff --git a/test/mjsunit/regress/regress-assignment-in-test-context.js b/test/mjsunit/regress/regress-assignment-in-test-context.js
new file mode 100644
index 0000000..bc40985
--- /dev/null
+++ b/test/mjsunit/regress/regress-assignment-in-test-context.js
@@ -0,0 +1,20 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --always-opt
+// Flags: --turbo-filter=* --turbo-deoptimization
+
+function assertEquals() {}
+
+function f(o) {
+  if (o.setterProperty = 0) {
+    return 1;
+  }
+  return 2;
+}
+
+function deopt() { %DeoptimizeFunction(f); }
+
+assertEquals(2,
+             f(Object.defineProperty({}, "setterProperty", { set: deopt })));
diff --git a/test/mjsunit/regress/regress-crbug-109362.js b/test/mjsunit/regress/regress-crbug-109362.js
new file mode 100644
index 0000000..b156013
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-109362.js
@@ -0,0 +1,26 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+function test(expectation, f) {
+  var stack;
+  try {
+    f();
+  } catch (e) {
+    stack = e.stack;
+  }
+  print(stack);
+  assertTrue(stack.indexOf("at eval (evaltest:" + expectation + ")") > 0);
+}
+
+test("1:5", new Function(
+    '1 + reference_error //@ sourceURL=evaltest'));
+test("2:6", new Function(
+    'x', '\n 1 + reference_error //@ sourceURL=evaltest'));
+test("2:6", new Function(
+    'x\n\n', "z//\n", "y", '\n 1 + reference_error //@ sourceURL=evaltest'));
+test("1:5", new Function(
+    'x/*', "z//\n", "y*/", '1 + reference_error //@ sourceURL=evaltest'));
+test("2:6", eval(
+    '(function () {\n 1 + reference_error //@ sourceURL=evaltest\n})'));
diff --git a/test/mjsunit/regress/regress-crbug-320922.js b/test/mjsunit/regress/regress-crbug-320922.js
index 9ba759a..f199628 100644
--- a/test/mjsunit/regress/regress-crbug-320922.js
+++ b/test/mjsunit/regress/regress-crbug-320922.js
@@ -27,8 +27,10 @@
 
 // Flags: --allow-natives-syntax
 
-var string = "hello world";
-var expected = "Hello " + "world";
+var string = "internalized dummy";
+var expected = "internalized dummy";
+string = "hello world";
+expected = "Hello " + "world";
 function Capitalize() {
   %_OneByteSeqStringSetChar(0, 0x48, string);
 }
diff --git a/test/mjsunit/regress/regress-crbug-323936.js b/test/mjsunit/regress/regress-crbug-323936.js
new file mode 100644
index 0000000..d896ead
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-323936.js
@@ -0,0 +1,46 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+Debug = debug.Debug;
+
+var step = 0;
+var exception = null;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    if (step == 0) {
+      assertEquals("error", exec_state.frame(0).evaluate("e").value());
+      exec_state.frame(0).evaluate("e = 'foo'");
+      exec_state.frame(0).evaluate("x = 'modified'");
+    } else {
+      assertEquals("argument", exec_state.frame(0).evaluate("e").value());
+      exec_state.frame(0).evaluate("e = 'bar'");
+    }
+    step++;
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+
+function f(e, x) {
+  try {
+    throw "error";
+  } catch(e) {
+    debugger;
+    assertEquals("foo", e);
+  }
+  debugger;
+  assertEquals("bar", e);
+  assertEquals("modified", x);
+}
+
+f("argument")
+assertNull(exception);
+assertEquals(2, step);
diff --git a/test/mjsunit/regress/regress-crbug-409614.js b/test/mjsunit/regress/regress-crbug-409614.js
new file mode 100644
index 0000000..7b27404
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-409614.js
@@ -0,0 +1,37 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+Debug = debug.Debug;
+var exception = null;
+var error_count = 0;
+
+function f() {
+  return 0;  // Break
+}
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    if (exec_state.frame(0).sourceLineText().indexOf("Break") <0) {
+      error_count++;
+    }
+    exec_state.prepareStep(Debug.StepAction.StepIn, 2);
+    f();  // We should not break in this call of f().
+  } catch (e) {
+    print(e + e.stack);
+    exception = e;
+  }
+}
+
+Debug.setListener(listener);
+
+debugger;  // Break
+f();
+
+Debug.setListener(null);  // Break
+
+assertNull(exception);
+assertEquals(0, error_count);
diff --git a/test/mjsunit/regress/regress-crbug-410033.js b/test/mjsunit/regress/regress-crbug-410033.js
new file mode 100644
index 0000000..63693e6
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-410033.js
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --expose-gc
+
+%GetScript('v8/gc');
diff --git a/test/mjsunit/regress/regress-crbug-412319.js b/test/mjsunit/regress/regress-crbug-412319.js
index 21386e3..c597b0d 100644
--- a/test/mjsunit/regress/regress-crbug-412319.js
+++ b/test/mjsunit/regress/regress-crbug-412319.js
@@ -15,5 +15,5 @@
 %OptimizeFunctionOnNextCall(__f_6);
 __f_6();
 function __f_7(__v_7) {
-  __v_7.push(Infinity);
+  __v_7.pop();
 }
diff --git a/test/mjsunit/regress/regress-crbug-416558.js b/test/mjsunit/regress/regress-crbug-416558.js
new file mode 100644
index 0000000..375ad40
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-416558.js
@@ -0,0 +1,115 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = /x/;
+  store(c);
+  function get_hole() {
+    var b = /x/;
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Date();
+  store(c);
+  function get_hole() {
+    var b = new Date();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Number(1);
+  store(c);
+  function get_hole() {
+    var b = new Number(1);
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Boolean();
+  store(c);
+  function get_hole() {
+    var b = new Boolean();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Map();
+  store(c);
+  function get_hole() {
+    var b = new Map();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new Set();
+  store(c);
+  function get_hole() {
+    var b = new Set();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new WeakMap();
+  store(c);
+  function get_hole() {
+    var b = new WeakMap();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
+
+(function() {
+  function store(x) { x[0] = 0; }
+  store([]);
+  var c = new WeakSet();
+  store(c);
+  function get_hole() {
+    var b = new WeakSet();
+    store(b);
+    return b[1];
+  }
+  assertEquals(undefined, get_hole());
+  assertEquals(undefined, get_hole());
+})();
diff --git a/test/mjsunit/regress/regress-crbug-424142.js b/test/mjsunit/regress/regress-crbug-424142.js
new file mode 100644
index 0000000..0a370d4
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-424142.js
@@ -0,0 +1,36 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+(function outer() {
+  var C = (function C_() {
+    var y = 1;
+    function CC() {
+      this.x = 0;
+    }
+    CC.prototype.f = function CCf() {
+      this.x += y;
+      return this.x;
+    };
+    return CC;
+  })();
+
+  var c = new C(0);
+})
+
+function sentinel() {}
+
+Debug = debug.Debug;
+
+var script = Debug.findScript(sentinel);
+var line = 14;
+var line_start = Debug.findScriptSourcePosition(script, line, 0);
+var line_end = Debug.findScriptSourcePosition(script, line + 1, 0) - 1;
+var actual = Debug.setBreakPointByScriptIdAndPosition(
+                 script.id, line_start).actual_position;
+// Make sure the actual break position is within the line where we set
+// the break point.
+assertTrue(line_start <= actual);
+assertTrue(actual <= line_end);
diff --git a/test/mjsunit/regress/regress-crbug-425519.js b/test/mjsunit/regress/regress-crbug-425519.js
new file mode 100644
index 0000000..d08e7b9
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-425519.js
@@ -0,0 +1,15 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function load(a, i) {
+  return a[i];
+}
+
+load([]);
+load(0);
+load("x", 0);
+%OptimizeFunctionOnNextCall(load);
+load([], 0);
diff --git a/test/mjsunit/harmony/numeric-literals-off.js b/test/mjsunit/regress/regress-crbug-425585.js
similarity index 73%
copy from test/mjsunit/harmony/numeric-literals-off.js
copy to test/mjsunit/regress/regress-crbug-425585.js
index 37204ed..c27febb 100644
--- a/test/mjsunit/harmony/numeric-literals-off.js
+++ b/test/mjsunit/regress/regress-crbug-425585.js
@@ -1,4 +1,4 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright 2014 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -25,17 +25,24 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// This is to ensure that we do not support 0b and 0o in Number when
-// the --harmony-numeric-literals flag is not set.
 
+var correct_result = "This is the correct result.";
 
-function TestOctalLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0o0'));
+function foo(recursion_depth) {
+   if (recursion_depth > 0) return foo(recursion_depth - 1);
+   return new String(correct_result, 1, 2, 3, 4, 5, 6);
 }
-TestOctalLiteralUsingNumberFunction();
 
-
-function TestBinaryLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0b0'));
+// Roll our own non-strict assertEquals replacement.
+function test(i) {
+   var actual = foo(i);
+   if (correct_result != actual) {
+     var msg = "Expected \"" + correct_result + "\", found " + actual;
+     throw new MjsUnitAssertionError(msg);
+   }
 }
-TestBinaryLiteralUsingNumberFunction();
+
+test(1);
+test(1);
+test(10);
+test(100);
diff --git a/test/mjsunit/regress/regress-crbug-429159.js b/test/mjsunit/regress/regress-crbug-429159.js
new file mode 100644
index 0000000..69f1856
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-429159.js
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+try {
+  var src = "return " + Array(12000).join("src,") + "src";
+  var fun = Function(src);
+  assertEquals(src, fun());
+} catch (e) {
+  // Some architectures throw a RangeError, that is fine.
+  assertInstanceof(e, RangeError);
+}
diff --git a/test/mjsunit/regress/regress-crbug-430846.js b/test/mjsunit/regress/regress-crbug-430846.js
new file mode 100644
index 0000000..3047c7f
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-430846.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function foo() { return 1; };
+var o1 = {};
+o1.foo = foo;
+
+var json = '{"foo": {"x": 1}}';
+var o2 = JSON.parse(json);
+var o3 = JSON.parse(json);
+assertTrue(%HaveSameMap(o2, o3));
diff --git a/test/mjsunit/regress/regress-crbug-431602.js b/test/mjsunit/regress/regress-crbug-431602.js
new file mode 100644
index 0000000..2467aaf
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-431602.js
@@ -0,0 +1,23 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --always-opt
+
+var heap_number_producer = {y:1.5};
+heap_number_producer.y = 0;
+var heap_number_zero = heap_number_producer.y;
+var non_constant_eight = {};
+non_constant_eight = 8;
+
+function BreakIt() {
+  return heap_number_zero | (1 | non_constant_eight);
+}
+
+function expose(a, b, c) {
+  return b;
+}
+
+assertEquals(9, expose(8, 9, 10));
+assertEquals(9, expose(8, BreakIt(), 10));
+assertEquals(9, BreakIt());
diff --git a/test/mjsunit/regress/regress-crbug-432493.js b/test/mjsunit/regress/regress-crbug-432493.js
new file mode 100644
index 0000000..87c4f83
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-432493.js
@@ -0,0 +1,57 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+
+function f() {
+  var a = 1;
+  var b = 2;
+  return a + b;
+}
+
+var exception = null;
+var break_count = 0;
+var throw_count = 0;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      break_count++;
+      // Disable all breakpoints from within the debug event callback.
+      Debug.debuggerFlags().breakPointsActive.setValue(false);
+    } else if (event = Debug.DebugEvent.Exception) {
+      throw_count++;
+      // Enable all breakpoints from within the debug event callback.
+      Debug.debuggerFlags().breakPointsActive.setValue(true);
+    }
+  } catch (e) {
+    exception = e;
+  }
+}
+
+Debug = debug.Debug;
+
+Debug.setListener(listener);
+Debug.setBreakOnException();
+Debug.setBreakPoint(f, 2);
+
+f();
+f();
+
+assertEquals(1, break_count);
+assertEquals(0, throw_count);
+
+// Trigger exception event.
+try { throw 1; } catch (e) {}
+
+f();
+f();
+
+Debug.setListener(null);
+Debug.clearBreakOnException();
+Debug.debuggerFlags().breakPointsActive.setValue(true);
+
+assertEquals(2, break_count);
+assertEquals(1, throw_count);
+assertNull(exception);
diff --git a/test/mjsunit/regress/regress-crbug-433332.js b/test/mjsunit/regress/regress-crbug-433332.js
new file mode 100644
index 0000000..d763243
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-433332.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(foo) {
+  var g;
+  true ? (g = 0.1) : g |=  null;
+  if (null != g) {}
+};
+
+f(1.4);
+f(1.4);
+%OptimizeFunctionOnNextCall(f);
+f(1.4);
diff --git a/test/mjsunit/regress/regress-crbug-433766.js b/test/mjsunit/regress/regress-crbug-433766.js
new file mode 100644
index 0000000..fae9483
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-433766.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var filler = "//" + new Array(('@')).join('x');
+
+// Test strict eval in global context.
+eval(
+  "'use strict';" +
+  "var x = 23;" +
+  "var f = function bozo1() {" +
+  "  return x;" +
+  "};" +
+  "f;" +
+  filler
+)();
diff --git a/test/mjsunit/regress/regress-crbug-435825.js b/test/mjsunit/regress/regress-crbug-435825.js
new file mode 100644
index 0000000..e10b812
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-435825.js
@@ -0,0 +1,11 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Error.prepareStackTrace = function (a,b) { return b; };
+
+try {
+  /(invalid regexp/;
+} catch (e) {
+  e.stack[0].getThis().toString();
+}
diff --git a/test/mjsunit/regress/regress-crbug-436820.js b/test/mjsunit/regress/regress-crbug-436820.js
new file mode 100644
index 0000000..eea386c
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-436820.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function c(p) {
+  return {__proto__: p};
+}
+var p = {};
+var o = c(p);
+p.x = 0.6;
+Object.defineProperty(p, "x", { writable: false });
diff --git a/test/mjsunit/regress/regress-eval-cache.js b/test/mjsunit/regress/regress-eval-cache.js
new file mode 100644
index 0000000..8f8dc18
--- /dev/null
+++ b/test/mjsunit/regress/regress-eval-cache.js
@@ -0,0 +1,19 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function f() {
+  try {
+    throw 1;
+  } catch (e) {
+    var a = 0;
+    var b = 0;
+    var c = 0;
+    var x = 1;
+    var result = eval('eval("x")').toString();
+    assertEquals("1", result);
+  }
+  var x = 2;
+  var result = eval('eval("x")').toString();
+  assertEquals("2", result);
+})();
diff --git a/test/mjsunit/regress/regress-lea-matching.js b/test/mjsunit/regress/regress-lea-matching.js
new file mode 100644
index 0000000..988368a
--- /dev/null
+++ b/test/mjsunit/regress/regress-lea-matching.js
@@ -0,0 +1,14 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f(a, b, c) {
+  a = a|0;
+  b = b|0;
+  c = c|0;
+  var r = 0;
+  r = a + ((b << 1) + c) | 0;
+  return r|0;
+}
+
+assertEquals(8, f(1, 2, 3));
diff --git a/test/mjsunit/regress/regress-parse-object-literal.js b/test/mjsunit/regress/regress-parse-object-literal.js
index 96d63c2..93725eb 100644
--- a/test/mjsunit/regress/regress-parse-object-literal.js
+++ b/test/mjsunit/regress/regress-parse-object-literal.js
@@ -24,6 +24,8 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Flags: --noharmony-classes --noharmony-object-literals
 
 // Should throw, not crash.
 assertThrows("var o = { get /*space*/ () {} }");
diff --git a/test/mjsunit/regress/regress-shift-enumerable.js b/test/mjsunit/regress/regress-shift-enumerable.js
new file mode 100644
index 0000000..f3ee258
--- /dev/null
+++ b/test/mjsunit/regress/regress-shift-enumerable.js
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var arr = [1, 2];
+Object.defineProperty(arr, 0xfffe, {
+  value: 3,
+  configurable: true,
+  writable: true,
+  enumerable: false
+});
+arr[0xffff] = 4;
+arr.shift();
+var desc = Object.getOwnPropertyDescriptor(arr, 0xfffe);
+assertEquals(4, desc.value);
+assertFalse(desc.enumerable);
diff --git a/test/mjsunit/harmony/numeric-literals-off.js b/test/mjsunit/regress/regress-splice-large-index.js
similarity index 79%
rename from test/mjsunit/harmony/numeric-literals-off.js
rename to test/mjsunit/regress/regress-splice-large-index.js
index 37204ed..5da17ee 100644
--- a/test/mjsunit/harmony/numeric-literals-off.js
+++ b/test/mjsunit/regress/regress-splice-large-index.js
@@ -25,17 +25,16 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// This is to ensure that we do not support 0b and 0o in Number when
-// the --harmony-numeric-literals flag is not set.
+var a = [];
+a[0xfffffffe] = 10;
+assertThrows("a.unshift(1);", RangeError);
+assertEquals(0xffffffff, a.length);
+assertEquals(10, a[0xffffffff]);
+assertEquals(undefined, a[0xfffffffe]);
 
-
-function TestOctalLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0o0'));
-}
-TestOctalLiteralUsingNumberFunction();
-
-
-function TestBinaryLiteralUsingNumberFunction() {
-  assertEquals(NaN, Number('0b0'));
-}
-TestBinaryLiteralUsingNumberFunction();
+a = [1,2,3];
+a[0xfffffffe] = 10;
+assertThrows("a.splice(1,1,7,7,7,7,7);", RangeError);
+assertEquals([1,7,7,7,7,7,3], a.slice(0, 7));
+assertEquals(0xffffffff, a.length);
+assertEquals(10, a[0xfffffffe + 5 - 1]);
diff --git a/test/mjsunit/regress/regress-unsigned-mul-add.js b/test/mjsunit/regress/regress-unsigned-mul-add.js
new file mode 100644
index 0000000..0a2fc65
--- /dev/null
+++ b/test/mjsunit/regress/regress-unsigned-mul-add.js
@@ -0,0 +1,10 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f(a) {
+  var x = a >>> 0;
+  return (x * 1.0 + x * 1.0) << 0;
+}
+
+assertEquals(-2, f(-1));
diff --git a/test/mjsunit/regress/regress-weakening-multiplication.js b/test/mjsunit/regress/regress-weakening-multiplication.js
new file mode 100644
index 0000000..dcf0011
--- /dev/null
+++ b/test/mjsunit/regress/regress-weakening-multiplication.js
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f() {
+  for (var j = 1; j < 1; j *= -8) {
+  }
+  for (var i = 1; i < 1; j += 2) {
+    j * -1;
+  }
+}
+f();
diff --git a/test/mjsunit/runtime-gen/loadfromsuper.js b/test/mjsunit/runtime-gen/loadfromsuper.js
deleted file mode 100644
index 25f4ff9..0000000
--- a/test/mjsunit/runtime-gen/loadfromsuper.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
-// Flags: --allow-natives-syntax --harmony --harmony-proxies
-var _home_object = new Object();
-var _receiver = new Object();
-var _name = "name";
-%LoadFromSuper(_home_object, _receiver, _name);
diff --git a/test/mjsunit/serialize-embedded-error.js b/test/mjsunit/serialize-embedded-error.js
new file mode 100644
index 0000000..473c931
--- /dev/null
+++ b/test/mjsunit/serialize-embedded-error.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// --serialize-toplevel --cache=code
+
+var caught = false;
+try {
+  parseInt() = 0;
+} catch(e) {
+  caught = true;
+}
+assertTrue(caught);
diff --git a/test/mjsunit/serialize-ic.js b/test/mjsunit/serialize-ic.js
new file mode 100644
index 0000000..8e5cd2f
--- /dev/null
+++ b/test/mjsunit/serialize-ic.js
@@ -0,0 +1,18 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --cache=code --serialize-toplevel
+
+var foo = [];
+foo[0] = "bar";
+assertEquals(["bar"], foo);
+
+var a;
+var b = 1;
+a = [2];               // STORE_IC
+a[0] = a[0] + 1;       // KEYED_STORE_IC, KEYED_LOAD_IC, BINARY_OP_IC
+assertTrue(a[0] > b);  // CALL_IC, COMPARE_IC
+b = b == null;         // COMPARE_NIL_IC
+b = b || Boolean('');  // TO_BOOLEAN_IC
+assertFalse(b);
diff --git a/test/mjsunit/setters-on-elements.js b/test/mjsunit/setters-on-elements.js
index dd3fabf..001906c 100644
--- a/test/mjsunit/setters-on-elements.js
+++ b/test/mjsunit/setters-on-elements.js
@@ -191,8 +191,8 @@
 
 var values = [3, 3.5, true];
 
-for(var c = 0; c < 3; c++) {
-  for(var s = 0; s < 3; s++) {
+for(var c = 0; c < cf.length; c++) {
+  for(var s = 0; s < values.length; s++) {
     base_setter_test(cf[c], 0, values[s]);
     base_setter_test(cf[c], 1, values[s]);
   }
diff --git a/test/mjsunit/strict-mode.js b/test/mjsunit/strict-mode.js
index 5fb404a..62d003f 100644
--- a/test/mjsunit/strict-mode.js
+++ b/test/mjsunit/strict-mode.js
@@ -25,6 +25,9 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Flags: --turbo-deoptimization --noharmony-scoping
+// Flags: --noharmony-classes --noharmony-object-literals
+
 function CheckStrictMode(code, exception) {
   assertDoesNotThrow(code);
   assertThrows("'use strict';\n" + code, exception);
diff --git a/test/mjsunit/string-slices.js b/test/mjsunit/string-slices.js
index c3f889b..52f1506 100644
--- a/test/mjsunit/string-slices.js
+++ b/test/mjsunit/string-slices.js
@@ -193,7 +193,8 @@
     utf.substring(5,1) + utf.substring(3,7));
 
 // Externalizing strings.
-var a = "123456789" + "qwertyuiopasdfghjklzxcvbnm";
+var a = "internalized dummy";
+a = "123456789" + "qwertyuiopasdfghjklzxcvbnm";
 var b = "23456789qwertyuiopasdfghjklzxcvbn"
 assertEquals(a.slice(1,-1), b);
 
diff --git a/test/mjsunit/test-hidden-string.js b/test/mjsunit/test-hidden-string.js
deleted file mode 100644
index a5d32c8..0000000
--- a/test/mjsunit/test-hidden-string.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Flags: --allow-natives-syntax
-
-var o = {};
-%SetHiddenProperty(o, "test", 1);
-// Create non-internalized ""
-var empty = "a".substring(1, 1);
-assertEquals(undefined, o[empty]);
diff --git a/test/mjsunit/third_party/object-keys.js b/test/mjsunit/third_party/object-keys.js
index d09265c..c800374 100644
--- a/test/mjsunit/third_party/object-keys.js
+++ b/test/mjsunit/third_party/object-keys.js
@@ -31,8 +31,8 @@
 
 // Based on LayoutTests/fast/js/Object-keys.html
 
-assertThrows(function () { Object.keys(2) }, TypeError);
-assertThrows(function () { Object.keys("foo") }, TypeError);
+assertEquals(Object.keys(2), []);
+assertEquals(Object.keys("foo"), ["0", "1", "2"]);
 assertThrows(function () { Object.keys(null) }, TypeError);
 assertThrows(function () { Object.keys(undefined) }, TypeError);
 
diff --git a/test/mjsunit/tools/tickprocessor-test.default b/test/mjsunit/tools/tickprocessor-test.default
index 3e01532..c2fe441 100644
--- a/test/mjsunit/tools/tickprocessor-test.default
+++ b/test/mjsunit/tools/tickprocessor-test.default
@@ -24,6 +24,13 @@
       4   30.8%          Shared libraries
       2   15.4%          Unaccounted
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+      2   40.0%   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1   20.0%    7.7%  v8::internal::JSObject::LookupOwnRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1   20.0%    7.7%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1   20.0%    7.7%  exp
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/tools/tickprocessor-test.func-info b/test/mjsunit/tools/tickprocessor-test.func-info
index c93b6ec..1f34cfb 100644
--- a/test/mjsunit/tools/tickprocessor-test.func-info
+++ b/test/mjsunit/tools/tickprocessor-test.func-info
@@ -18,6 +18,9 @@
       0    0.0%    0.0%  GC
       0    0.0%          Shared libraries
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/tools/tickprocessor-test.gc-state b/test/mjsunit/tools/tickprocessor-test.gc-state
index 6b1a6a3..d96acf5 100644
--- a/test/mjsunit/tools/tickprocessor-test.gc-state
+++ b/test/mjsunit/tools/tickprocessor-test.gc-state
@@ -16,6 +16,9 @@
       0    0.0%    0.0%  GC
       0    0.0%          Shared libraries
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/tools/tickprocessor-test.ignore-unknown b/test/mjsunit/tools/tickprocessor-test.ignore-unknown
index de70527..263cec5 100644
--- a/test/mjsunit/tools/tickprocessor-test.ignore-unknown
+++ b/test/mjsunit/tools/tickprocessor-test.ignore-unknown
@@ -23,6 +23,13 @@
       0    0.0%    0.0%  GC
       4   36.4%          Shared libraries
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+      2   40.0%   18.2%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1   20.0%    9.1%  v8::internal::JSObject::LookupOwnRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1   20.0%    9.1%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1   20.0%    9.1%  exp
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/tools/tickprocessor-test.separate-ic b/test/mjsunit/tools/tickprocessor-test.separate-ic
index 119ccbe..aee1d1f 100644
--- a/test/mjsunit/tools/tickprocessor-test.separate-ic
+++ b/test/mjsunit/tools/tickprocessor-test.separate-ic
@@ -26,6 +26,13 @@
       4   30.8%          Shared libraries
       2   15.4%          Unaccounted
 
+ [C++ entry points]:
+   ticks    cpp   total   name
+      2   40.0%   15.4%  v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+      1   20.0%    7.7%  v8::internal::JSObject::LookupOwnRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+      1   20.0%    7.7%  v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+      1   20.0%    7.7%  exp
+
  [Bottom up (heavy) profile]:
   Note: percentage shows a share of a particular caller in the total
   amount of its parent calls.
diff --git a/test/mjsunit/unused-context-in-with.js b/test/mjsunit/unused-context-in-with.js
new file mode 100644
index 0000000..2973ca2
--- /dev/null
+++ b/test/mjsunit/unused-context-in-with.js
@@ -0,0 +1,13 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var x = 1;
+function foo(object) {
+  with(object) {
+    x;
+  }
+  return 100;
+}
+
+assertEquals(100,foo("str"));
diff --git a/test/mjsunit/var.js b/test/mjsunit/var.js
index 5999d70..c3c331e 100644
--- a/test/mjsunit/var.js
+++ b/test/mjsunit/var.js
@@ -35,3 +35,22 @@
 assertTrue(!z && typeof z == 'undefined');
 if (false) { var z; }
 assertTrue(!z && typeof z == 'undefined');
+
+assertThrows("var \u2E2F;", SyntaxError);
+assertThrows("var \\u2E2F;", SyntaxError);
+
+assertDoesNotThrow("var \u2118;");
+assertDoesNotThrow("var \\u2118;");
+assertDoesNotThrow("var \u212E;");
+assertDoesNotThrow("var \\u212E;");
+assertDoesNotThrow("var \u309B;");
+assertDoesNotThrow("var \\u309B;");
+assertDoesNotThrow("var \u309C;");
+assertDoesNotThrow("var \\u309C;");
+
+assertDoesNotThrow("var $\u00B7;");
+assertDoesNotThrow("var $\u0387;");
+assertDoesNotThrow("var $\u1369;");
+assertDoesNotThrow("var $\u1370;");
+assertDoesNotThrow("var $\u1371;");
+assertDoesNotThrow("var $\u19DA;");
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index e9f58c6..9ba07f7 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -117,6 +117,11 @@
   'js1_5/GC/regress-348532': [SKIP],
 
 
+  # Runs for too long: huge array with getters and setters. As it says
+  # in the test: "This test will probably run out of memory".
+  'js1_5/extensions/regress-345967': [SKIP],
+
+
   ##################### FLAKY TESTS #####################
 
   # These tests time out in debug mode but pass in product mode
@@ -216,7 +221,8 @@
 
   # Test that depends on timer resolution. Fails every now and then
   # if we're unlucky enough to get a context switch at a bad time.
-  'js1_5/extensions/regress-363258': [PASS, FAIL],
+  # TODO(mstarzinger): Switch off TF on windows due to timeouts.
+  'js1_5/extensions/regress-363258': [PASS, FAIL, ['system == windows', NO_VARIANTS]],
 
 
   # Test that assumes specific runtime for a regexp, flaky in debug mode.
@@ -273,21 +279,6 @@
   # RegExp flags.
   'ecma_3/RegExp/15.10.4.1-6': [FAIL_OK],
 
-  # PCRE doesn't allow subpattern nesting deeper than 200, this tests
-  # depth 500.  JSC detects the case, and return null from the match,
-  # and passes this test (the test doesn't check for a correct return
-  # value).
-  'ecma_3/RegExp/regress-119909': [PASS, FAIL_OK],
-
-
-  # Difference in the way capturing subpatterns work.  In JS, when the
-  # 'minimum repeat count' is reached, the empty string must not match.
-  # In this case, we are similar but not identical to JSC.  Hard to
-  # support the JS behavior with PCRE, so maybe emulate JSC?
-  'ecma_3/RegExp/regress-209919': [PASS, FAIL_OK],
-  'js1_5/extensions/regress-459606': [PASS, FAIL_OK],
-
-
   # PCRE's match limit is reached.  SpiderMonkey hangs on the first one,
   # JSC returns true somehow.  Maybe they up the match limit?  There is
   # an open V8 bug 676063 about this.
@@ -310,12 +301,12 @@
   'js1_5/Regress/regress-230216-2': [FAIL_OK],
 
 
-  # Regexp too long for PCRE.
-  'js1_5/Regress/regress-280769': [PASS, FAIL],
-  'js1_5/Regress/regress-280769-1': [PASS, FAIL],
-  'js1_5/Regress/regress-280769-2': [PASS, FAIL],
-  'js1_5/Regress/regress-280769-4': [PASS, FAIL],
-  'js1_5/Regress/regress-280769-5': [PASS, FAIL],
+  # BUG(v8:3767)
+  'js1_5/Regress/regress-280769-2': [PASS, ['arch == arm64', SKIP]],
+
+  # Regexps too big.
+  'js1_5/Regress/regress-280769-1': [SKIP],
+  'js1_5/Regress/regress-280769-5': [SKIP],
 
 
   # We do not support static RegExp.multiline - should we?.
@@ -361,9 +352,9 @@
 
 
   # No support for toSource().
-  'js1_5/Regress/regress-248444': [FAIL_OK],
   'js1_5/Regress/regress-313967-01': [FAIL_OK],
   'js1_5/Regress/regress-313967-02': [FAIL_OK],
+  'js1_5/extensions/regress-459606': [FAIL_OK],
 
   # This fails because we don't have stack space for Function.prototype.apply
   # with very large numbers of arguments.  The test uses 2^24 arguments.
@@ -567,11 +558,6 @@
   'js1_5/Regress/regress-336100': [FAIL_OK],
 
 
-  # Regular expression test failures due to PCRE. We match JSC (ie, perl)
-  # behavior and not the ECMA spec.
-  'ecma_3/RegExp/perlstress-001': [PASS, FAIL_OK],
-  'ecma_3/RegExp/regress-334158': [PASS, FAIL],
-
   # This test fails due to http://code.google.com/p/v8/issues/detail?id=187
   # Failure to clear captures when a lookahead is unwound.
   'ecma_3/RegExp/15.10.2-1': [PASS, FAIL_OK],
@@ -674,7 +660,6 @@
   'js1_5/extensions/regress-311792-01': [FAIL_OK],
   'js1_5/extensions/regress-312278': [FAIL_OK],
   'js1_5/extensions/regress-313630': [FAIL_OK],
-  'js1_5/extensions/regress-313763': [FAIL_OK],
   'js1_5/extensions/regress-313803': [FAIL_OK],
   'js1_5/extensions/regress-314874': [FAIL_OK],
   'js1_5/extensions/regress-322957': [FAIL_OK],
@@ -684,8 +669,6 @@
   'js1_5/extensions/regress-336409-1': [FAIL_OK],
   'js1_5/extensions/regress-336409-2': [FAIL_OK],
   'js1_5/extensions/regress-336410-2': [FAIL_OK],
-  'js1_5/extensions/regress-341956-01': [FAIL_OK],
-  'js1_5/extensions/regress-345967': [FAIL_OK],
   'js1_5/extensions/regress-346494-01': [FAIL_OK],
   'js1_5/extensions/regress-346494': [FAIL_OK],
   'js1_5/extensions/regress-347306-02': [FAIL_OK],
@@ -863,11 +846,10 @@
 
 
 ['arch ==  arm64', {
-  # BUG(v8:3152): Runs out of stack in debug mode.
-  'js1_5/extensions/regress-355497': [FAIL_OK, ['mode == debug', SKIP]],
-
   # BUG(v8:3503): Times out in debug mode.
   'js1_5/Regress/regress-280769-2': [PASS, FAIL, ['mode == debug', SKIP]],
+  # BUG(v8:3716): Flaky failure.
+  'ecma/Date/15.9.5.26-1': [PASS, FAIL],
 }],  # 'arch ==  arm64'
 
 
@@ -890,6 +872,10 @@
   'js1_5/GC/regress-203278-2': [PASS, TIMEOUT, NO_VARIANTS],
 }],  # 'arch == mipsel or arch == mips64el'
 
+['arch == mips64el and simulator_run == True', {
+  'js1_5/extensions/regress-355497': [FAIL_OK, 'Flags: --sim-stack-size=512'],
+}],
+
 ['arch == mips', {
 
   # BUG(3251229): Times out when running new crankshaft test script.
@@ -928,5 +914,8 @@
   'js1_5/extensions/regress-330569': [SKIP],
   'js1_5/extensions/regress-351448': [SKIP],
   'js1_5/extensions/regress-336410-1': [SKIP],
+
+  #BUG(3152): Avoid C stack overflow.
+  'js1_5/extensions/regress-355497': [FAIL_OK, 'Flags: --sim-stack-size=512'],
 }],  # 'arch == arm64 and simulator_run == True'
 ]
diff --git a/test/perf-test/Collections/Collections.json b/test/perf-test/Collections/Collections.json
deleted file mode 100644
index bf735c0..0000000
--- a/test/perf-test/Collections/Collections.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "path": ["."],
-  "main": "run.js",
-  "flags": ["--harmony-collections"],
-  "run_count": 5,
-  "units": "score",
-  "results_regexp": "^%s\\-Collections\\(Score\\): (.+)$",
-  "total": true,
-  "tests": [
-    {"name": "Map"},
-    {"name": "Set"},
-    {"name": "WeakMap"},
-    {"name": "WeakSet"}
-  ]
-}
diff --git a/test/perf-test/Collections/map.js b/test/perf-test/Collections/map.js
deleted file mode 100644
index b310a71..0000000
--- a/test/perf-test/Collections/map.js
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-var MapBenchmark = new BenchmarkSuite('Map', [1000], [
-  new Benchmark('Set', false, false, 0, MapSet),
-  new Benchmark('Has', false, false, 0, MapHas, MapSetup, MapTearDown),
-  new Benchmark('Get', false, false, 0, MapGet, MapSetup, MapTearDown),
-  new Benchmark('Delete', false, false, 0, MapDelete, MapSetup, MapTearDown),
-  new Benchmark('ForEach', false, false, 0, MapForEach, MapSetup, MapTearDown),
-]);
-
-
-var map;
-var N = 10;
-
-
-function MapSetup() {
-  map = new Map;
-  for (var i = 0; i < N; i++) {
-    map.set(i, i);
-  }
-}
-
-
-function MapTearDown() {
-  map = null;
-}
-
-
-function MapSet() {
-  MapSetup();
-  MapTearDown();
-}
-
-
-function MapHas() {
-  for (var i = 0; i < N; i++) {
-    if (!map.has(i)) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (map.has(i)) {
-      throw new Error();
-    }
-  }
-}
-
-
-function MapGet() {
-  for (var i = 0; i < N; i++) {
-    if (map.get(i) !== i) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (map.get(i) !== undefined) {
-      throw new Error();
-    }
-  }
-}
-
-
-function MapDelete() {
-  // This is run more than once per setup so we will end up deleting items
-  // more than once. Therefore, we do not the return value of delete.
-  for (var i = 0; i < N; i++) {
-    map.delete(i);
-  }
-}
-
-
-function MapForEach() {
-  map.forEach(function(v, k) {
-    if (v !== k) {
-      throw new Error();
-    }
-  });
-}
diff --git a/test/perf-test/Collections/set.js b/test/perf-test/Collections/set.js
deleted file mode 100644
index e6455e1..0000000
--- a/test/perf-test/Collections/set.js
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-var SetBenchmark = new BenchmarkSuite('Set', [1000], [
-  new Benchmark('Add', false, false, 0, SetAdd),
-  new Benchmark('Has', false, false, 0, SetHas, SetSetup, SetTearDown),
-  new Benchmark('Delete', false, false, 0, SetDelete, SetSetup, SetTearDown),
-  new Benchmark('ForEach', false, false, 0, SetForEach, SetSetup, SetTearDown),
-]);
-
-
-var set;
-var N = 10;
-
-
-function SetSetup() {
-  set = new Set;
-  for (var i = 0; i < N; i++) {
-    set.add(i);
-  }
-}
-
-
-function SetTearDown() {
-  map = null;
-}
-
-
-function SetAdd() {
-  SetSetup();
-  SetTearDown();
-}
-
-
-function SetHas() {
-  for (var i = 0; i < N; i++) {
-    if (!set.has(i)) {
-      throw new Error();
-    }
-  }
-  for (var i = N; i < 2 * N; i++) {
-    if (set.has(i)) {
-      throw new Error();
-    }
-  }
-}
-
-
-function SetDelete() {
-  // This is run more than once per setup so we will end up deleting items
-  // more than once. Therefore, we do not the return value of delete.
-  for (var i = 0; i < N; i++) {
-    set.delete(i);
-  }
-}
-
-
-function SetForEach() {
-  set.forEach(function(v, k) {
-    if (v !== k) {
-      throw new Error();
-    }
-  });
-}
diff --git a/test/preparser/strict-const.js b/test/preparser/strict-const.js
index 2b9230c..97b9081 100644
--- a/test/preparser/strict-const.js
+++ b/test/preparser/strict-const.js
@@ -24,6 +24,8 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Flags: --noharmony-scoping
 
 "use strict";
 const x = 42;
diff --git a/test/preparser/strict-function-statement.pyt b/test/preparser/strict-function-statement.pyt
index 08c4288..cc3d7bb 100644
--- a/test/preparser/strict-function-statement.pyt
+++ b/test/preparser/strict-function-statement.pyt
@@ -29,71 +29,81 @@
 
 # A template that performs the same strict-mode test in different
 # scopes (global scope, function scope, and nested function scope).
-def StrictTest(name, source):
-  Test(name, '"use strict";\n' + source, "strict_function")
+def StrictTest(name, source, legacy):
+  if legacy:
+    extra_flags = [
+      "--noharmony-scoping",
+      "--noharmony-classes",
+      "--noharmony-object-literals"]
+  else:
+    extra_flags = []
+  Test(name, '"use strict";\n' + source, "strict_function",
+       extra_flags)
   Test(name + '-infunc',
        'function foo() {\n "use strict";\n' + source +'\n}\n',
-       "strict_function")
+       "strict_function", 
+       extra_flags)
   Test(name + '-infunc2',
        'function foo() {\n "use strict";\n  function bar() {\n' +
        source +'\n }\n}\n',
-       "strict_function")
+       "strict_function",
+       extra_flags)
 
 # Not testing with-scope, since with is not allowed in strict mode at all.
 
 StrictTest("block", """
   { function foo() { } }
-""")
+""", True)
 
 StrictTest("try-w-catch", """
   try { function foo() { } } catch (e) { }
-""")
+""", True)
 
 StrictTest("try-w-finally", """
   try { function foo() { } } finally { }
-""")
+""", True)
 
 StrictTest("catch", """
   try { } catch (e) { function foo() { } }
-""")
+""", True)
 
 StrictTest("finally", """
   try { } finally { function foo() { } }
-""")
+""", True)
 
 StrictTest("for", """
   for (;;) { function foo() { } }
-""")
+""", True)
 
 StrictTest("while", """
   while (true) { function foo() { } }
-""")
+""", True)
 
 StrictTest("do", """
   do { function foo() { } } while (true);
-""")
+""", True)
 
 StrictTest("then", """
   if (true) { function foo() { } }
-""")
+""", True)
 
 
 StrictTest("then-w-else", """
   if (true) { function foo() { } } else { }
-""")
+""", True)
 
 
 StrictTest("else", """
   if (true) { } else { function foo() { } }
-""")
+""", True)
 
 StrictTest("switch-case", """
   switch (true) { case true: function foo() { } }
-""")
+""", False)
 
 StrictTest("labeled", """
   label: function foo() { }
-""")
+""", False)
 
 
 
diff --git a/test/preparser/testcfg.py b/test/preparser/testcfg.py
index 850c0a4..ddd311c 100644
--- a/test/preparser/testcfg.py
+++ b/test/preparser/testcfg.py
@@ -34,6 +34,10 @@
 from testrunner.objects import testcase
 
 
+FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
+INVALID_FLAGS = ["--enable-slow-asserts"]
+
+
 class PreparserTestSuite(testsuite.TestSuite):
   def __init__(self, name, root):
     super(PreparserTestSuite, self).__init__(name, root)
@@ -59,12 +63,13 @@
 
   def _ParsePythonTestTemplates(self, result, filename):
     pathname = os.path.join(self.root, filename + ".pyt")
-    def Test(name, source, expectation):
+    def Test(name, source, expectation, extra_flags=[]):
       source = source.replace("\n", " ")
       testname = os.path.join(filename, name)
       flags = ["-e", source]
       if expectation:
         flags += ["--throws"]
+      flags += extra_flags
       test = testcase.TestCase(self, testname, flags=flags)
       result.append(test)
     def Template(name, source):
@@ -104,6 +109,15 @@
     first = testcase.flags[0]
     if first != "-e":
       testcase.flags[0] = os.path.join(self.root, first)
+      source = self.GetSourceForTest(testcase)
+      result = []
+      flags_match = re.findall(FLAGS_PATTERN, source)
+      for match in flags_match:
+        result += match.strip().split()
+      result += context.mode_flags
+      result = [x for x in result if x not in INVALID_FLAGS]
+      result.append(os.path.join(self.root, testcase.path + ".js"))
+      return testcase.flags + result
     return testcase.flags
 
   def GetSourceForTest(self, testcase):
diff --git a/test/test262-es6/README b/test/test262-es6/README
index d0b3b42..86fa0dc 100644
--- a/test/test262-es6/README
+++ b/test/test262-es6/README
@@ -4,13 +4,13 @@
 
   https://github.com/tc39/test262
 
-at hash 9bd6686 (2014/08/25 revision) as 'data' in this directory.  Using later
+at hash 61113db (2014/10/23 revision) as 'data' in this directory.  Using later
 version may be possible but the tests are only known to pass (and indeed run)
 with that revision.
 
   git clone https://github.com/tc39/test262 data
   cd data
-  git checkout 9bd6686
+  git checkout 61113db
 
 If you do update to a newer revision you may have to change the test
 harness adapter code since it uses internal functionality from the
diff --git a/test/test262-es6/test262-es6.status b/test/test262-es6/test262-es6.status
index c4c94f3..8662159 100644
--- a/test/test262-es6/test262-es6.status
+++ b/test/test262-es6/test262-es6.status
@@ -29,12 +29,13 @@
 [ALWAYS, {
   ############################### BUGS ###################################
 
-  '15.5.4.9_CE': [['no_i18n', SKIP]],
-
   # BUG(v8:3455)
   '11.2.3_b': [FAIL],
   '12.2.3_b': [FAIL],
 
+  # Unicode canonicalization is not available with i18n turned off.
+  '15.5.4.9_CE': [['no_i18n', SKIP]],
+
   ###################### NEEDS INVESTIGATION #######################
 
   # Possibly same cause as S8.5_A2.1, below: floating-point tests.
@@ -49,6 +50,25 @@
 
   ###################### MISSING ES6 FEATURES #######################
 
+  # Array.fill (currently requires --harmony-arrays)
+  'S22.1.3.6_T1': [FAIL],
+
+  # Array.find (currently requires --harmony-arrays)
+  'S22.1.2.3_T1': [FAIL],
+  'S22.1.2.3_T2': [FAIL],
+  'Array.prototype.find_empty-array-undefined': [FAIL],
+  'Array.prototype.find_length-property': [FAIL],
+  'Array.prototype.find_modify-after-start': [FAIL],
+  'Array.prototype.find_non-returning-predicate': [FAIL],
+  'Array.prototype.find_predicate-arguments': [FAIL],
+  'Array.prototype.find_push-after-start': [FAIL],
+  'Array.prototype.find_remove-after-start': [FAIL],
+  'Array.prototype.find_return-found-value': [FAIL],
+  'Array.prototype.find_skip-empty': [FAIL],
+  'Array.prototype.find_this-defined': [FAIL],
+  'Array.prototype.find_this-is-object': [FAIL],
+  'Array.prototype.find_this-undefined': [FAIL],
+
   # Array.from
   'S22.1.2.1_T1': [FAIL],
   'S22.1.2.1_T2': [FAIL],
@@ -70,6 +90,11 @@
   # '11.1.5_4-4-d-3': [FAIL],
   # '11.1.5_4-4-d-4': [FAIL],
 
+  # ES6 does ToObject for Object.prototype.getOwnPropertyNames
+  '15.2.3.4-1': [FAIL],
+  '15.2.3.4-1-4': [FAIL],
+  '15.2.3.4-1-5': [FAIL],
+
   # ES6 allows block-local functions.
   'Sbp_A1_T1': [FAIL],
   'Sbp_A2_T1': [FAIL],
@@ -137,6 +162,20 @@
   # Test262 Bug: https://bugs.ecmascript.org/show_bug.cgi?id=596
   'bug_596_1': [PASS, FAIL_OK],
 
+  # Tests do not return boolean.
+  '15.2.3.14-1-1': [PASS, FAIL_OK],
+  '15.2.3.14-1-2': [PASS, FAIL_OK],
+  '15.2.3.14-1-3': [PASS, FAIL_OK],
+
+  # String.prototype.contains renamed to 'S.p.includes'
+  'String.prototype.contains_FailBadLocation' : [FAIL_OK],
+  'String.prototype.contains_FailLocation' : [FAIL_OK],
+  'String.prototype.contains_FailMissingLetter' : [FAIL_OK],
+  'String.prototype.contains_lengthProp' : [FAIL_OK],
+  'String.prototype.contains_Success' : [FAIL_OK],
+  'String.prototype.contains_SuccessNoLocation' : [FAIL_OK],
+
+
   ############################ SKIPPED TESTS #############################
 
   # These tests take a looong time to run in debug mode.
diff --git a/test/test262-es6/testcfg.py b/test/test262-es6/testcfg.py
index 59eda32..0a89410 100644
--- a/test/test262-es6/testcfg.py
+++ b/test/test262-es6/testcfg.py
@@ -37,8 +37,8 @@
 from testrunner.local import utils
 from testrunner.objects import testcase
 
-TEST_262_ARCHIVE_REVISION = "9bd6686"  # This is the 2014-08-25 revision.
-TEST_262_ARCHIVE_MD5 = "0f5928b391864890d5a397f8cdc82705"
+TEST_262_ARCHIVE_REVISION = "61113db"  # This is the 2014-10-23 revision.
+TEST_262_ARCHIVE_MD5 = "261e69b4a97a4bfc18225cf3938daf50"
 TEST_262_URL = "https://github.com/tc39/test262/tarball/%s"
 TEST_262_HARNESS_FILES = ["sta.js"]
 
@@ -147,9 +147,11 @@
       with open(archive_name, "rb") as f:
         for chunk in iter(lambda: f.read(8192), ""):
           md5.update(chunk)
+      print "MD5 hash is %s" % md5.hexdigest()
       if md5.hexdigest() != TEST_262_ARCHIVE_MD5:
         os.remove(archive_name)
-        raise Exception("Hash mismatch of test data file")
+        print "MD5 expected %s" % TEST_262_ARCHIVE_MD5
+        raise Exception("MD5 hash mismatch of test data file")
       archive = tarfile.open(archive_name, "r:gz")
       if sys.platform in ("win32", "cygwin"):
         # Magic incantation to allow longer path names on Windows.
diff --git a/test/test262/test262.status b/test/test262/test262.status
index 8666313..d32f8f3 100644
--- a/test/test262/test262.status
+++ b/test/test262/test262.status
@@ -35,6 +35,22 @@
   '11.2.3_b': [FAIL],
   '12.2.3_b': [FAIL],
 
+  ############################### ES6 ###################################
+  # ES6 allows block-local functions.
+  'Sbp_A1_T1': [PASS, FAIL_OK],
+  'Sbp_A2_T1': [PASS, FAIL_OK],
+  'Sbp_A2_T2': [PASS, FAIL_OK],
+  'Sbp_A3_T1': [PASS, FAIL_OK],
+  'Sbp_A3_T2': [PASS, FAIL_OK],
+  'Sbp_A4_T1': [PASS, FAIL_OK],
+  'Sbp_A4_T2': [PASS, FAIL_OK],
+  'Sbp_A5_T1': [PASS], # Test is broken (strict reference to unbound variable)
+  'Sbp_A5_T2': [PASS, FAIL_OK],
+
+  # Passes in ES6 since {__arr} syntax is parsed as object literal.
+  'S12.1_A4_T2': [PASS, FAIL_OK],
+  'S12.6.4_A15': [PASS, FAIL_OK],
+
   ######################## NEEDS INVESTIGATION ###########################
 
   # These test failures are specific to the intl402 suite and need investigation
@@ -87,6 +103,17 @@
   'S15.9.3.1_A5_T5': [PASS, FAIL_OK],
   'S15.9.3.1_A5_T6': [PASS, FAIL_OK],
 
+  # ObjectKeys() no longer throws TypeError when passed a primitive value which
+  # is not null or undefined (per ES6).
+  '15.2.3.14-1-1': [FAIL_OK],
+  '15.2.3.14-1-2': [FAIL_OK],
+  '15.2.3.14-1-3': [FAIL_OK],
+
+  # Object.getOwnPropertyNames(O) no longer throws when passed a primitive value.
+  '15.2.3.4-1-4': [FAIL_OK],
+  '15.2.3.4-1-5': [FAIL_OK],
+  '15.2.3.4-1': [FAIL_OK],
+
   ############################ SKIPPED TESTS #############################
 
   # These tests take a looong time to run in debug mode.
diff --git a/test/unittests/DEPS b/test/unittests/DEPS
new file mode 100644
index 0000000..4df37f8
--- /dev/null
+++ b/test/unittests/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+src",
+  "+testing"
+]
diff --git a/test/unittests/base/bits-unittest.cc b/test/unittests/base/bits-unittest.cc
new file mode 100644
index 0000000..9caba84
--- /dev/null
+++ b/test/unittests/base/bits-unittest.cc
@@ -0,0 +1,281 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "src/base/bits.h"
+#include "src/base/macros.h"
+#include "testing/gtest-support.h"
+
+#ifdef DEBUG
+#define DISABLE_IN_RELEASE(Name) Name
+#else
+#define DISABLE_IN_RELEASE(Name) DISABLED_##Name
+#endif
+
+namespace v8 {
+namespace base {
+namespace bits {
+
+TEST(Bits, CountPopulation32) {
+  EXPECT_EQ(0u, CountPopulation32(0));
+  EXPECT_EQ(1u, CountPopulation32(1));
+  EXPECT_EQ(8u, CountPopulation32(0x11111111));
+  EXPECT_EQ(16u, CountPopulation32(0xf0f0f0f0));
+  EXPECT_EQ(24u, CountPopulation32(0xfff0f0ff));
+  EXPECT_EQ(32u, CountPopulation32(0xffffffff));
+}
+
+
+TEST(Bits, CountPopulation64) {
+  EXPECT_EQ(0u, CountPopulation64(0));
+  EXPECT_EQ(1u, CountPopulation64(1));
+  EXPECT_EQ(2u, CountPopulation64(0x8000000000000001));
+  EXPECT_EQ(8u, CountPopulation64(0x11111111));
+  EXPECT_EQ(16u, CountPopulation64(0xf0f0f0f0));
+  EXPECT_EQ(24u, CountPopulation64(0xfff0f0ff));
+  EXPECT_EQ(32u, CountPopulation64(0xffffffff));
+  EXPECT_EQ(16u, CountPopulation64(0x1111111111111111));
+  EXPECT_EQ(32u, CountPopulation64(0xf0f0f0f0f0f0f0f0));
+  EXPECT_EQ(48u, CountPopulation64(0xfff0f0fffff0f0ff));
+  EXPECT_EQ(64u, CountPopulation64(0xffffffffffffffff));
+}
+
+
+TEST(Bits, CountLeadingZeros32) {
+  EXPECT_EQ(32u, CountLeadingZeros32(0));
+  EXPECT_EQ(31u, CountLeadingZeros32(1));
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(31u - shift, CountLeadingZeros32(1u << shift));
+  }
+  EXPECT_EQ(4u, CountLeadingZeros32(0x0f0f0f0f));
+}
+
+
+TEST(Bits, CountLeadingZeros64) {
+  EXPECT_EQ(64u, CountLeadingZeros64(0));
+  EXPECT_EQ(63u, CountLeadingZeros64(1));
+  TRACED_FORRANGE(uint32_t, shift, 0, 63) {
+    EXPECT_EQ(63u - shift, CountLeadingZeros64(V8_UINT64_C(1) << shift));
+  }
+  EXPECT_EQ(36u, CountLeadingZeros64(0x0f0f0f0f));
+  EXPECT_EQ(4u, CountLeadingZeros64(0x0f0f0f0f00000000));
+}
+
+
+TEST(Bits, CountTrailingZeros32) {
+  EXPECT_EQ(32u, CountTrailingZeros32(0));
+  EXPECT_EQ(31u, CountTrailingZeros32(0x80000000));
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(shift, CountTrailingZeros32(1u << shift));
+  }
+  EXPECT_EQ(4u, CountTrailingZeros32(0xf0f0f0f0));
+}
+
+
+TEST(Bits, CountTrailingZeros64) {
+  EXPECT_EQ(64u, CountTrailingZeros64(0));
+  EXPECT_EQ(63u, CountTrailingZeros64(0x8000000000000000));
+  TRACED_FORRANGE(uint32_t, shift, 0, 63) {
+    EXPECT_EQ(shift, CountTrailingZeros64(V8_UINT64_C(1) << shift));
+  }
+  EXPECT_EQ(4u, CountTrailingZeros64(0xf0f0f0f0));
+  EXPECT_EQ(36u, CountTrailingZeros64(0xf0f0f0f000000000));
+}
+
+
+TEST(Bits, IsPowerOfTwo32) {
+  EXPECT_FALSE(IsPowerOfTwo32(0U));
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_TRUE(IsPowerOfTwo32(1U << shift));
+    EXPECT_FALSE(IsPowerOfTwo32((1U << shift) + 5U));
+    EXPECT_FALSE(IsPowerOfTwo32(~(1U << shift)));
+  }
+  TRACED_FORRANGE(uint32_t, shift, 2, 31) {
+    EXPECT_FALSE(IsPowerOfTwo32((1U << shift) - 1U));
+  }
+  EXPECT_FALSE(IsPowerOfTwo32(0xffffffff));
+}
+
+
+TEST(Bits, IsPowerOfTwo64) {
+  EXPECT_FALSE(IsPowerOfTwo64(0U));
+  TRACED_FORRANGE(uint32_t, shift, 0, 63) {
+    EXPECT_TRUE(IsPowerOfTwo64(V8_UINT64_C(1) << shift));
+    EXPECT_FALSE(IsPowerOfTwo64((V8_UINT64_C(1) << shift) + 5U));
+    EXPECT_FALSE(IsPowerOfTwo64(~(V8_UINT64_C(1) << shift)));
+  }
+  TRACED_FORRANGE(uint32_t, shift, 2, 63) {
+    EXPECT_FALSE(IsPowerOfTwo64((V8_UINT64_C(1) << shift) - 1U));
+  }
+  EXPECT_FALSE(IsPowerOfTwo64(V8_UINT64_C(0xffffffffffffffff)));
+}
+
+
+TEST(Bits, RoundUpToPowerOfTwo32) {
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(1u << shift, RoundUpToPowerOfTwo32(1u << shift));
+  }
+  EXPECT_EQ(0u, RoundUpToPowerOfTwo32(0));
+  EXPECT_EQ(4u, RoundUpToPowerOfTwo32(3));
+  EXPECT_EQ(0x80000000u, RoundUpToPowerOfTwo32(0x7fffffffu));
+}
+
+
+TEST(BitsDeathTest, DISABLE_IN_RELEASE(RoundUpToPowerOfTwo32)) {
+  ASSERT_DEATH_IF_SUPPORTED({ RoundUpToPowerOfTwo32(0x80000001u); },
+                            "0x80000000");
+}
+
+
+TEST(Bits, RoundDownToPowerOfTwo32) {
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(1u << shift, RoundDownToPowerOfTwo32(1u << shift));
+  }
+  EXPECT_EQ(0u, RoundDownToPowerOfTwo32(0));
+  EXPECT_EQ(4u, RoundDownToPowerOfTwo32(5));
+  EXPECT_EQ(0x80000000u, RoundDownToPowerOfTwo32(0x80000001u));
+}
+
+
+TEST(Bits, RotateRight32) {
+  TRACED_FORRANGE(uint32_t, shift, 0, 31) {
+    EXPECT_EQ(0u, RotateRight32(0u, shift));
+  }
+  EXPECT_EQ(1u, RotateRight32(1, 0));
+  EXPECT_EQ(1u, RotateRight32(2, 1));
+  EXPECT_EQ(0x80000000u, RotateRight32(1, 1));
+}
+
+
+TEST(Bits, RotateRight64) {
+  TRACED_FORRANGE(uint64_t, shift, 0, 63) {
+    EXPECT_EQ(0u, RotateRight64(0u, shift));
+  }
+  EXPECT_EQ(1u, RotateRight64(1, 0));
+  EXPECT_EQ(1u, RotateRight64(2, 1));
+  EXPECT_EQ(V8_UINT64_C(0x8000000000000000), RotateRight64(1, 1));
+}
+
+
+TEST(Bits, SignedAddOverflow32) {
+  int32_t val = 0;
+  EXPECT_FALSE(SignedAddOverflow32(0, 0, &val));
+  EXPECT_EQ(0, val);
+  EXPECT_TRUE(
+      SignedAddOverflow32(std::numeric_limits<int32_t>::max(), 1, &val));
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(), val);
+  EXPECT_TRUE(
+      SignedAddOverflow32(std::numeric_limits<int32_t>::min(), -1, &val));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), val);
+  EXPECT_TRUE(SignedAddOverflow32(std::numeric_limits<int32_t>::max(),
+                                  std::numeric_limits<int32_t>::max(), &val));
+  EXPECT_EQ(-2, val);
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_FALSE(SignedAddOverflow32(i, j, &val));
+      EXPECT_EQ(i + j, val);
+    }
+  }
+}
+
+
+TEST(Bits, SignedSubOverflow32) {
+  int32_t val = 0;
+  EXPECT_FALSE(SignedSubOverflow32(0, 0, &val));
+  EXPECT_EQ(0, val);
+  EXPECT_TRUE(
+      SignedSubOverflow32(std::numeric_limits<int32_t>::min(), 1, &val));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), val);
+  EXPECT_TRUE(
+      SignedSubOverflow32(std::numeric_limits<int32_t>::max(), -1, &val));
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(), val);
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_FALSE(SignedSubOverflow32(i, j, &val));
+      EXPECT_EQ(i - j, val);
+    }
+  }
+}
+
+
+TEST(Bits, SignedMulHigh32) {
+  EXPECT_EQ(0, SignedMulHigh32(0, 0));
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    TRACED_FORRANGE(int32_t, j, 1, i) { EXPECT_EQ(0, SignedMulHigh32(i, j)); }
+  }
+  EXPECT_EQ(-1073741824, SignedMulHigh32(std::numeric_limits<int32_t>::max(),
+                                         std::numeric_limits<int32_t>::min()));
+  EXPECT_EQ(-1073741824, SignedMulHigh32(std::numeric_limits<int32_t>::min(),
+                                         std::numeric_limits<int32_t>::max()));
+  EXPECT_EQ(1, SignedMulHigh32(1024 * 1024 * 1024, 4));
+  EXPECT_EQ(2, SignedMulHigh32(8 * 1024, 1024 * 1024));
+}
+
+
+TEST(Bits, SignedMulHighAndAdd32) {
+  TRACED_FORRANGE(int32_t, i, 1, 50) {
+    EXPECT_EQ(i, SignedMulHighAndAdd32(0, 0, i));
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_EQ(i, SignedMulHighAndAdd32(j, j, i));
+    }
+    EXPECT_EQ(i + 1, SignedMulHighAndAdd32(1024 * 1024 * 1024, 4, i));
+  }
+}
+
+
+TEST(Bits, SignedDiv32) {
+  EXPECT_EQ(std::numeric_limits<int32_t>::min(),
+            SignedDiv32(std::numeric_limits<int32_t>::min(), -1));
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(),
+            SignedDiv32(std::numeric_limits<int32_t>::max(), 1));
+  TRACED_FORRANGE(int32_t, i, 0, 50) {
+    EXPECT_EQ(0, SignedDiv32(i, 0));
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_EQ(1, SignedDiv32(j, j));
+      EXPECT_EQ(i / j, SignedDiv32(i, j));
+      EXPECT_EQ(-i / j, SignedDiv32(i, -j));
+    }
+  }
+}
+
+
+TEST(Bits, SignedMod32) {
+  EXPECT_EQ(0, SignedMod32(std::numeric_limits<int32_t>::min(), -1));
+  EXPECT_EQ(0, SignedMod32(std::numeric_limits<int32_t>::max(), 1));
+  TRACED_FORRANGE(int32_t, i, 0, 50) {
+    EXPECT_EQ(0, SignedMod32(i, 0));
+    TRACED_FORRANGE(int32_t, j, 1, i) {
+      EXPECT_EQ(0, SignedMod32(j, j));
+      EXPECT_EQ(i % j, SignedMod32(i, j));
+      EXPECT_EQ(i % j, SignedMod32(i, -j));
+    }
+  }
+}
+
+
+TEST(Bits, UnsignedDiv32) {
+  TRACED_FORRANGE(uint32_t, i, 0, 50) {
+    EXPECT_EQ(0u, UnsignedDiv32(i, 0));
+    TRACED_FORRANGE(uint32_t, j, i + 1, 100) {
+      EXPECT_EQ(1u, UnsignedDiv32(j, j));
+      EXPECT_EQ(i / j, UnsignedDiv32(i, j));
+    }
+  }
+}
+
+
+TEST(Bits, UnsignedMod32) {
+  TRACED_FORRANGE(uint32_t, i, 0, 50) {
+    EXPECT_EQ(0u, UnsignedMod32(i, 0));
+    TRACED_FORRANGE(uint32_t, j, i + 1, 100) {
+      EXPECT_EQ(0u, UnsignedMod32(j, j));
+      EXPECT_EQ(i % j, UnsignedMod32(i, j));
+    }
+  }
+}
+
+}  // namespace bits
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/cpu-unittest.cc b/test/unittests/base/cpu-unittest.cc
new file mode 100644
index 0000000..5c58f86
--- /dev/null
+++ b/test/unittests/base/cpu-unittest.cc
@@ -0,0 +1,49 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/cpu.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+TEST(CPUTest, FeatureImplications) {
+  CPU cpu;
+
+  // ia32 and x64 features
+  EXPECT_TRUE(!cpu.has_sse() || cpu.has_mmx());
+  EXPECT_TRUE(!cpu.has_sse2() || cpu.has_sse());
+  EXPECT_TRUE(!cpu.has_sse3() || cpu.has_sse2());
+  EXPECT_TRUE(!cpu.has_ssse3() || cpu.has_sse3());
+  EXPECT_TRUE(!cpu.has_sse41() || cpu.has_sse3());
+  EXPECT_TRUE(!cpu.has_sse42() || cpu.has_sse41());
+
+  // arm features
+  EXPECT_TRUE(!cpu.has_vfp3_d32() || cpu.has_vfp3());
+}
+
+
+TEST(CPUTest, RequiredFeatures) {
+  CPU cpu;
+
+#if V8_HOST_ARCH_ARM
+  EXPECT_TRUE(cpu.has_fpu());
+#endif
+
+#if V8_HOST_ARCH_IA32
+  EXPECT_TRUE(cpu.has_fpu());
+  EXPECT_TRUE(cpu.has_sahf());
+#endif
+
+#if V8_HOST_ARCH_X64
+  EXPECT_TRUE(cpu.has_fpu());
+  EXPECT_TRUE(cpu.has_cmov());
+  EXPECT_TRUE(cpu.has_mmx());
+  EXPECT_TRUE(cpu.has_sse());
+  EXPECT_TRUE(cpu.has_sse2());
+#endif
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/division-by-constant-unittest.cc b/test/unittests/base/division-by-constant-unittest.cc
new file mode 100644
index 0000000..58816db
--- /dev/null
+++ b/test/unittests/base/division-by-constant-unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Check all examples from table 10-1 of "Hacker's Delight".
+
+#include "src/base/division-by-constant.h"
+
+#include <stdint.h>
+
+#include <ostream>  // NOLINT
+
+#include "testing/gtest-support.h"
+
+namespace v8 {
+namespace base {
+
+template <class T>
+std::ostream& operator<<(std::ostream& os,
+                         const MagicNumbersForDivision<T>& mag) {
+  return os << "{ multiplier: " << mag.multiplier << ", shift: " << mag.shift
+            << ", add: " << mag.add << " }";
+}
+
+
+// Some abbreviations...
+
+typedef MagicNumbersForDivision<uint32_t> M32;
+typedef MagicNumbersForDivision<uint64_t> M64;
+
+
+static M32 s32(int32_t d) {
+  return SignedDivisionByConstant<uint32_t>(static_cast<uint32_t>(d));
+}
+
+
+static M64 s64(int64_t d) {
+  return SignedDivisionByConstant<uint64_t>(static_cast<uint64_t>(d));
+}
+
+
+static M32 u32(uint32_t d) { return UnsignedDivisionByConstant<uint32_t>(d); }
+static M64 u64(uint64_t d) { return UnsignedDivisionByConstant<uint64_t>(d); }
+
+
+TEST(DivisionByConstant, Signed32) {
+  EXPECT_EQ(M32(0x99999999U, 1, false), s32(-5));
+  EXPECT_EQ(M32(0x55555555U, 1, false), s32(-3));
+  int32_t d = -1;
+  for (unsigned k = 1; k <= 32 - 1; ++k) {
+    d *= 2;
+    EXPECT_EQ(M32(0x7FFFFFFFU, k - 1, false), s32(d));
+  }
+  for (unsigned k = 1; k <= 32 - 2; ++k) {
+    EXPECT_EQ(M32(0x80000001U, k - 1, false), s32(1 << k));
+  }
+  EXPECT_EQ(M32(0x55555556U, 0, false), s32(3));
+  EXPECT_EQ(M32(0x66666667U, 1, false), s32(5));
+  EXPECT_EQ(M32(0x2AAAAAABU, 0, false), s32(6));
+  EXPECT_EQ(M32(0x92492493U, 2, false), s32(7));
+  EXPECT_EQ(M32(0x38E38E39U, 1, false), s32(9));
+  EXPECT_EQ(M32(0x66666667U, 2, false), s32(10));
+  EXPECT_EQ(M32(0x2E8BA2E9U, 1, false), s32(11));
+  EXPECT_EQ(M32(0x2AAAAAABU, 1, false), s32(12));
+  EXPECT_EQ(M32(0x51EB851FU, 3, false), s32(25));
+  EXPECT_EQ(M32(0x10624DD3U, 3, false), s32(125));
+  EXPECT_EQ(M32(0x68DB8BADU, 8, false), s32(625));
+}
+
+
+TEST(DivisionByConstant, Unsigned32) {
+  EXPECT_EQ(M32(0x00000000U, 0, true), u32(1));
+  for (unsigned k = 1; k <= 30; ++k) {
+    EXPECT_EQ(M32(1U << (32 - k), 0, false), u32(1U << k));
+  }
+  EXPECT_EQ(M32(0xAAAAAAABU, 1, false), u32(3));
+  EXPECT_EQ(M32(0xCCCCCCCDU, 2, false), u32(5));
+  EXPECT_EQ(M32(0xAAAAAAABU, 2, false), u32(6));
+  EXPECT_EQ(M32(0x24924925U, 3, true), u32(7));
+  EXPECT_EQ(M32(0x38E38E39U, 1, false), u32(9));
+  EXPECT_EQ(M32(0xCCCCCCCDU, 3, false), u32(10));
+  EXPECT_EQ(M32(0xBA2E8BA3U, 3, false), u32(11));
+  EXPECT_EQ(M32(0xAAAAAAABU, 3, false), u32(12));
+  EXPECT_EQ(M32(0x51EB851FU, 3, false), u32(25));
+  EXPECT_EQ(M32(0x10624DD3U, 3, false), u32(125));
+  EXPECT_EQ(M32(0xD1B71759U, 9, false), u32(625));
+}
+
+
+TEST(DivisionByConstant, Signed64) {
+  EXPECT_EQ(M64(0x9999999999999999ULL, 1, false), s64(-5));
+  EXPECT_EQ(M64(0x5555555555555555ULL, 1, false), s64(-3));
+  int64_t d = -1;
+  for (unsigned k = 1; k <= 64 - 1; ++k) {
+    d *= 2;
+    EXPECT_EQ(M64(0x7FFFFFFFFFFFFFFFULL, k - 1, false), s64(d));
+  }
+  for (unsigned k = 1; k <= 64 - 2; ++k) {
+    EXPECT_EQ(M64(0x8000000000000001ULL, k - 1, false), s64(1LL << k));
+  }
+  EXPECT_EQ(M64(0x5555555555555556ULL, 0, false), s64(3));
+  EXPECT_EQ(M64(0x6666666666666667ULL, 1, false), s64(5));
+  EXPECT_EQ(M64(0x2AAAAAAAAAAAAAABULL, 0, false), s64(6));
+  EXPECT_EQ(M64(0x4924924924924925ULL, 1, false), s64(7));
+  EXPECT_EQ(M64(0x1C71C71C71C71C72ULL, 0, false), s64(9));
+  EXPECT_EQ(M64(0x6666666666666667ULL, 2, false), s64(10));
+  EXPECT_EQ(M64(0x2E8BA2E8BA2E8BA3ULL, 1, false), s64(11));
+  EXPECT_EQ(M64(0x2AAAAAAAAAAAAAABULL, 1, false), s64(12));
+  EXPECT_EQ(M64(0xA3D70A3D70A3D70BULL, 4, false), s64(25));
+  EXPECT_EQ(M64(0x20C49BA5E353F7CFULL, 4, false), s64(125));
+  EXPECT_EQ(M64(0x346DC5D63886594BULL, 7, false), s64(625));
+}
+
+
+TEST(DivisionByConstant, Unsigned64) {
+  EXPECT_EQ(M64(0x0000000000000000ULL, 0, true), u64(1));
+  for (unsigned k = 1; k <= 64 - 2; ++k) {
+    EXPECT_EQ(M64(1ULL << (64 - k), 0, false), u64(1ULL << k));
+  }
+  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 1, false), u64(3));
+  EXPECT_EQ(M64(0xCCCCCCCCCCCCCCCDULL, 2, false), u64(5));
+  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 2, false), u64(6));
+  EXPECT_EQ(M64(0x2492492492492493ULL, 3, true), u64(7));
+  EXPECT_EQ(M64(0xE38E38E38E38E38FULL, 3, false), u64(9));
+  EXPECT_EQ(M64(0xCCCCCCCCCCCCCCCDULL, 3, false), u64(10));
+  EXPECT_EQ(M64(0x2E8BA2E8BA2E8BA3ULL, 1, false), u64(11));
+  EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 3, false), u64(12));
+  EXPECT_EQ(M64(0x47AE147AE147AE15ULL, 5, true), u64(25));
+  EXPECT_EQ(M64(0x0624DD2F1A9FBE77ULL, 7, true), u64(125));
+  EXPECT_EQ(M64(0x346DC5D63886594BULL, 7, false), u64(625));
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/flags-unittest.cc b/test/unittests/base/flags-unittest.cc
new file mode 100644
index 0000000..6f19399
--- /dev/null
+++ b/test/unittests/base/flags-unittest.cc
@@ -0,0 +1,104 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+#include "src/base/flags.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+namespace {
+
+enum Flag1 {
+  kFlag1None = 0,
+  kFlag1First = 1u << 1,
+  kFlag1Second = 1u << 2,
+  kFlag1All = kFlag1None | kFlag1First | kFlag1Second
+};
+typedef Flags<Flag1> Flags1;
+
+
+DEFINE_OPERATORS_FOR_FLAGS(Flags1)
+
+
+Flags1 bar(Flags1 flags1) { return flags1; }
+
+}  // namespace
+
+
+TEST(FlagsTest, BasicOperations) {
+  Flags1 a;
+  EXPECT_EQ(kFlag1None, static_cast<int>(a));
+  a |= kFlag1First;
+  EXPECT_EQ(kFlag1First, static_cast<int>(a));
+  a = a | kFlag1Second;
+  EXPECT_EQ(kFlag1All, static_cast<int>(a));
+  a &= kFlag1Second;
+  EXPECT_EQ(kFlag1Second, static_cast<int>(a));
+  a = kFlag1None & a;
+  EXPECT_EQ(kFlag1None, static_cast<int>(a));
+  a ^= (kFlag1All | kFlag1None);
+  EXPECT_EQ(kFlag1All, static_cast<int>(a));
+  Flags1 b = ~a;
+  EXPECT_EQ(kFlag1All, static_cast<int>(a));
+  EXPECT_EQ(~static_cast<int>(a), static_cast<int>(b));
+  Flags1 c = a;
+  EXPECT_EQ(a, c);
+  EXPECT_NE(a, b);
+  EXPECT_EQ(a, bar(a));
+  EXPECT_EQ(a, bar(kFlag1All));
+}
+
+
+namespace {
+namespace foo {
+
+enum Option {
+  kNoOptions = 0,
+  kOption1 = 1,
+  kOption2 = 2,
+  kAllOptions = kNoOptions | kOption1 | kOption2
+};
+typedef Flags<Option> Options;
+
+}  // namespace foo
+
+
+DEFINE_OPERATORS_FOR_FLAGS(foo::Options)
+
+}  // namespace
+
+
+TEST(FlagsTest, NamespaceScope) {
+  foo::Options options;
+  options ^= foo::kNoOptions;
+  options |= foo::kOption1 | foo::kOption2;
+  EXPECT_EQ(foo::kAllOptions, static_cast<int>(options));
+}
+
+
+namespace {
+
+struct Foo {
+  enum Enum { kEnum1 = 1, kEnum2 = 2 };
+  typedef Flags<Enum, uint32_t> Enums;
+};
+
+
+DEFINE_OPERATORS_FOR_FLAGS(Foo::Enums)
+
+}  // namespace
+
+
+TEST(FlagsTest, ClassScope) {
+  Foo::Enums enums;
+  enums |= Foo::kEnum1;
+  enums |= Foo::kEnum2;
+  EXPECT_TRUE(enums & Foo::kEnum1);
+  EXPECT_TRUE(enums & Foo::kEnum2);
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/functional-unittest.cc b/test/unittests/base/functional-unittest.cc
new file mode 100644
index 0000000..97a27a4
--- /dev/null
+++ b/test/unittests/base/functional-unittest.cc
@@ -0,0 +1,196 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/functional.h"
+
+#include <limits>
+#include <set>
+
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace base {
+
+TEST(FunctionalTest, HashBool) {
+  hash<bool> h, h1, h2;
+  EXPECT_EQ(h1(true), h2(true));
+  EXPECT_EQ(h1(false), h2(false));
+  EXPECT_NE(h(true), h(false));
+}
+
+
+TEST(FunctionalTest, HashFloatZero) {
+  hash<float> h;
+  EXPECT_EQ(h(0.0f), h(-0.0f));
+}
+
+
+TEST(FunctionalTest, HashDoubleZero) {
+  hash<double> h;
+  EXPECT_EQ(h(0.0), h(-0.0));
+}
+
+
+template <typename T>
+class FunctionalTest : public TestWithRandomNumberGenerator {};
+
+typedef ::testing::Types<signed char, unsigned char,
+                         short,                    // NOLINT(runtime/int)
+                         unsigned short,           // NOLINT(runtime/int)
+                         int, unsigned int, long,  // NOLINT(runtime/int)
+                         unsigned long,            // NOLINT(runtime/int)
+                         long long,                // NOLINT(runtime/int)
+                         unsigned long long,       // NOLINT(runtime/int)
+                         int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
+                         int64_t, uint64_t, float, double> FunctionalTypes;
+
+TYPED_TEST_CASE(FunctionalTest, FunctionalTypes);
+
+
+TYPED_TEST(FunctionalTest, EqualToImpliesSameHashCode) {
+  hash<TypeParam> h;
+  std::equal_to<TypeParam> e;
+  TypeParam values[32];
+  this->rng()->NextBytes(values, sizeof(values));
+  TRACED_FOREACH(TypeParam, v1, values) {
+    TRACED_FOREACH(TypeParam, v2, values) {
+      if (e(v1, v2)) EXPECT_EQ(h(v1), h(v2));
+    }
+  }
+}
+
+
+TYPED_TEST(FunctionalTest, HashEqualsHashValue) {
+  for (int i = 0; i < 128; ++i) {
+    TypeParam v;
+    this->rng()->NextBytes(&v, sizeof(v));
+    hash<TypeParam> h;
+    EXPECT_EQ(h(v), hash_value(v));
+  }
+}
+
+
+TYPED_TEST(FunctionalTest, HashIsStateless) {
+  hash<TypeParam> h1, h2;
+  for (int i = 0; i < 128; ++i) {
+    TypeParam v;
+    this->rng()->NextBytes(&v, sizeof(v));
+    EXPECT_EQ(h1(v), h2(v));
+  }
+}
+
+
+TYPED_TEST(FunctionalTest, HashIsOkish) {
+  std::set<TypeParam> vs;
+  for (size_t i = 0; i < 128; ++i) {
+    TypeParam v;
+    this->rng()->NextBytes(&v, sizeof(v));
+    vs.insert(v);
+  }
+  std::set<size_t> hs;
+  for (const auto& v : vs) {
+    hash<TypeParam> h;
+    hs.insert(h(v));
+  }
+  EXPECT_LE(vs.size() / 4u, hs.size());
+}
+
+
+TYPED_TEST(FunctionalTest, HashValueArrayUsesHashRange) {
+  TypeParam values[128];
+  this->rng()->NextBytes(&values, sizeof(values));
+  EXPECT_EQ(hash_range(values, values + arraysize(values)), hash_value(values));
+}
+
+
+TYPED_TEST(FunctionalTest, BitEqualTo) {
+  bit_equal_to<TypeParam> pred;
+  for (size_t i = 0; i < 128; ++i) {
+    TypeParam v1, v2;
+    this->rng()->NextBytes(&v1, sizeof(v1));
+    this->rng()->NextBytes(&v2, sizeof(v2));
+    EXPECT_PRED2(pred, v1, v1);
+    EXPECT_PRED2(pred, v2, v2);
+    EXPECT_EQ(memcmp(&v1, &v2, sizeof(TypeParam)) == 0, pred(v1, v2));
+  }
+}
+
+
+TYPED_TEST(FunctionalTest, BitEqualToImpliesSameBitHash) {
+  bit_hash<TypeParam> h;
+  bit_equal_to<TypeParam> e;
+  TypeParam values[32];
+  this->rng()->NextBytes(&values, sizeof(values));
+  TRACED_FOREACH(TypeParam, v1, values) {
+    TRACED_FOREACH(TypeParam, v2, values) {
+      if (e(v1, v2)) EXPECT_EQ(h(v1), h(v2));
+    }
+  }
+}
+
+
+namespace {
+
+struct Foo {
+  int x;
+  double y;
+};
+
+
+size_t hash_value(Foo const& v) { return hash_combine(v.x, v.y); }
+
+}  // namespace
+
+
+TEST(FunctionalTest, HashUsesArgumentDependentLookup) {
+  const int kIntValues[] = {std::numeric_limits<int>::min(), -1, 0, 1, 42,
+                            std::numeric_limits<int>::max()};
+  const double kDoubleValues[] = {
+      std::numeric_limits<double>::min(), -1, -0, 0, 1,
+      std::numeric_limits<double>::max()};
+  TRACED_FOREACH(int, x, kIntValues) {
+    TRACED_FOREACH(double, y, kDoubleValues) {
+      hash<Foo> h;
+      Foo foo = {x, y};
+      EXPECT_EQ(hash_combine(x, y), h(foo));
+    }
+  }
+}
+
+
+TEST(FunctionalTest, BitEqualToFloat) {
+  bit_equal_to<float> pred;
+  EXPECT_FALSE(pred(0.0f, -0.0f));
+  EXPECT_FALSE(pred(-0.0f, 0.0f));
+  float const qNaN = std::numeric_limits<float>::quiet_NaN();
+  float const sNaN = std::numeric_limits<float>::signaling_NaN();
+  EXPECT_PRED2(pred, qNaN, qNaN);
+  EXPECT_PRED2(pred, sNaN, sNaN);
+}
+
+
+TEST(FunctionalTest, BitHashFloatDifferentForZeroAndMinusZero) {
+  bit_hash<float> h;
+  EXPECT_NE(h(0.0f), h(-0.0f));
+}
+
+
+TEST(FunctionalTest, BitEqualToDouble) {
+  bit_equal_to<double> pred;
+  EXPECT_FALSE(pred(0.0, -0.0));
+  EXPECT_FALSE(pred(-0.0, 0.0));
+  double const qNaN = std::numeric_limits<double>::quiet_NaN();
+  double const sNaN = std::numeric_limits<double>::signaling_NaN();
+  EXPECT_PRED2(pred, qNaN, qNaN);
+  EXPECT_PRED2(pred, sNaN, sNaN);
+}
+
+
+TEST(FunctionalTest, BitHashDoubleDifferentForZeroAndMinusZero) {
+  bit_hash<double> h;
+  EXPECT_NE(h(0.0), h(-0.0));
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/iterator-unittest.cc b/test/unittests/base/iterator-unittest.cc
new file mode 100644
index 0000000..8da26ce
--- /dev/null
+++ b/test/unittests/base/iterator-unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/iterator.h"
+
+#include <deque>
+
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace base {
+
+TEST(IteratorTest, IteratorRangeEmpty) {
+  base::iterator_range<char*> r;
+  EXPECT_EQ(r.begin(), r.end());
+  EXPECT_EQ(r.end(), r.cend());
+  EXPECT_EQ(r.begin(), r.cbegin());
+  EXPECT_TRUE(r.empty());
+  EXPECT_EQ(0, r.size());
+}
+
+
+TEST(IteratorTest, IteratorRangeArray) {
+  int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+  base::iterator_range<int*> r1(&array[0], &array[10]);
+  for (auto i : r1) {
+    EXPECT_EQ(array[i], i);
+  }
+  EXPECT_EQ(10, r1.size());
+  EXPECT_FALSE(r1.empty());
+  for (size_t i = 0; i < arraysize(array); ++i) {
+    EXPECT_EQ(r1[i], array[i]);
+  }
+  base::iterator_range<int*> r2(&array[0], &array[0]);
+  EXPECT_EQ(0, r2.size());
+  EXPECT_TRUE(r2.empty());
+  for (auto i : array) {
+    EXPECT_EQ(r2.end(), std::find(r2.begin(), r2.end(), i));
+  }
+}
+
+
+TEST(IteratorTest, IteratorRangeDeque) {
+  typedef std::deque<unsigned> C;
+  C c;
+  c.push_back(1);
+  c.push_back(2);
+  c.push_back(2);
+  base::iterator_range<typename C::iterator> r(c.begin(), c.end());
+  EXPECT_EQ(3, r.size());
+  EXPECT_FALSE(r.empty());
+  EXPECT_TRUE(c.begin() == r.begin());
+  EXPECT_TRUE(c.end() == r.end());
+  EXPECT_EQ(0, std::count(r.begin(), r.end(), 0));
+  EXPECT_EQ(1, std::count(r.begin(), r.end(), 1));
+  EXPECT_EQ(2, std::count(r.begin(), r.end(), 2));
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/platform/condition-variable-unittest.cc b/test/unittests/base/platform/condition-variable-unittest.cc
new file mode 100644
index 0000000..fe0ad2a
--- /dev/null
+++ b/test/unittests/base/platform/condition-variable-unittest.cc
@@ -0,0 +1,301 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/platform/condition-variable.h"
+
+#include "src/base/platform/platform.h"
+#include "src/base/platform/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+TEST(ConditionVariable, WaitForAfterNofityOnSameThread) {
+  for (int n = 0; n < 10; ++n) {
+    Mutex mutex;
+    ConditionVariable cv;
+
+    LockGuard<Mutex> lock_guard(&mutex);
+
+    cv.NotifyOne();
+    EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
+
+    cv.NotifyAll();
+    EXPECT_FALSE(cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n)));
+  }
+}
+
+
+namespace {
+
+class ThreadWithMutexAndConditionVariable FINAL : public Thread {
+ public:
+  ThreadWithMutexAndConditionVariable()
+      : Thread(Options("ThreadWithMutexAndConditionVariable")),
+        running_(false),
+        finished_(false) {}
+  virtual ~ThreadWithMutexAndConditionVariable() {}
+
+  virtual void Run() OVERRIDE {
+    LockGuard<Mutex> lock_guard(&mutex_);
+    running_ = true;
+    cv_.NotifyOne();
+    while (running_) {
+      cv_.Wait(&mutex_);
+    }
+    finished_ = true;
+    cv_.NotifyAll();
+  }
+
+  bool running_;
+  bool finished_;
+  ConditionVariable cv_;
+  Mutex mutex_;
+};
+
+}  // namespace
+
+
+TEST(ConditionVariable, MultipleThreadsWithSeparateConditionVariables) {
+  static const int kThreadCount = 128;
+  ThreadWithMutexAndConditionVariable threads[kThreadCount];
+
+  for (int n = 0; n < kThreadCount; ++n) {
+    LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+    EXPECT_FALSE(threads[n].running_);
+    EXPECT_FALSE(threads[n].finished_);
+    threads[n].Start();
+    // Wait for nth thread to start.
+    while (!threads[n].running_) {
+      threads[n].cv_.Wait(&threads[n].mutex_);
+    }
+  }
+
+  for (int n = kThreadCount - 1; n >= 0; --n) {
+    LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+    EXPECT_TRUE(threads[n].running_);
+    EXPECT_FALSE(threads[n].finished_);
+  }
+
+  for (int n = 0; n < kThreadCount; ++n) {
+    LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+    EXPECT_TRUE(threads[n].running_);
+    EXPECT_FALSE(threads[n].finished_);
+    // Tell the nth thread to quit.
+    threads[n].running_ = false;
+    threads[n].cv_.NotifyOne();
+  }
+
+  for (int n = kThreadCount - 1; n >= 0; --n) {
+    // Wait for nth thread to quit.
+    LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+    while (!threads[n].finished_) {
+      threads[n].cv_.Wait(&threads[n].mutex_);
+    }
+    EXPECT_FALSE(threads[n].running_);
+    EXPECT_TRUE(threads[n].finished_);
+  }
+
+  for (int n = 0; n < kThreadCount; ++n) {
+    threads[n].Join();
+    LockGuard<Mutex> lock_guard(&threads[n].mutex_);
+    EXPECT_FALSE(threads[n].running_);
+    EXPECT_TRUE(threads[n].finished_);
+  }
+}
+
+
+namespace {
+
+class ThreadWithSharedMutexAndConditionVariable FINAL : public Thread {
+ public:
+  ThreadWithSharedMutexAndConditionVariable()
+      : Thread(Options("ThreadWithSharedMutexAndConditionVariable")),
+        running_(false),
+        finished_(false),
+        cv_(NULL),
+        mutex_(NULL) {}
+  virtual ~ThreadWithSharedMutexAndConditionVariable() {}
+
+  virtual void Run() OVERRIDE {
+    LockGuard<Mutex> lock_guard(mutex_);
+    running_ = true;
+    cv_->NotifyAll();
+    while (running_) {
+      cv_->Wait(mutex_);
+    }
+    finished_ = true;
+    cv_->NotifyAll();
+  }
+
+  bool running_;
+  bool finished_;
+  ConditionVariable* cv_;
+  Mutex* mutex_;
+};
+
+}  // namespace
+
+
+TEST(ConditionVariable, MultipleThreadsWithSharedSeparateConditionVariables) {
+  static const int kThreadCount = 128;
+  ThreadWithSharedMutexAndConditionVariable threads[kThreadCount];
+  ConditionVariable cv;
+  Mutex mutex;
+
+  for (int n = 0; n < kThreadCount; ++n) {
+    threads[n].mutex_ = &mutex;
+    threads[n].cv_ = &cv;
+  }
+
+  // Start all threads.
+  {
+    LockGuard<Mutex> lock_guard(&mutex);
+    for (int n = 0; n < kThreadCount; ++n) {
+      EXPECT_FALSE(threads[n].running_);
+      EXPECT_FALSE(threads[n].finished_);
+      threads[n].Start();
+    }
+  }
+
+  // Wait for all threads to start.
+  {
+    LockGuard<Mutex> lock_guard(&mutex);
+    for (int n = kThreadCount - 1; n >= 0; --n) {
+      while (!threads[n].running_) {
+        cv.Wait(&mutex);
+      }
+    }
+  }
+
+  // Make sure that all threads are running.
+  {
+    LockGuard<Mutex> lock_guard(&mutex);
+    for (int n = 0; n < kThreadCount; ++n) {
+      EXPECT_TRUE(threads[n].running_);
+      EXPECT_FALSE(threads[n].finished_);
+    }
+  }
+
+  // Tell all threads to quit.
+  {
+    LockGuard<Mutex> lock_guard(&mutex);
+    for (int n = kThreadCount - 1; n >= 0; --n) {
+      EXPECT_TRUE(threads[n].running_);
+      EXPECT_FALSE(threads[n].finished_);
+      // Tell the nth thread to quit.
+      threads[n].running_ = false;
+    }
+    cv.NotifyAll();
+  }
+
+  // Wait for all threads to quit.
+  {
+    LockGuard<Mutex> lock_guard(&mutex);
+    for (int n = 0; n < kThreadCount; ++n) {
+      while (!threads[n].finished_) {
+        cv.Wait(&mutex);
+      }
+    }
+  }
+
+  // Make sure all threads are finished.
+  {
+    LockGuard<Mutex> lock_guard(&mutex);
+    for (int n = kThreadCount - 1; n >= 0; --n) {
+      EXPECT_FALSE(threads[n].running_);
+      EXPECT_TRUE(threads[n].finished_);
+    }
+  }
+
+  // Join all threads.
+  for (int n = 0; n < kThreadCount; ++n) {
+    threads[n].Join();
+  }
+}
+
+
+namespace {
+
+class LoopIncrementThread FINAL : public Thread {
+ public:
+  LoopIncrementThread(int rem, int* counter, int limit, int thread_count,
+                      ConditionVariable* cv, Mutex* mutex)
+      : Thread(Options("LoopIncrementThread")),
+        rem_(rem),
+        counter_(counter),
+        limit_(limit),
+        thread_count_(thread_count),
+        cv_(cv),
+        mutex_(mutex) {
+    EXPECT_LT(rem, thread_count);
+    EXPECT_EQ(0, limit % thread_count);
+  }
+
+  virtual void Run() OVERRIDE {
+    int last_count = -1;
+    while (true) {
+      LockGuard<Mutex> lock_guard(mutex_);
+      int count = *counter_;
+      while (count % thread_count_ != rem_ && count < limit_) {
+        cv_->Wait(mutex_);
+        count = *counter_;
+      }
+      if (count >= limit_) break;
+      EXPECT_EQ(*counter_, count);
+      if (last_count != -1) {
+        EXPECT_EQ(last_count + (thread_count_ - 1), count);
+      }
+      count++;
+      *counter_ = count;
+      last_count = count;
+      cv_->NotifyAll();
+    }
+  }
+
+ private:
+  const int rem_;
+  int* counter_;
+  const int limit_;
+  const int thread_count_;
+  ConditionVariable* cv_;
+  Mutex* mutex_;
+};
+
+}  // namespace
+
+
+TEST(ConditionVariable, LoopIncrement) {
+  static const int kMaxThreadCount = 16;
+  Mutex mutex;
+  ConditionVariable cv;
+  for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) {
+    int limit = thread_count * 10;
+    int counter = 0;
+
+    // Setup the threads.
+    Thread** threads = new Thread* [thread_count];
+    for (int n = 0; n < thread_count; ++n) {
+      threads[n] = new LoopIncrementThread(n, &counter, limit, thread_count,
+                                           &cv, &mutex);
+    }
+
+    // Start all threads.
+    for (int n = thread_count - 1; n >= 0; --n) {
+      threads[n]->Start();
+    }
+
+    // Join and cleanup all threads.
+    for (int n = 0; n < thread_count; ++n) {
+      threads[n]->Join();
+      delete threads[n];
+    }
+    delete[] threads;
+
+    EXPECT_EQ(limit, counter);
+  }
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/platform/mutex-unittest.cc b/test/unittests/base/platform/mutex-unittest.cc
new file mode 100644
index 0000000..5af5efb
--- /dev/null
+++ b/test/unittests/base/platform/mutex-unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/platform/mutex.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+TEST(Mutex, LockGuardMutex) {
+  Mutex mutex;
+  { LockGuard<Mutex> lock_guard(&mutex); }
+  { LockGuard<Mutex> lock_guard(&mutex); }
+}
+
+
+TEST(Mutex, LockGuardRecursiveMutex) {
+  RecursiveMutex recursive_mutex;
+  { LockGuard<RecursiveMutex> lock_guard(&recursive_mutex); }
+  {
+    LockGuard<RecursiveMutex> lock_guard1(&recursive_mutex);
+    LockGuard<RecursiveMutex> lock_guard2(&recursive_mutex);
+  }
+}
+
+
+TEST(Mutex, LockGuardLazyMutex) {
+  LazyMutex lazy_mutex = LAZY_MUTEX_INITIALIZER;
+  { LockGuard<Mutex> lock_guard(lazy_mutex.Pointer()); }
+  { LockGuard<Mutex> lock_guard(lazy_mutex.Pointer()); }
+}
+
+
+TEST(Mutex, LockGuardLazyRecursiveMutex) {
+  LazyRecursiveMutex lazy_recursive_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER;
+  { LockGuard<RecursiveMutex> lock_guard(lazy_recursive_mutex.Pointer()); }
+  {
+    LockGuard<RecursiveMutex> lock_guard1(lazy_recursive_mutex.Pointer());
+    LockGuard<RecursiveMutex> lock_guard2(lazy_recursive_mutex.Pointer());
+  }
+}
+
+
+TEST(Mutex, MultipleMutexes) {
+  Mutex mutex1;
+  Mutex mutex2;
+  Mutex mutex3;
+  // Order 1
+  mutex1.Lock();
+  mutex2.Lock();
+  mutex3.Lock();
+  mutex1.Unlock();
+  mutex2.Unlock();
+  mutex3.Unlock();
+  // Order 2
+  mutex1.Lock();
+  mutex2.Lock();
+  mutex3.Lock();
+  mutex3.Unlock();
+  mutex2.Unlock();
+  mutex1.Unlock();
+}
+
+
+TEST(Mutex, MultipleRecursiveMutexes) {
+  RecursiveMutex recursive_mutex1;
+  RecursiveMutex recursive_mutex2;
+  // Order 1
+  recursive_mutex1.Lock();
+  recursive_mutex2.Lock();
+  EXPECT_TRUE(recursive_mutex1.TryLock());
+  EXPECT_TRUE(recursive_mutex2.TryLock());
+  recursive_mutex1.Unlock();
+  recursive_mutex1.Unlock();
+  recursive_mutex2.Unlock();
+  recursive_mutex2.Unlock();
+  // Order 2
+  recursive_mutex1.Lock();
+  EXPECT_TRUE(recursive_mutex1.TryLock());
+  recursive_mutex2.Lock();
+  EXPECT_TRUE(recursive_mutex2.TryLock());
+  recursive_mutex2.Unlock();
+  recursive_mutex1.Unlock();
+  recursive_mutex2.Unlock();
+  recursive_mutex1.Unlock();
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/platform/platform-unittest.cc b/test/unittests/base/platform/platform-unittest.cc
new file mode 100644
index 0000000..b17a9b9
--- /dev/null
+++ b/test/unittests/base/platform/platform-unittest.cc
@@ -0,0 +1,118 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/platform/platform.h"
+
+#if V8_OS_POSIX
+#include <unistd.h>  // NOLINT
+#endif
+
+#if V8_OS_WIN
+#include "src/base/win32-headers.h"
+#endif
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if V8_OS_ANDROID
+#define DISABLE_ON_ANDROID(Name) DISABLED_##Name
+#else
+#define DISABLE_ON_ANDROID(Name) Name
+#endif
+
+namespace v8 {
+namespace base {
+
+TEST(OS, GetCurrentProcessId) {
+#if V8_OS_POSIX
+  EXPECT_EQ(static_cast<int>(getpid()), OS::GetCurrentProcessId());
+#endif
+
+#if V8_OS_WIN
+  EXPECT_EQ(static_cast<int>(::GetCurrentProcessId()),
+            OS::GetCurrentProcessId());
+#endif
+}
+
+
+namespace {
+
+class SelfJoinThread FINAL : public Thread {
+ public:
+  SelfJoinThread() : Thread(Options("SelfJoinThread")) {}
+  void Run() FINAL { Join(); }
+};
+
+}  // namespace
+
+
+TEST(Thread, DISABLE_ON_ANDROID(SelfJoin)) {
+  SelfJoinThread thread;
+  thread.Start();
+  thread.Join();
+}
+
+
+namespace {
+
+class ThreadLocalStorageTest : public Thread, public ::testing::Test {
+ public:
+  ThreadLocalStorageTest() : Thread(Options("ThreadLocalStorageTest")) {
+    for (size_t i = 0; i < arraysize(keys_); ++i) {
+      keys_[i] = Thread::CreateThreadLocalKey();
+    }
+  }
+  ~ThreadLocalStorageTest() {
+    for (size_t i = 0; i < arraysize(keys_); ++i) {
+      Thread::DeleteThreadLocalKey(keys_[i]);
+    }
+  }
+
+  void Run() FINAL {
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK(!Thread::HasThreadLocal(keys_[i]));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      Thread::SetThreadLocal(keys_[i], GetValue(i));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK(Thread::HasThreadLocal(keys_[i]));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK_EQ(GetValue(i), Thread::GetThreadLocal(keys_[i]));
+      CHECK_EQ(GetValue(i), Thread::GetExistingThreadLocal(keys_[i]));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      Thread::SetThreadLocal(keys_[i], GetValue(arraysize(keys_) - i - 1));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK(Thread::HasThreadLocal(keys_[i]));
+    }
+    for (size_t i = 0; i < arraysize(keys_); i++) {
+      CHECK_EQ(GetValue(arraysize(keys_) - i - 1),
+               Thread::GetThreadLocal(keys_[i]));
+      CHECK_EQ(GetValue(arraysize(keys_) - i - 1),
+               Thread::GetExistingThreadLocal(keys_[i]));
+    }
+  }
+
+ private:
+  static void* GetValue(size_t x) {
+    return bit_cast<void*>(static_cast<uintptr_t>(x + 1));
+  }
+
+  // Older versions of Android have fewer TLS slots (nominally 64, but the
+  // system uses "about 5 of them" itself).
+  Thread::LocalStorageKey keys_[32];
+};
+
+}  // namespace
+
+
+TEST_F(ThreadLocalStorageTest, DoTest) {
+  Run();
+  Start();
+  Join();
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/platform/semaphore-unittest.cc b/test/unittests/base/platform/semaphore-unittest.cc
new file mode 100644
index 0000000..c68435f
--- /dev/null
+++ b/test/unittests/base/platform/semaphore-unittest.cc
@@ -0,0 +1,145 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cstring>
+
+#include "src/base/platform/platform.h"
+#include "src/base/platform/semaphore.h"
+#include "src/base/platform/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+namespace {
+
+static const char kAlphabet[] = "XKOAD";
+static const size_t kAlphabetSize = sizeof(kAlphabet) - 1;
+static const size_t kBufferSize = 987;  // GCD(buffer size, alphabet size) = 1
+static const size_t kDataSize = kBufferSize * kAlphabetSize * 10;
+
+
+class ProducerThread FINAL : public Thread {
+ public:
+  ProducerThread(char* buffer, Semaphore* free_space, Semaphore* used_space)
+      : Thread(Options("ProducerThread")),
+        buffer_(buffer),
+        free_space_(free_space),
+        used_space_(used_space) {}
+  virtual ~ProducerThread() {}
+
+  virtual void Run() OVERRIDE {
+    for (size_t n = 0; n < kDataSize; ++n) {
+      free_space_->Wait();
+      buffer_[n % kBufferSize] = kAlphabet[n % kAlphabetSize];
+      used_space_->Signal();
+    }
+  }
+
+ private:
+  char* buffer_;
+  Semaphore* const free_space_;
+  Semaphore* const used_space_;
+};
+
+
+class ConsumerThread FINAL : public Thread {
+ public:
+  ConsumerThread(const char* buffer, Semaphore* free_space,
+                 Semaphore* used_space)
+      : Thread(Options("ConsumerThread")),
+        buffer_(buffer),
+        free_space_(free_space),
+        used_space_(used_space) {}
+  virtual ~ConsumerThread() {}
+
+  virtual void Run() OVERRIDE {
+    for (size_t n = 0; n < kDataSize; ++n) {
+      used_space_->Wait();
+      EXPECT_EQ(kAlphabet[n % kAlphabetSize], buffer_[n % kBufferSize]);
+      free_space_->Signal();
+    }
+  }
+
+ private:
+  const char* buffer_;
+  Semaphore* const free_space_;
+  Semaphore* const used_space_;
+};
+
+
+class WaitAndSignalThread FINAL : public Thread {
+ public:
+  explicit WaitAndSignalThread(Semaphore* semaphore)
+      : Thread(Options("WaitAndSignalThread")), semaphore_(semaphore) {}
+  virtual ~WaitAndSignalThread() {}
+
+  virtual void Run() OVERRIDE {
+    for (int n = 0; n < 100; ++n) {
+      semaphore_->Wait();
+      ASSERT_FALSE(semaphore_->WaitFor(TimeDelta::FromMicroseconds(1)));
+      semaphore_->Signal();
+    }
+  }
+
+ private:
+  Semaphore* const semaphore_;
+};
+
+}  // namespace
+
+
+TEST(Semaphore, ProducerConsumer) {
+  char buffer[kBufferSize];
+  std::memset(buffer, 0, sizeof(buffer));
+  Semaphore free_space(kBufferSize);
+  Semaphore used_space(0);
+  ProducerThread producer_thread(buffer, &free_space, &used_space);
+  ConsumerThread consumer_thread(buffer, &free_space, &used_space);
+  producer_thread.Start();
+  consumer_thread.Start();
+  producer_thread.Join();
+  consumer_thread.Join();
+}
+
+
+TEST(Semaphore, WaitAndSignal) {
+  Semaphore semaphore(0);
+  WaitAndSignalThread t1(&semaphore);
+  WaitAndSignalThread t2(&semaphore);
+
+  t1.Start();
+  t2.Start();
+
+  // Make something available.
+  semaphore.Signal();
+
+  t1.Join();
+  t2.Join();
+
+  semaphore.Wait();
+
+  EXPECT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1)));
+}
+
+
+TEST(Semaphore, WaitFor) {
+  Semaphore semaphore(0);
+
+  // Semaphore not signalled - timeout.
+  ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0)));
+  ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100)));
+  ASSERT_FALSE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000)));
+
+  // Semaphore signalled - no timeout.
+  semaphore.Signal();
+  ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(0)));
+  semaphore.Signal();
+  ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(100)));
+  semaphore.Signal();
+  ASSERT_TRUE(semaphore.WaitFor(TimeDelta::FromMicroseconds(1000)));
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/platform/time-unittest.cc b/test/unittests/base/platform/time-unittest.cc
new file mode 100644
index 0000000..b3bfbab
--- /dev/null
+++ b/test/unittests/base/platform/time-unittest.cc
@@ -0,0 +1,186 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/platform/time.h"
+
+#if V8_OS_MACOSX
+#include <mach/mach_time.h>
+#endif
+#if V8_OS_POSIX
+#include <sys/time.h>
+#endif
+
+#if V8_OS_WIN
+#include "src/base/win32-headers.h"
+#endif
+
+#include "src/base/platform/elapsed-timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+TEST(TimeDelta, FromAndIn) {
+  EXPECT_EQ(TimeDelta::FromDays(2), TimeDelta::FromHours(48));
+  EXPECT_EQ(TimeDelta::FromHours(3), TimeDelta::FromMinutes(180));
+  EXPECT_EQ(TimeDelta::FromMinutes(2), TimeDelta::FromSeconds(120));
+  EXPECT_EQ(TimeDelta::FromSeconds(2), TimeDelta::FromMilliseconds(2000));
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2), TimeDelta::FromMicroseconds(2000));
+  EXPECT_EQ(static_cast<int>(13), TimeDelta::FromDays(13).InDays());
+  EXPECT_EQ(static_cast<int>(13), TimeDelta::FromHours(13).InHours());
+  EXPECT_EQ(static_cast<int>(13), TimeDelta::FromMinutes(13).InMinutes());
+  EXPECT_EQ(static_cast<int64_t>(13), TimeDelta::FromSeconds(13).InSeconds());
+  EXPECT_DOUBLE_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF());
+  EXPECT_EQ(static_cast<int64_t>(13),
+            TimeDelta::FromMilliseconds(13).InMilliseconds());
+  EXPECT_DOUBLE_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF());
+  EXPECT_EQ(static_cast<int64_t>(13),
+            TimeDelta::FromMicroseconds(13).InMicroseconds());
+}
+
+
+#if V8_OS_MACOSX
+TEST(TimeDelta, MachTimespec) {
+  TimeDelta null = TimeDelta();
+  EXPECT_EQ(null, TimeDelta::FromMachTimespec(null.ToMachTimespec()));
+  TimeDelta delta1 = TimeDelta::FromMilliseconds(42);
+  EXPECT_EQ(delta1, TimeDelta::FromMachTimespec(delta1.ToMachTimespec()));
+  TimeDelta delta2 = TimeDelta::FromDays(42);
+  EXPECT_EQ(delta2, TimeDelta::FromMachTimespec(delta2.ToMachTimespec()));
+}
+#endif
+
+
+TEST(Time, JsTime) {
+  Time t = Time::FromJsTime(700000.3);
+  EXPECT_DOUBLE_EQ(700000.3, t.ToJsTime());
+}
+
+
+#if V8_OS_POSIX
+TEST(Time, Timespec) {
+  Time null;
+  EXPECT_TRUE(null.IsNull());
+  EXPECT_EQ(null, Time::FromTimespec(null.ToTimespec()));
+  Time now = Time::Now();
+  EXPECT_EQ(now, Time::FromTimespec(now.ToTimespec()));
+  Time now_sys = Time::NowFromSystemTime();
+  EXPECT_EQ(now_sys, Time::FromTimespec(now_sys.ToTimespec()));
+  Time unix_epoch = Time::UnixEpoch();
+  EXPECT_EQ(unix_epoch, Time::FromTimespec(unix_epoch.ToTimespec()));
+  Time max = Time::Max();
+  EXPECT_TRUE(max.IsMax());
+  EXPECT_EQ(max, Time::FromTimespec(max.ToTimespec()));
+}
+
+
+TEST(Time, Timeval) {
+  Time null;
+  EXPECT_TRUE(null.IsNull());
+  EXPECT_EQ(null, Time::FromTimeval(null.ToTimeval()));
+  Time now = Time::Now();
+  EXPECT_EQ(now, Time::FromTimeval(now.ToTimeval()));
+  Time now_sys = Time::NowFromSystemTime();
+  EXPECT_EQ(now_sys, Time::FromTimeval(now_sys.ToTimeval()));
+  Time unix_epoch = Time::UnixEpoch();
+  EXPECT_EQ(unix_epoch, Time::FromTimeval(unix_epoch.ToTimeval()));
+  Time max = Time::Max();
+  EXPECT_TRUE(max.IsMax());
+  EXPECT_EQ(max, Time::FromTimeval(max.ToTimeval()));
+}
+#endif
+
+
+#if V8_OS_WIN
+TEST(Time, Filetime) {
+  Time null;
+  EXPECT_TRUE(null.IsNull());
+  EXPECT_EQ(null, Time::FromFiletime(null.ToFiletime()));
+  Time now = Time::Now();
+  EXPECT_EQ(now, Time::FromFiletime(now.ToFiletime()));
+  Time now_sys = Time::NowFromSystemTime();
+  EXPECT_EQ(now_sys, Time::FromFiletime(now_sys.ToFiletime()));
+  Time unix_epoch = Time::UnixEpoch();
+  EXPECT_EQ(unix_epoch, Time::FromFiletime(unix_epoch.ToFiletime()));
+  Time max = Time::Max();
+  EXPECT_TRUE(max.IsMax());
+  EXPECT_EQ(max, Time::FromFiletime(max.ToFiletime()));
+}
+#endif
+
+
+namespace {
+
+template <typename T>
+static void ResolutionTest(T (*Now)(), TimeDelta target_granularity) {
+  // We're trying to measure that intervals increment in a VERY small amount
+  // of time -- according to the specified target granularity. Unfortunately,
+  // if we happen to have a context switch in the middle of our test, the
+  // context switch could easily exceed our limit. So, we iterate on this
+  // several times. As long as we're able to detect the fine-granularity
+  // timers at least once, then the test has succeeded.
+  static const TimeDelta kExpirationTimeout = TimeDelta::FromSeconds(1);
+  ElapsedTimer timer;
+  timer.Start();
+  TimeDelta delta;
+  do {
+    T start = Now();
+    T now = start;
+    // Loop until we can detect that the clock has changed. Non-HighRes timers
+    // will increment in chunks, i.e. 15ms. By spinning until we see a clock
+    // change, we detect the minimum time between measurements.
+    do {
+      now = Now();
+      delta = now - start;
+    } while (now <= start);
+    EXPECT_NE(static_cast<int64_t>(0), delta.InMicroseconds());
+  } while (delta > target_granularity && !timer.HasExpired(kExpirationTimeout));
+  EXPECT_LE(delta, target_granularity);
+}
+
+}  // namespace
+
+
+TEST(Time, NowResolution) {
+  // We assume that Time::Now() has at least 16ms resolution.
+  static const TimeDelta kTargetGranularity = TimeDelta::FromMilliseconds(16);
+  ResolutionTest<Time>(&Time::Now, kTargetGranularity);
+}
+
+
+TEST(TimeTicks, NowResolution) {
+  // We assume that TimeTicks::Now() has at least 16ms resolution.
+  static const TimeDelta kTargetGranularity = TimeDelta::FromMilliseconds(16);
+  ResolutionTest<TimeTicks>(&TimeTicks::Now, kTargetGranularity);
+}
+
+
+TEST(TimeTicks, HighResolutionNowResolution) {
+  if (!TimeTicks::IsHighResolutionClockWorking()) return;
+
+  // We assume that TimeTicks::HighResolutionNow() has sub-ms resolution.
+  static const TimeDelta kTargetGranularity = TimeDelta::FromMilliseconds(1);
+  ResolutionTest<TimeTicks>(&TimeTicks::HighResolutionNow, kTargetGranularity);
+}
+
+
+TEST(TimeTicks, IsMonotonic) {
+  TimeTicks previous_normal_ticks;
+  TimeTicks previous_highres_ticks;
+  ElapsedTimer timer;
+  timer.Start();
+  while (!timer.HasExpired(TimeDelta::FromMilliseconds(100))) {
+    TimeTicks normal_ticks = TimeTicks::Now();
+    TimeTicks highres_ticks = TimeTicks::HighResolutionNow();
+    EXPECT_GE(normal_ticks, previous_normal_ticks);
+    EXPECT_GE((normal_ticks - previous_normal_ticks).InMicroseconds(), 0);
+    EXPECT_GE(highres_ticks, previous_highres_ticks);
+    EXPECT_GE((highres_ticks - previous_highres_ticks).InMicroseconds(), 0);
+    previous_normal_ticks = normal_ticks;
+    previous_highres_ticks = highres_ticks;
+  }
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/sys-info-unittest.cc b/test/unittests/base/sys-info-unittest.cc
new file mode 100644
index 0000000..a760f94
--- /dev/null
+++ b/test/unittests/base/sys-info-unittest.cc
@@ -0,0 +1,32 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/sys-info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if V8_OS_NACL
+#define DISABLE_ON_NACL(Name) DISABLED_##Name
+#else
+#define DISABLE_ON_NACL(Name) Name
+#endif
+
+namespace v8 {
+namespace base {
+
+TEST(SysInfoTest, NumberOfProcessors) {
+  EXPECT_LT(0, SysInfo::NumberOfProcessors());
+}
+
+
+TEST(SysInfoTest, DISABLE_ON_NACL(AmountOfPhysicalMemory)) {
+  EXPECT_LT(0, SysInfo::AmountOfPhysicalMemory());
+}
+
+
+TEST(SysInfoTest, AmountOfVirtualMemory) {
+  EXPECT_LE(0, SysInfo::AmountOfVirtualMemory());
+}
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/base/utils/random-number-generator-unittest.cc b/test/unittests/base/utils/random-number-generator-unittest.cc
new file mode 100644
index 0000000..7c533db
--- /dev/null
+++ b/test/unittests/base/utils/random-number-generator-unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <climits>
+
+#include "src/base/utils/random-number-generator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace base {
+
+class RandomNumberGeneratorTest : public ::testing::TestWithParam<int> {};
+
+
+static const int kMaxRuns = 12345;
+
+
+TEST_P(RandomNumberGeneratorTest, NextIntWithMaxValue) {
+  RandomNumberGenerator rng(GetParam());
+  for (int max = 1; max <= kMaxRuns; ++max) {
+    int n = rng.NextInt(max);
+    EXPECT_LE(0, n);
+    EXPECT_LT(n, max);
+  }
+}
+
+
+TEST_P(RandomNumberGeneratorTest, NextBooleanReturnsFalseOrTrue) {
+  RandomNumberGenerator rng(GetParam());
+  for (int k = 0; k < kMaxRuns; ++k) {
+    bool b = rng.NextBool();
+    EXPECT_TRUE(b == false || b == true);
+  }
+}
+
+
+TEST_P(RandomNumberGeneratorTest, NextDoubleReturnsValueBetween0And1) {
+  RandomNumberGenerator rng(GetParam());
+  for (int k = 0; k < kMaxRuns; ++k) {
+    double d = rng.NextDouble();
+    EXPECT_LE(0.0, d);
+    EXPECT_LT(d, 1.0);
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(RandomSeeds, RandomNumberGeneratorTest,
+                        ::testing::Values(INT_MIN, -1, 0, 1, 42, 100,
+                                          1234567890, 987654321, INT_MAX));
+
+}  // namespace base
+}  // namespace v8
diff --git a/test/unittests/char-predicates-unittest.cc b/test/unittests/char-predicates-unittest.cc
new file mode 100644
index 0000000..d1ba2c5
--- /dev/null
+++ b/test/unittests/char-predicates-unittest.cc
@@ -0,0 +1,121 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/char-predicates.h"
+#include "src/unicode.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace internal {
+
+TEST(CharPredicatesTest, WhiteSpace) {
+  // As of Unicode 6.3.0, \u180E is no longer a white space. We still consider
+  // it to be one though, since JS recognizes all white spaces in Unicode 5.1.
+  EXPECT_TRUE(WhiteSpace::Is(0x0009));
+  EXPECT_TRUE(WhiteSpace::Is(0x000B));
+  EXPECT_TRUE(WhiteSpace::Is(0x000C));
+  EXPECT_TRUE(WhiteSpace::Is(' '));
+  EXPECT_TRUE(WhiteSpace::Is(0x00A0));
+  EXPECT_TRUE(WhiteSpace::Is(0x180E));
+  EXPECT_TRUE(WhiteSpace::Is(0xFEFF));
+}
+
+
+TEST(CharPredicatesTest, WhiteSpaceOrLineTerminator) {
+  // As of Unicode 6.3.0, \u180E is no longer a white space. We still consider
+  // it to be one though, since JS recognizes all white spaces in Unicode 5.1.
+  // White spaces
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x0009));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000B));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000C));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(' '));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x00A0));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x180E));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0xFEFF));
+  // Line terminators
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000A));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x000D));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x2028));
+  EXPECT_TRUE(WhiteSpaceOrLineTerminator::Is(0x2029));
+}
+
+
+TEST(CharPredicatesTest, IdentifierStart) {
+  EXPECT_TRUE(IdentifierStart::Is('$'));
+  EXPECT_TRUE(IdentifierStart::Is('_'));
+  EXPECT_TRUE(IdentifierStart::Is('\\'));
+
+  // http://www.unicode.org/reports/tr31/
+  // Other_ID_Start
+  EXPECT_TRUE(IdentifierStart::Is(0x2118));
+  EXPECT_TRUE(IdentifierStart::Is(0x212E));
+  EXPECT_TRUE(IdentifierStart::Is(0x309B));
+  EXPECT_TRUE(IdentifierStart::Is(0x309C));
+
+  // Issue 2892:
+  // \u2E2F has the Pattern_Syntax property, excluding it from ID_Start.
+  EXPECT_FALSE(unibrow::ID_Start::Is(0x2E2F));
+}
+
+
+TEST(CharPredicatesTest, IdentifierPart) {
+  EXPECT_TRUE(IdentifierPart::Is('$'));
+  EXPECT_TRUE(IdentifierPart::Is('_'));
+  EXPECT_TRUE(IdentifierPart::Is('\\'));
+  EXPECT_TRUE(IdentifierPart::Is(0x200C));
+  EXPECT_TRUE(IdentifierPart::Is(0x200D));
+
+  // http://www.unicode.org/reports/tr31/
+  // Other_ID_Start
+  EXPECT_TRUE(IdentifierPart::Is(0x2118));
+  EXPECT_TRUE(IdentifierPart::Is(0x212E));
+  EXPECT_TRUE(IdentifierPart::Is(0x309B));
+  EXPECT_TRUE(IdentifierPart::Is(0x309C));
+
+  // Other_ID_Continue
+  EXPECT_TRUE(IdentifierPart::Is(0x00B7));
+  EXPECT_TRUE(IdentifierPart::Is(0x0387));
+  EXPECT_TRUE(IdentifierPart::Is(0x1369));
+  EXPECT_TRUE(IdentifierPart::Is(0x1370));
+  EXPECT_TRUE(IdentifierPart::Is(0x1371));
+  EXPECT_TRUE(IdentifierPart::Is(0x19DA));
+
+  // Issue 2892:
+  // \u2E2F has the Pattern_Syntax property, excluding it from ID_Start.
+  EXPECT_FALSE(IdentifierPart::Is(0x2E2F));
+}
+
+
+#ifdef V8_I18N_SUPPORT
+TEST(CharPredicatesTest, SupplementaryPlaneIdentifiers) {
+  // Both ID_Start and ID_Continue.
+  EXPECT_TRUE(IdentifierStart::Is(0x10403));  // Category Lu
+  EXPECT_TRUE(IdentifierPart::Is(0x10403));
+  EXPECT_TRUE(IdentifierStart::Is(0x1043C));  // Category Ll
+  EXPECT_TRUE(IdentifierPart::Is(0x1043C));
+  EXPECT_TRUE(IdentifierStart::Is(0x16F9C));  // Category Lm
+  EXPECT_TRUE(IdentifierPart::Is(0x16F9C));
+  EXPECT_TRUE(IdentifierStart::Is(0x10048));  // Category Lo
+  EXPECT_TRUE(IdentifierPart::Is(0x10048));
+  EXPECT_TRUE(IdentifierStart::Is(0x1014D));  // Category Nl
+  EXPECT_TRUE(IdentifierPart::Is(0x1014D));
+
+  // Only ID_Continue.
+  EXPECT_FALSE(IdentifierStart::Is(0x101FD));  // Category Mn
+  EXPECT_TRUE(IdentifierPart::Is(0x101FD));
+  EXPECT_FALSE(IdentifierStart::Is(0x11002));  // Category Mc
+  EXPECT_TRUE(IdentifierPart::Is(0x11002));
+  EXPECT_FALSE(IdentifierStart::Is(0x104A9));  // Category Nd
+  EXPECT_TRUE(IdentifierPart::Is(0x104A9));
+
+  // Neither.
+  EXPECT_FALSE(IdentifierStart::Is(0x10111));  // Category No
+  EXPECT_FALSE(IdentifierPart::Is(0x10111));
+  EXPECT_FALSE(IdentifierStart::Is(0x1F4A9));  // Category So
+  EXPECT_FALSE(IdentifierPart::Is(0x1F4A9));
+}
+#endif  // V8_I18N_SUPPORT
+
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc b/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
new file mode 100644
index 0000000..fbdf87a
--- /dev/null
+++ b/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
@@ -0,0 +1,2352 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+typedef RawMachineAssembler::Label MLabel;
+typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*);
+
+
+// Data processing instructions.
+struct DPI {
+  Constructor constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  ArchOpcode reverse_arch_opcode;
+  ArchOpcode test_arch_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const DPI& dpi) {
+  return os << dpi.constructor_name;
+}
+
+
+static const DPI kDPIs[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kArmAnd, kArmAnd, kArmTst},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kArmOrr, kArmOrr, kArmOrr},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArmEor, kArmEor, kArmTeq},
+    {&RawMachineAssembler::Int32Add, "Int32Add", kArmAdd, kArmAdd, kArmCmn},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArmSub, kArmRsb, kArmCmp}};
+
+
+// Data processing instructions with overflow.
+struct ODPI {
+  Constructor constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  ArchOpcode reverse_arch_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const ODPI& odpi) {
+  return os << odpi.constructor_name;
+}
+
+
+static const ODPI kODPIs[] = {{&RawMachineAssembler::Int32AddWithOverflow,
+                               "Int32AddWithOverflow", kArmAdd, kArmAdd},
+                              {&RawMachineAssembler::Int32SubWithOverflow,
+                               "Int32SubWithOverflow", kArmSub, kArmRsb}};
+
+
+// Shifts.
+struct Shift {
+  Constructor constructor;
+  const char* constructor_name;
+  int32_t i_low;          // lowest possible immediate
+  int32_t i_high;         // highest possible immediate
+  AddressingMode i_mode;  // Operand2_R_<shift>_I
+  AddressingMode r_mode;  // Operand2_R_<shift>_R
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Shift& shift) {
+  return os << shift.constructor_name;
+}
+
+
+static const Shift kShifts[] = {
+    {&RawMachineAssembler::Word32Sar, "Word32Sar", 1, 32,
+     kMode_Operand2_R_ASR_I, kMode_Operand2_R_ASR_R},
+    {&RawMachineAssembler::Word32Shl, "Word32Shl", 0, 31,
+     kMode_Operand2_R_LSL_I, kMode_Operand2_R_LSL_R},
+    {&RawMachineAssembler::Word32Shr, "Word32Shr", 1, 32,
+     kMode_Operand2_R_LSR_I, kMode_Operand2_R_LSR_R},
+    {&RawMachineAssembler::Word32Ror, "Word32Ror", 1, 31,
+     kMode_Operand2_R_ROR_I, kMode_Operand2_R_ROR_R}};
+
+
+// Immediates (random subset).
+static const int32_t kImmediates[] = {
+    std::numeric_limits<int32_t>::min(), -2147483617, -2147483606, -2113929216,
+    -2080374784,                         -1996488704, -1879048192, -1459617792,
+    -1358954496,                         -1342177265, -1275068414, -1073741818,
+    -1073741777,                         -855638016,  -805306368,  -402653184,
+    -268435444,                          -16777216,   0,           35,
+    61,                                  105,         116,         171,
+    245,                                 255,         692,         1216,
+    1248,                                1520,        1600,        1888,
+    3744,                                4080,        5888,        8384,
+    9344,                                9472,        9792,        13312,
+    15040,                               15360,       20736,       22272,
+    23296,                               32000,       33536,       37120,
+    45824,                               47872,       56320,       59392,
+    65280,                               72704,       101376,      147456,
+    161792,                              164864,      167936,      173056,
+    195584,                              209920,      212992,      356352,
+    655360,                              704512,      716800,      851968,
+    901120,                              1044480,     1523712,     2572288,
+    3211264,                             3588096,     3833856,     3866624,
+    4325376,                             5177344,     6488064,     7012352,
+    7471104,                             14090240,    16711680,    19398656,
+    22282240,                            28573696,    30408704,    30670848,
+    43253760,                            54525952,    55312384,    56623104,
+    68157440,                            115343360,   131072000,   187695104,
+    188743680,                           195035136,   197132288,   203423744,
+    218103808,                           267386880,   268435470,   285212672,
+    402653185,                           415236096,   595591168,   603979776,
+    603979778,                           629145600,   1073741835,  1073741855,
+    1073741861,                          1073741884,  1157627904,  1476395008,
+    1476395010,                          1610612741,  2030043136,  2080374785,
+    2097152000};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Data processing instructions.
+
+
+typedef InstructionSelectorTestWithParam<DPI> InstructionSelectorDPITest;
+
+
+TEST_P(InstructionSelectorDPITest, Parameters) {
+  const DPI dpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorDPITest, Immediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, ShiftByParameter) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return((m.*dpi.constructor)(
+        m.Parameter(0),
+        (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return((m.*dpi.constructor)(
+        (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
+        m.Parameter(2)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, ShiftByImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return((m.*dpi.constructor)(
+          m.Parameter(0),
+          (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return((m.*dpi.constructor)(
+          (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+          m.Parameter(1)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchWithParameters) {
+  const DPI dpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchWithImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)), &a,
+             &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)), &a,
+             &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchWithShiftByParameter) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch((m.*dpi.constructor)(
+                 m.Parameter(0),
+                 (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch((m.*dpi.constructor)(
+                 (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
+                 m.Parameter(2)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchWithShiftByImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      MLabel a, b;
+      m.Branch((m.*dpi.constructor)(m.Parameter(0),
+                                    (m.*shift.constructor)(
+                                        m.Parameter(1), m.Int32Constant(imm))),
+               &a, &b);
+      m.Bind(&a);
+      m.Return(m.Int32Constant(1));
+      m.Bind(&b);
+      m.Return(m.Int32Constant(0));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(5U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+      EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      MLabel a, b;
+      m.Branch((m.*dpi.constructor)(
+                   (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+                   m.Parameter(1)),
+               &a, &b);
+      m.Bind(&a);
+      m.Return(m.Int32Constant(1));
+      m.Bind(&b);
+      m.Return(m.Int32Constant(0));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(5U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+      EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchIfZeroWithParameters) {
+  const DPI dpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  m.Branch(m.Word32Equal((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)),
+                         m.Int32Constant(0)),
+           &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithParameters) {
+  const DPI dpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  m.Branch(
+      m.Word32NotEqual((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)),
+                       m.Int32Constant(0)),
+      &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchIfZeroWithImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32Equal(
+                 (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+                 m.Int32Constant(0)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32Equal(
+                 (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)),
+                 m.Int32Constant(0)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithImmediate) {
+  const DPI dpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32NotEqual(
+                 (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+                 m.Int32Constant(0)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32NotEqual(
+                 (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)),
+                 m.Int32Constant(0)),
+             &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorDPITest,
+                        ::testing::ValuesIn(kDPIs));
+
+
+// -----------------------------------------------------------------------------
+// Data processing instructions with overflow.
+
+
+typedef InstructionSelectorTestWithParam<ODPI> InstructionSelectorODPITest;
+
+
+TEST_P(InstructionSelectorODPITest, OvfWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Projection(1, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorODPITest, OvfWithImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, OvfWithShiftByParameter) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, (m.*odpi.constructor)(
+               m.Parameter(0),
+               (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, (m.*odpi.constructor)(
+               (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
+               m.Parameter(0))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, OvfWithShiftByImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return(m.Projection(
+          1, (m.*odpi.constructor)(m.Parameter(0),
+                                   (m.*shift.constructor)(
+                                       m.Parameter(1), m.Int32Constant(imm)))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_LE(1U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+      EXPECT_EQ(kOverflow, s[0]->flags_condition());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return(m.Projection(
+          1, (m.*odpi.constructor)(
+                 (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
+                 m.Parameter(0))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_LE(1U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+      EXPECT_EQ(kOverflow, s[0]->flags_condition());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, ValWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Projection(0, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_P(InstructionSelectorODPITest, ValWithImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, ValWithShiftByParameter) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, (m.*odpi.constructor)(
+               m.Parameter(0),
+               (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, (m.*odpi.constructor)(
+               (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
+               m.Parameter(0))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, ValWithShiftByImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return(m.Projection(
+          0, (m.*odpi.constructor)(m.Parameter(0),
+                                   (m.*shift.constructor)(
+                                       m.Parameter(1), m.Int32Constant(imm)))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_LE(1U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return(m.Projection(
+          0, (m.*odpi.constructor)(
+                 (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
+                 m.Parameter(0))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_LE(1U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BothWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+  Stream s = m.Build();
+  ASSERT_LE(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(2U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorODPITest, BothWithImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BothWithShiftByParameter) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* n = (m.*odpi.constructor)(
+        m.Parameter(0), (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* n = (m.*odpi.constructor)(
+        (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), m.Parameter(2));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BothWithShiftByImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      Node* n = (m.*odpi.constructor)(
+          m.Parameter(0),
+          (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)));
+      m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+      Stream s = m.Build();
+      ASSERT_LE(1U, s.size());
+      EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(2U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+      EXPECT_EQ(kOverflow, s[0]->flags_condition());
+    }
+  }
+  TRACED_FOREACH(Shift, shift, kShifts) {
+    TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      Node* n = (m.*odpi.constructor)(
+          (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
+          m.Parameter(1));
+      m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+      Stream s = m.Build();
+      ASSERT_LE(1U, s.size());
+      EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+      EXPECT_EQ(2U, s[0]->OutputCount());
+      EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+      EXPECT_EQ(kOverflow, s[0]->flags_condition());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BranchWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Branch(m.Projection(1, n), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(0));
+  m.Bind(&b);
+  m.Return(m.Projection(0, n));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(4U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorODPITest, BranchWithImmediate) {
+  const ODPI odpi = GetParam();
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
+    m.Branch(m.Projection(1, n), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(0));
+    m.Bind(&b);
+    m.Return(m.Projection(0, n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0));
+    m.Branch(m.Projection(1, n), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(0));
+    m.Bind(&b);
+    m.Return(m.Projection(0, n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorODPITest, BranchIfZeroWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Branch(m.Word32Equal(m.Projection(1, n), m.Int32Constant(0)), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Projection(0, n));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(4U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kNotOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorODPITest, BranchIfNotZeroWithParameters) {
+  const ODPI odpi = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  MLabel a, b;
+  Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Branch(m.Word32NotEqual(m.Projection(1, n), m.Int32Constant(0)), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Projection(0, n));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(4U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorODPITest,
+                        ::testing::ValuesIn(kODPIs));
+
+
+// -----------------------------------------------------------------------------
+// Shifts.
+
+
+typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest;
+
+
+TEST_P(InstructionSelectorShiftTest, Parameters) {
+  const Shift shift = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return((m.*shift.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Immediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return((m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameter) {
+  const Shift shift = GetParam();
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(
+        m.Word32Equal(m.Parameter(0),
+                      (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(
+        m.Word32Equal((m.*shift.constructor)(m.Parameter(1), m.Parameter(2)),
+                      m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameterAndImmediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(
+        (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
+        m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(
+        m.Parameter(0),
+        (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32EqualToZeroWithParameters) {
+  const Shift shift = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Word32Equal(m.Int32Constant(0),
+                    (m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(2U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32EqualToZeroWithImmediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(
+        m.Int32Constant(0),
+        (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMov, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32NotWithParameters) {
+  const Shift shift = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Word32Not((m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
+  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32NotWithImmediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Not(
+        (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithParameters) {
+  const Shift shift = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Word32And(m.Parameter(0), m.Word32Not((m.*shift.constructor)(
+                                           m.Parameter(1), m.Parameter(2)))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmBic, s[0]->arch_opcode());
+  EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithImmediate) {
+  const Shift shift = GetParam();
+  TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Parameter(0),
+                         m.Word32Not((m.*shift.constructor)(
+                             m.Parameter(1), m.Int32Constant(imm)))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
+    EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
+                        ::testing::ValuesIn(kShifts));
+
+
+// -----------------------------------------------------------------------------
+// Memory access instructions.
+
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode ldr_opcode;
+  ArchOpcode str_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[40];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
+  return os << memacc.type;
+}
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8,
+     kArmLdrsb,
+     kArmStrb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint8,
+     kArmLdrb,
+     kArmStrb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3914, -3536, -3234, -3185, -3169, -1073, -990, -859, -720, -434,
+      -127, -124, -122, -105, -91, -86, -64, -55, -53, -30, -10, -3, 0, 20, 28,
+      39, 58, 64, 73, 75, 100, 108, 121, 686, 963, 1363, 2759, 3449, 4095}},
+    {kMachInt16,
+     kArmLdrsh,
+     kArmStrh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-255, -251, -232, -220, -144, -138, -130, -126, -116, -115, -102, -101,
+      -98, -69, -59, -56, -39, -35, -23, -19, -7, 0, 22, 26, 37, 68, 83, 87, 98,
+      102, 108, 111, 117, 171, 195, 203, 204, 245, 246, 255}},
+    {kMachUint16,
+     kArmLdrh,
+     kArmStrh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-255, -230, -201, -172, -125, -119, -118, -105, -98, -79, -54, -42, -41,
+      -32, -12, -11, -5, -4, 0, 5, 9, 25, 28, 51, 58, 60, 89, 104, 108, 109,
+      114, 116, 120, 138, 150, 161, 166, 172, 228, 255}},
+    {kMachInt32,
+     kArmLdr,
+     kArmStr,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -1898, -1685, -1562, -1408, -1313, -344, -128, -116, -100, -92,
+      -80, -72, -71, -56, -25, -21, -11, -9, 0, 3, 5, 27, 28, 42, 52, 63, 88,
+      93, 97, 125, 846, 1037, 2102, 2403, 2597, 2632, 2997, 3935, 4095}},
+    {kMachFloat32,
+     kArmVldrF32,
+     kArmVstrF32,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-1020, -928, -896, -772, -728, -680, -660, -488, -372, -112, -100, -92,
+      -84, -80, -72, -64, -60, -56, -52, -48, -36, -32, -20, -8, -4, 0, 8, 20,
+      24, 40, 64, 112, 204, 388, 516, 852, 856, 976, 988, 1020}},
+    {kMachFloat64,
+     kArmVldrF64,
+     kArmVstrF64,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-1020, -948, -796, -696, -612, -364, -320, -308, -128, -112, -108, -104,
+      -96, -84, -80, -56, -48, -40, -20, 0, 24, 28, 36, 48, 64, 84, 96, 100,
+      108, 116, 120, 140, 156, 408, 432, 444, 772, 832, 940, 1020}}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(0U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat32);
+  m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVcvtF64F32, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat64);
+  m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVcvtF32F64, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+// -----------------------------------------------------------------------------
+// Comparisons.
+
+
+namespace {
+
+struct Comparison {
+  Constructor constructor;
+  const char* constructor_name;
+  FlagsCondition flags_condition;
+  FlagsCondition negated_flags_condition;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Comparison& cmp) {
+  return os << cmp.constructor_name;
+}
+
+
+const Comparison kComparisons[] = {
+    {&RawMachineAssembler::Word32Equal, "Word32Equal", kEqual, kNotEqual},
+    {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kSignedLessThan,
+     kSignedGreaterThanOrEqual},
+    {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
+     kSignedLessThanOrEqual, kSignedGreaterThan},
+    {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kUnsignedLessThan,
+     kUnsignedGreaterThanOrEqual},
+    {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
+     kUnsignedLessThanOrEqual, kUnsignedGreaterThan}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<Comparison>
+    InstructionSelectorComparisonTest;
+
+
+TEST_P(InstructionSelectorComparisonTest, Parameters) {
+  const Comparison& cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const r = (m.*cmp.constructor)(p0, p1);
+  m.Return(r);
+  Stream const s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->OutputAt(0)));
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorComparisonTest, Word32EqualWithZero) {
+  {
+    const Comparison& cmp = GetParam();
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r =
+        m.Word32Equal((m.*cmp.constructor)(p0, p1), m.Int32Constant(0));
+    m.Return(r);
+    Stream const s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->OutputAt(0)));
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(cmp.negated_flags_condition, s[0]->flags_condition());
+  }
+  {
+    const Comparison& cmp = GetParam();
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r =
+        m.Word32Equal(m.Int32Constant(0), (m.*cmp.constructor)(p0, p1));
+    m.Return(r);
+    Stream const s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->OutputAt(0)));
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(cmp.negated_flags_condition, s[0]->flags_condition());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorComparisonTest,
+                        ::testing::ValuesIn(kComparisons));
+
+
+// -----------------------------------------------------------------------------
+// Miscellaneous.
+
+
+TEST_F(InstructionSelectorTest, Float64SubWithMinusZero) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* const p0 = m.Parameter(0);
+  Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmVnegF64, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(p0, m.Int32Mul(p1, p2));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(m.Int32Mul(p1, p2), p0);
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmMla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithInt32MulHigh) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(p0, m.Int32MulHigh(p1, p2));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSmmla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(m.Int32MulHigh(p1, p2), p0);
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSmmla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithWord32And) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(m.Word32And(p0, m.Int32Constant(0xff)), p1);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxtab, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(p1, m.Word32And(p0, m.Int32Constant(0xff)));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxtab, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(m.Word32And(p0, m.Int32Constant(0xffff)), p1);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxtah, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(p1, m.Word32And(p0, m.Int32Constant(0xffff)));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxtah, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithWord32SarWithWord32Shl) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)),
+        p1);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtab, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(
+        p1,
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24)));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtab, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)),
+        p1);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtah, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const r = m.Int32Add(
+        p1,
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16)));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtah, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArmMul, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmSub, s[1]->arch_opcode());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithInt32MulForMLS) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
+  Stream s = m.Build(MLS);
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMls, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(3U, s[0]->InputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32DivWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(4U, s.size());
+  EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+  EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode());
+  ASSERT_EQ(1U, s[3]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32DivWithParametersForSUDIV) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(SUDIV);
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32ModWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(6U, s.size());
+  EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+  EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode());
+  ASSERT_EQ(1U, s[3]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
+  EXPECT_EQ(kArmMul, s[4]->arch_opcode());
+  ASSERT_EQ(1U, s[4]->OutputCount());
+  ASSERT_EQ(2U, s[4]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1)));
+  EXPECT_EQ(kArmSub, s[5]->arch_opcode());
+  ASSERT_EQ(1U, s[5]->OutputCount());
+  ASSERT_EQ(2U, s[5]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIV) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(SUDIV);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(kArmMul, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(kArmSub, s[2]->arch_opcode());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIVAndMLS) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(MLS, SUDIV);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(kArmMls, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_EQ(3U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMul, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulWithImmediate) {
+  // x * (2^k + 1) -> x + (x >> k)
+  TRACED_FORRANGE(int32_t, k, 1, 30) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmAdd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  // x * (2^k - 1) -> -x + (x >> k)
+  TRACED_FORRANGE(int32_t, k, 3, 30) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) - 1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmRsb, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  // (2^k + 1) * x -> x + (x >> k)
+  TRACED_FORRANGE(int32_t, k, 1, 30) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmAdd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  // x * (2^k - 1) -> -x + (x >> k)
+  TRACED_FORRANGE(int32_t, k, 3, 30) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Mul(m.Int32Constant((1 << k) - 1), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmRsb, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmSmmul, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32MulHighWithParameters) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Uint32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmUmull, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(2U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->OutputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32DivWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Div(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(4U, s.size());
+  EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+  EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode());
+  ASSERT_EQ(1U, s[3]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32DivWithParametersForSUDIV) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Div(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(SUDIV);
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32ModWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(6U, s.size());
+  EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+  EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode());
+  ASSERT_EQ(1U, s[3]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
+  EXPECT_EQ(kArmMul, s[4]->arch_opcode());
+  ASSERT_EQ(1U, s[4]->OutputCount());
+  ASSERT_EQ(2U, s[4]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1)));
+  EXPECT_EQ(kArmSub, s[5]->arch_opcode());
+  ASSERT_EQ(1U, s[5]->OutputCount());
+  ASSERT_EQ(2U, s[5]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32ModWithParametersForSUDIV) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(SUDIV);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(kArmMul, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(kArmSub, s[2]->arch_opcode());
+  ASSERT_EQ(1U, s[2]->OutputCount());
+  ASSERT_EQ(2U, s[2]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32ModWithParametersForSUDIVAndMLS) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Uint32Mod(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build(MLS, SUDIV);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(kArmMls, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_EQ(3U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2)));
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) {
+  TRACED_FORRANGE(int32_t, width, 1, 32) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Parameter(0),
+                         m.Int32Constant(0xffffffffu >> (32 - width))));
+    Stream s = m.Build(ARMv7);
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+  }
+  TRACED_FORRANGE(int32_t, width, 1, 32) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
+                         m.Parameter(0)));
+    Stream s = m.Build(ARMv7);
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) {
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 9, (32 - lsb) - 1) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(
+          m.Parameter(0),
+          m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb))));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmBfc, s[0]->arch_opcode());
+      ASSERT_EQ(1U, s[0]->OutputCount());
+      EXPECT_TRUE(
+          UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 9, (32 - lsb) - 1) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(
+          m.Word32And(m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb)),
+                      m.Parameter(0)));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmBfc, s[0]->arch_opcode());
+      ASSERT_EQ(1U, s[0]->OutputCount());
+      EXPECT_TRUE(
+          UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWith0xffff) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r = m.Word32And(p0, m.Int32Constant(0xffff));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxth, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r = m.Word32And(m.Int32Constant(0xffff), p0);
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmUxth, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r =
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxtb, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r =
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSxth, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediateForARMv7) {
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      uint32_t max = 1 << lsb;
+      if (max > static_cast<uint32_t>(kMaxInt)) max -= 1;
+      uint32_t jnk = rng()->NextInt(max);
+      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
+                           m.Int32Constant(lsb)));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      uint32_t max = 1 << lsb;
+      if (max > static_cast<uint32_t>(kMaxInt)) max -= 1;
+      uint32_t jnk = rng()->NextInt(max);
+      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
+                           m.Int32Constant(lsb)));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithWord32Not) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Parameter(0), m.Word32Not(m.Parameter(1))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Word32And(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmBic, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Word32Equal(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithImmediate) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    if (imm == 0) continue;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    if (imm == 0) continue;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(imm), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmTst, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmTst, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  m.Return(m.Word32Not(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) {
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
+                           m.Int32Constant(0xffffffffu >> (32 - width))));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 0, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
+                           m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
+      Stream s = m.Build(ARMv7);
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
new file mode 100644
index 0000000..cd3ce09
--- /dev/null
+++ b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
@@ -0,0 +1,2176 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+typedef RawMachineAssembler::Label MLabel;
+
+template <typename T>
+struct MachInst {
+  T constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  MachineType machine_type;
+};
+
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
+
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
+  return os << mi.constructor_name;
+}
+
+
+struct Shift {
+  MachInst2 mi;
+  AddressingMode mode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Shift& shift) {
+  return os << shift.mi;
+}
+
+
+// Helper to build Int32Constant or Int64Constant depending on the given
+// machine type.
+Node* BuildConstant(InstructionSelectorTest::StreamBuilder& m, MachineType type,
+                    int64_t value) {
+  switch (type) {
+    case kMachInt32:
+      return m.Int32Constant(value);
+      break;
+
+    case kMachInt64:
+      return m.Int64Constant(value);
+      break;
+
+    default:
+      UNIMPLEMENTED();
+  }
+  return NULL;
+}
+
+
+// ARM64 logical instructions.
+static const MachInst2 kLogicalInstructions[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kArm64And32, kMachInt32},
+    {&RawMachineAssembler::Word64And, "Word64And", kArm64And, kMachInt64},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, kMachInt32},
+    {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, kMachInt64},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eor32, kMachInt32},
+    {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eor, kMachInt64}};
+
+
+// ARM64 logical immediates: contiguous set bits, rotated about a power of two
+// sized block. The block is then duplicated across the word. Below is a random
+// subset of the 32-bit immediates.
+static const uint32_t kLogical32Immediates[] = {
+    0x00000002, 0x00000003, 0x00000070, 0x00000080, 0x00000100, 0x000001c0,
+    0x00000300, 0x000007e0, 0x00003ffc, 0x00007fc0, 0x0003c000, 0x0003f000,
+    0x0003ffc0, 0x0003fff8, 0x0007ff00, 0x0007ffe0, 0x000e0000, 0x001e0000,
+    0x001ffffc, 0x003f0000, 0x003f8000, 0x00780000, 0x007fc000, 0x00ff0000,
+    0x01800000, 0x01800180, 0x01f801f8, 0x03fe0000, 0x03ffffc0, 0x03fffffc,
+    0x06000000, 0x07fc0000, 0x07ffc000, 0x07ffffc0, 0x07ffffe0, 0x0ffe0ffe,
+    0x0ffff800, 0x0ffffff0, 0x0fffffff, 0x18001800, 0x1f001f00, 0x1f801f80,
+    0x30303030, 0x3ff03ff0, 0x3ff83ff8, 0x3fff0000, 0x3fff8000, 0x3fffffc0,
+    0x70007000, 0x7f7f7f7f, 0x7fc00000, 0x7fffffc0, 0x8000001f, 0x800001ff,
+    0x81818181, 0x9fff9fff, 0xc00007ff, 0xc0ffffff, 0xdddddddd, 0xe00001ff,
+    0xe00003ff, 0xe007ffff, 0xefffefff, 0xf000003f, 0xf001f001, 0xf3fff3ff,
+    0xf800001f, 0xf80fffff, 0xf87ff87f, 0xfbfbfbfb, 0xfc00001f, 0xfc0000ff,
+    0xfc0001ff, 0xfc03fc03, 0xfe0001ff, 0xff000001, 0xff03ff03, 0xff800000,
+    0xff800fff, 0xff801fff, 0xff87ffff, 0xffc0003f, 0xffc007ff, 0xffcfffcf,
+    0xffe00003, 0xffe1ffff, 0xfff0001f, 0xfff07fff, 0xfff80007, 0xfff87fff,
+    0xfffc00ff, 0xfffe07ff, 0xffff00ff, 0xffffc001, 0xfffff007, 0xfffff3ff,
+    0xfffff807, 0xfffff9ff, 0xfffffc0f, 0xfffffeff};
+
+
+// Random subset of 64-bit logical immediates.
+static const uint64_t kLogical64Immediates[] = {
+    0x0000000000000001, 0x0000000000000002, 0x0000000000000003,
+    0x0000000000000070, 0x0000000000000080, 0x0000000000000100,
+    0x00000000000001c0, 0x0000000000000300, 0x0000000000000600,
+    0x00000000000007e0, 0x0000000000003ffc, 0x0000000000007fc0,
+    0x0000000600000000, 0x0000003ffffffffc, 0x000000f000000000,
+    0x000001f800000000, 0x0003fc0000000000, 0x0003fc000003fc00,
+    0x0003ffffffc00000, 0x0003ffffffffffc0, 0x0006000000060000,
+    0x003ffffffffc0000, 0x0180018001800180, 0x01f801f801f801f8,
+    0x0600000000000000, 0x1000000010000000, 0x1000100010001000,
+    0x1010101010101010, 0x1111111111111111, 0x1f001f001f001f00,
+    0x1f1f1f1f1f1f1f1f, 0x1ffffffffffffffe, 0x3ffc3ffc3ffc3ffc,
+    0x5555555555555555, 0x7f7f7f7f7f7f7f7f, 0x8000000000000000,
+    0x8000001f8000001f, 0x8181818181818181, 0x9999999999999999,
+    0x9fff9fff9fff9fff, 0xaaaaaaaaaaaaaaaa, 0xdddddddddddddddd,
+    0xe0000000000001ff, 0xf800000000000000, 0xf8000000000001ff,
+    0xf807f807f807f807, 0xfefefefefefefefe, 0xfffefffefffefffe,
+    0xfffff807fffff807, 0xfffff9fffffff9ff, 0xfffffc0ffffffc0f,
+    0xfffffc0fffffffff, 0xfffffefffffffeff, 0xfffffeffffffffff,
+    0xffffff8000000000, 0xfffffffefffffffe, 0xffffffffefffffff,
+    0xfffffffff9ffffff, 0xffffffffff800000, 0xffffffffffffc0ff,
+    0xfffffffffffffffe};
+
+
+// ARM64 arithmetic instructions.
+struct AddSub {
+  MachInst2 mi;
+  ArchOpcode negate_arch_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const AddSub& op) {
+  return os << op.mi;
+}
+
+
+static const AddSub kAddSubInstructions[] = {
+    {{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32},
+     kArm64Sub32},
+    {{&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64},
+     kArm64Sub},
+    {{&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32},
+     kArm64Add32},
+    {{&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64},
+     kArm64Add}};
+
+
+// ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12.
+// Below is a combination of a random subset and some edge values.
+static const int32_t kAddSubImmediates[] = {
+    0,        1,        69,       493,      599,      701,      719,
+    768,      818,      842,      945,      1246,     1286,     1429,
+    1669,     2171,     2179,     2182,     2254,     2334,     2338,
+    2343,     2396,     2449,     2610,     2732,     2855,     2876,
+    2944,     3377,     3458,     3475,     3476,     3540,     3574,
+    3601,     3813,     3871,     3917,     4095,     4096,     16384,
+    364544,   462848,   970752,   1523712,  1863680,  2363392,  3219456,
+    3280896,  4247552,  4526080,  4575232,  4960256,  5505024,  5894144,
+    6004736,  6193152,  6385664,  6795264,  7114752,  7233536,  7348224,
+    7499776,  7573504,  7729152,  8634368,  8937472,  9465856,  10354688,
+    10682368, 11059200, 11460608, 13168640, 13176832, 14336000, 15028224,
+    15597568, 15892480, 16773120};
+
+
+// ARM64 flag setting data processing instructions.
+static const MachInst2 kDPFlagSetInstructions[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, kMachInt32},
+    {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, kMachInt32},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, kMachInt32},
+    {&RawMachineAssembler::Word64And, "Word64And", kArm64Tst, kMachInt64}};
+
+
+// ARM64 arithmetic with overflow instructions.
+static const MachInst2 kOvfAddSubInstructions[] = {
+    {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
+     kArm64Add32, kMachInt32},
+    {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
+     kArm64Sub32, kMachInt32}};
+
+
+// ARM64 shift instructions.
+static const Shift kShiftInstructions[] = {
+    {{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Lsl32, kMachInt32},
+     kMode_Operand2_R_LSL_I},
+    {{&RawMachineAssembler::Word64Shl, "Word64Shl", kArm64Lsl, kMachInt64},
+     kMode_Operand2_R_LSL_I},
+    {{&RawMachineAssembler::Word32Shr, "Word32Shr", kArm64Lsr32, kMachInt32},
+     kMode_Operand2_R_LSR_I},
+    {{&RawMachineAssembler::Word64Shr, "Word64Shr", kArm64Lsr, kMachInt64},
+     kMode_Operand2_R_LSR_I},
+    {{&RawMachineAssembler::Word32Sar, "Word32Sar", kArm64Asr32, kMachInt32},
+     kMode_Operand2_R_ASR_I},
+    {{&RawMachineAssembler::Word64Sar, "Word64Sar", kArm64Asr, kMachInt64},
+     kMode_Operand2_R_ASR_I},
+    {{&RawMachineAssembler::Word32Ror, "Word32Ror", kArm64Ror32, kMachInt32},
+     kMode_Operand2_R_ROR_I},
+    {{&RawMachineAssembler::Word64Ror, "Word64Ror", kArm64Ror, kMachInt64},
+     kMode_Operand2_R_ROR_I}};
+
+
+// ARM64 Mul/Div instructions.
+static const MachInst2 kMulDivInstructions[] = {
+    {&RawMachineAssembler::Int32Mul, "Int32Mul", kArm64Mul32, kMachInt32},
+    {&RawMachineAssembler::Int64Mul, "Int64Mul", kArm64Mul, kMachInt64},
+    {&RawMachineAssembler::Int32Div, "Int32Div", kArm64Idiv32, kMachInt32},
+    {&RawMachineAssembler::Int64Div, "Int64Div", kArm64Idiv, kMachInt64},
+    {&RawMachineAssembler::Uint32Div, "Uint32Div", kArm64Udiv32, kMachInt32},
+    {&RawMachineAssembler::Uint64Div, "Uint64Div", kArm64Udiv, kMachInt64}};
+
+
+// ARM64 FP arithmetic instructions.
+static const MachInst2 kFPArithInstructions[] = {
+    {&RawMachineAssembler::Float64Add, "Float64Add", kArm64Float64Add,
+     kMachFloat64},
+    {&RawMachineAssembler::Float64Sub, "Float64Sub", kArm64Float64Sub,
+     kMachFloat64},
+    {&RawMachineAssembler::Float64Mul, "Float64Mul", kArm64Float64Mul,
+     kMachFloat64},
+    {&RawMachineAssembler::Float64Div, "Float64Div", kArm64Float64Div,
+     kMachFloat64}};
+
+
+struct FPCmp {
+  MachInst2 mi;
+  FlagsCondition cond;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const FPCmp& cmp) {
+  return os << cmp.mi;
+}
+
+
+// ARM64 FP comparison instructions.
+static const FPCmp kFPCmpInstructions[] = {
+    {{&RawMachineAssembler::Float64Equal, "Float64Equal", kArm64Float64Cmp,
+      kMachFloat64},
+     kUnorderedEqual},
+    {{&RawMachineAssembler::Float64LessThan, "Float64LessThan",
+      kArm64Float64Cmp, kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
+      kArm64Float64Cmp, kMachFloat64},
+     kUnorderedLessThanOrEqual}};
+
+
+struct Conversion {
+  // The machine_type field in MachInst1 represents the destination type.
+  MachInst1 mi;
+  MachineType src_machine_type;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const Conversion& conv) {
+  return os << conv.mi;
+}
+
+
+// ARM64 type conversion instructions.
+static const Conversion kConversionInstructions[] = {
+    {{&RawMachineAssembler::ChangeFloat32ToFloat64, "ChangeFloat32ToFloat64",
+      kArm64Float32ToFloat64, kMachFloat64},
+     kMachFloat32},
+    {{&RawMachineAssembler::TruncateFloat64ToFloat32,
+      "TruncateFloat64ToFloat32", kArm64Float64ToFloat32, kMachFloat32},
+     kMachFloat64},
+    {{&RawMachineAssembler::ChangeInt32ToInt64, "ChangeInt32ToInt64",
+      kArm64Sxtw, kMachInt64},
+     kMachInt32},
+    {{&RawMachineAssembler::ChangeUint32ToUint64, "ChangeUint32ToUint64",
+      kArm64Mov32, kMachUint64},
+     kMachUint32},
+    {{&RawMachineAssembler::TruncateInt64ToInt32, "TruncateInt64ToInt32",
+      kArm64Mov32, kMachInt32},
+     kMachInt64},
+    {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
+      kArm64Int32ToFloat64, kMachFloat64},
+     kMachInt32},
+    {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
+      kArm64Uint32ToFloat64, kMachFloat64},
+     kMachUint32},
+    {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
+      kArm64Float64ToInt32, kMachInt32},
+     kMachFloat64},
+    {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
+      kArm64Float64ToUint32, kMachUint32},
+     kMachFloat64}};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Logical instructions.
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorLogicalTest;
+
+
+TEST_P(InstructionSelectorLogicalTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorLogicalTest, Immediate) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  // TODO(all): Add support for testing 64-bit immediates.
+  if (type == kMachInt32) {
+    // Immediate on the right.
+    TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
+      StreamBuilder m(this, type, type);
+      m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+
+    // Immediate on the left; all logical ops should commute.
+    TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
+      StreamBuilder m(this, type, type);
+      m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorLogicalTest, ShiftByImmediate) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(Shift, shift, kShiftInstructions) {
+    // Only test 64-bit shifted operands with 64-bit instructions.
+    if (shift.mi.machine_type != type) continue;
+
+    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
+      StreamBuilder m(this, type, type, type);
+      m.Return((m.*dpi.constructor)(
+          m.Parameter(0),
+          (m.*shift.mi.constructor)(m.Parameter(1),
+                                    BuildConstant(m, type, imm))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+
+    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
+      StreamBuilder m(this, type, type, type);
+      m.Return((m.*dpi.constructor)(
+          (m.*shift.mi.constructor)(m.Parameter(1),
+                                    BuildConstant(m, type, imm)),
+          m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
+                        ::testing::ValuesIn(kLogicalInstructions));
+
+
+// -----------------------------------------------------------------------------
+// Add and Sub instructions.
+
+typedef InstructionSelectorTestWithParam<AddSub> InstructionSelectorAddSubTest;
+
+
+TEST_P(InstructionSelectorAddSubTest, Parameter) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    m.Return(
+        (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, NegImmediateOnRight) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    if (imm == 0) continue;
+    StreamBuilder m(this, type, type);
+    m.Return(
+        (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, -imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.negate_arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) {
+  const AddSub dpi = GetParam();
+  const MachineType type = dpi.mi.machine_type;
+  TRACED_FOREACH(Shift, shift, kShiftInstructions) {
+    // Only test 64-bit shifted operands with 64-bit instructions.
+    if (shift.mi.machine_type != type) continue;
+
+    if ((shift.mi.arch_opcode == kArm64Ror32) ||
+        (shift.mi.arch_opcode == kArm64Ror)) {
+      // Not supported by add/sub instructions.
+      continue;
+    }
+
+    TRACED_FORRANGE(int, imm, 0, ((type == kMachInt32) ? 31 : 63)) {
+      StreamBuilder m(this, type, type, type);
+      m.Return((m.*dpi.mi.constructor)(
+          m.Parameter(0),
+          (m.*shift.mi.constructor)(m.Parameter(1),
+                                    BuildConstant(m, type, imm))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest,
+                        ::testing::ValuesIn(kAddSubInstructions));
+
+
+TEST_F(InstructionSelectorTest, AddImmediateOnLeft) {
+  {
+    // 32-bit add.
+    TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+  {
+    // 64-bit add.
+    TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Int64Add(m.Int64Constant(imm), m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
+  // Subtraction with zero on the left maps to Neg.
+  {
+    // 32-bit subtract.
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Sub(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Neg32, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    // 64-bit subtract.
+    StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
+    m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Neg, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddNegImmediateOnLeft) {
+  {
+    // 32-bit add.
+    TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+      if (imm == 0) continue;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(-imm), m.Parameter(0)));
+      Stream s = m.Build();
+
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+  {
+    // 64-bit add.
+    TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+      if (imm == 0) continue;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Int64Add(m.Int64Constant(-imm), m.Parameter(0)));
+      Stream s = m.Build();
+
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Sub, s[0]->arch_opcode());
+      ASSERT_EQ(2U, s[0]->InputCount());
+      ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) {
+  // 32-bit add.
+  TRACED_FOREACH(Shift, shift, kShiftInstructions) {
+    // Only test relevant shifted operands.
+    if (shift.mi.machine_type != kMachInt32) continue;
+    if (shift.mi.arch_opcode == kArm64Ror32) continue;
+
+    TRACED_FORRANGE(int, imm, 0, 31) {
+      StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+      m.Return((m.Int32Add)(
+          (m.*shift.mi.constructor)(m.Parameter(1), m.Int32Constant(imm)),
+          m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+
+  // 64-bit add.
+  TRACED_FOREACH(Shift, shift, kShiftInstructions) {
+    // Only test relevant shifted operands.
+    if (shift.mi.machine_type != kMachInt64) continue;
+    if (shift.mi.arch_opcode == kArm64Ror) continue;
+
+    TRACED_FORRANGE(int, imm, 0, 63) {
+      StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
+      m.Return((m.Int64Add)(
+          (m.*shift.mi.constructor)(m.Parameter(1), m.Int64Constant(imm)),
+          m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Add, s[0]->arch_opcode());
+      EXPECT_EQ(shift.mode, s[0]->addressing_mode());
+      EXPECT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(2)));
+      EXPECT_EQ(1U, s[0]->OutputCount());
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Data processing controlled branches.
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorDPFlagSetTest;
+
+
+TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  MLabel a, b;
+  m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(1));
+  m.Bind(&b);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorDPFlagSetTest,
+                        ::testing::ValuesIn(kDPFlagSetInstructions));
+
+
+TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnRight) {
+  TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
+    // Skip the cases where the instruction selector would use tbz/tbnz.
+    if (base::bits::CountPopulation32(imm) == 1) continue;
+
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnRight) {
+  TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
+    // Skip the cases where the instruction selector would use tbz/tbnz.
+    if (base::bits::CountPopulation64(imm) == 1) continue;
+
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(imm)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndBranchWithImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kLogical32Immediates) {
+    // Skip the cases where the instruction selector would use tbz/tbnz.
+    if (base::bits::CountPopulation32(imm) == 1) continue;
+
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    ASSERT_LE(1U, s[0]->InputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndBranchWithImmediateOnLeft) {
+  TRACED_FOREACH(int64_t, imm, kLogical64Immediates) {
+    // Skip the cases where the instruction selector would use tbz/tbnz.
+    if (base::bits::CountPopulation64(imm) == 1) continue;
+
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(m.Word64And(m.Int64Constant(imm), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    ASSERT_LE(1U, s[0]->InputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
+    ASSERT_LE(1U, s[0]->InputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnRight) {
+  TRACED_FORRANGE(int, bit, 0, 31) {
+    uint32_t mask = 1 << bit;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(mask)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
+  }
+
+  TRACED_FORRANGE(int, bit, 0, 31) {
+    uint32_t mask = 1 << bit;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(
+        m.Word32BinaryNot(m.Word32And(m.Parameter(0), m.Int32Constant(mask))),
+        &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndBranchWithOneBitMaskOnLeft) {
+  TRACED_FORRANGE(int, bit, 0, 31) {
+    uint32_t mask = 1 << bit;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(m.Word32And(m.Int32Constant(mask), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
+  }
+
+  TRACED_FORRANGE(int, bit, 0, 31) {
+    uint32_t mask = 1 << bit;
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    m.Branch(
+        m.Word32BinaryNot(m.Word32And(m.Int32Constant(mask), m.Parameter(0))),
+        &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt32(s[0]->InputAt(1)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) {
+  TRACED_FORRANGE(int, bit, 0, 63) {
+    uint64_t mask = 1L << bit;
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(m.Word64And(m.Parameter(0), m.Int64Constant(mask)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
+  }
+
+  TRACED_FORRANGE(int, bit, 0, 63) {
+    uint64_t mask = 1L << bit;
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(
+        m.Word64BinaryNot(m.Word64And(m.Parameter(0), m.Int64Constant(mask))),
+        &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) {
+  TRACED_FORRANGE(int, bit, 0, 63) {
+    uint64_t mask = 1L << bit;
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(m.Word64And(m.Int64Constant(mask), m.Parameter(0)), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
+  }
+
+  TRACED_FORRANGE(int, bit, 0, 63) {
+    uint64_t mask = 1L << bit;
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    MLabel a, b;
+    m.Branch(
+        m.Word64BinaryNot(m.Word64And(m.Int64Constant(mask), m.Parameter(0))),
+        &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1)));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, CompareAgainstZeroAndBranch) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* p0 = m.Parameter(0);
+    m.Branch(p0, &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kNotEqual, s[0]->flags_condition());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  }
+
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* p0 = m.Parameter(0);
+    m.Branch(m.Word32BinaryNot(p0), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(1));
+    m.Bind(&b);
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64CompareAndBranch32, s[0]->arch_opcode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Add and subtract instructions with overflow.
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorOvfAddSubTest;
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return(
+      m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    m.Return(m.Projection(
+        1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return(
+      m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    m.Return(m.Projection(
+        0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+  Stream s = m.Build();
+  ASSERT_LE(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(2U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  MLabel a, b;
+  Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
+  m.Branch(m.Projection(1, n), &a, &b);
+  m.Bind(&a);
+  m.Return(m.Int32Constant(0));
+  m.Bind(&b);
+  m.Return(m.Projection(0, n));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(4U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+  EXPECT_EQ(kOverflow, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, type, type);
+    MLabel a, b;
+    Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
+    m.Branch(m.Projection(1, n), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(0));
+    m.Bind(&b);
+    m.Return(m.Projection(0, n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorOvfAddSubTest,
+                        ::testing::ValuesIn(kOvfAddSubInstructions));
+
+
+TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Projection(
+        0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_LE(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_none, s[0]->flags_mode());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
+    m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
+    Stream s = m.Build();
+
+    ASSERT_LE(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(2U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    MLabel a, b;
+    Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
+    m.Branch(m.Projection(1, n), &a, &b);
+    m.Bind(&a);
+    m.Return(m.Int32Constant(0));
+    m.Bind(&b);
+    m.Return(m.Projection(0, n));
+    Stream s = m.Build();
+
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
+    ASSERT_EQ(4U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
+    EXPECT_EQ(kOverflow, s[0]->flags_condition());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Shift instructions.
+
+
+typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest;
+
+
+TEST_P(InstructionSelectorShiftTest, Parameter) {
+  const Shift shift = GetParam();
+  const MachineType type = shift.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorShiftTest, Immediate) {
+  const Shift shift = GetParam();
+  const MachineType type = shift.mi.machine_type;
+  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
+    StreamBuilder m(this, type, type);
+    m.Return((m.*shift.mi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(shift.mi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
+                        ::testing::ValuesIn(kShiftInstructions));
+
+
+TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt64, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt64, kMachUint32);
+    Node* const p0 = m.Parameter(0);
+    Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Lsl, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  Node* const p = m.Parameter(0);
+  Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32)));
+  m.Return(t);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt64(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt32, kMachInt64);
+    Node* const p = m.Parameter(0);
+    Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(x)));
+    m.Return(t);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Lsr, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt64(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Mul and Div instructions.
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorMulDivTest;
+
+
+TEST_P(InstructionSelectorMulDivTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
+                        ::testing::ValuesIn(kMulDivInstructions));
+
+
+namespace {
+
+struct MulDPInst {
+  const char* mul_constructor_name;
+  Node* (RawMachineAssembler::*mul_constructor)(Node*, Node*);
+  Node* (RawMachineAssembler::*add_constructor)(Node*, Node*);
+  Node* (RawMachineAssembler::*sub_constructor)(Node*, Node*);
+  ArchOpcode add_arch_opcode;
+  ArchOpcode sub_arch_opcode;
+  ArchOpcode neg_arch_opcode;
+  MachineType machine_type;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MulDPInst& inst) {
+  return os << inst.mul_constructor_name;
+}
+
+}  // namespace
+
+
+static const MulDPInst kMulDPInstructions[] = {
+    {"Int32Mul", &RawMachineAssembler::Int32Mul, &RawMachineAssembler::Int32Add,
+     &RawMachineAssembler::Int32Sub, kArm64Madd32, kArm64Msub32, kArm64Mneg32,
+     kMachInt32},
+    {"Int64Mul", &RawMachineAssembler::Int64Mul, &RawMachineAssembler::Int64Add,
+     &RawMachineAssembler::Int64Sub, kArm64Madd, kArm64Msub, kArm64Mneg,
+     kMachInt64}};
+
+
+typedef InstructionSelectorTestWithParam<MulDPInst>
+    InstructionSelectorIntDPWithIntMulTest;
+
+
+TEST_P(InstructionSelectorIntDPWithIntMulTest, AddWithMul) {
+  const MulDPInst mdpi = GetParam();
+  const MachineType type = mdpi.machine_type;
+  {
+    StreamBuilder m(this, type, type, type, type);
+    Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
+    m.Return((m.*mdpi.add_constructor)(m.Parameter(0), n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, type, type, type, type);
+    Node* n = (m.*mdpi.mul_constructor)(m.Parameter(0), m.Parameter(1));
+    m.Return((m.*mdpi.add_constructor)(n, m.Parameter(2)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.add_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorIntDPWithIntMulTest, SubWithMul) {
+  const MulDPInst mdpi = GetParam();
+  const MachineType type = mdpi.machine_type;
+  {
+    StreamBuilder m(this, type, type, type, type);
+    Node* n = (m.*mdpi.mul_constructor)(m.Parameter(1), m.Parameter(2));
+    m.Return((m.*mdpi.sub_constructor)(m.Parameter(0), n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.sub_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorIntDPWithIntMulTest, NegativeMul) {
+  const MulDPInst mdpi = GetParam();
+  const MachineType type = mdpi.machine_type;
+  {
+    StreamBuilder m(this, type, type, type);
+    Node* n =
+        (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(0));
+    m.Return((m.*mdpi.mul_constructor)(n, m.Parameter(1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, type, type, type);
+    Node* n =
+        (m.*mdpi.sub_constructor)(BuildConstant(m, type, 0), m.Parameter(1));
+    m.Return((m.*mdpi.mul_constructor)(m.Parameter(0), n));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(mdpi.neg_arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntDPWithIntMulTest,
+                        ::testing::ValuesIn(kMulDPInstructions));
+
+
+// -----------------------------------------------------------------------------
+// Floating point instructions.
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorFPArithTest;
+
+
+TEST_P(InstructionSelectorFPArithTest, Parameter) {
+  const MachInst2 fpa = GetParam();
+  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
+  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
+                        ::testing::ValuesIn(kFPArithInstructions));
+
+
+typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
+
+
+TEST_P(InstructionSelectorFPCmpTest, Parameter) {
+  const FPCmp cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
+                        ::testing::ValuesIn(kFPCmpInstructions));
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+typedef InstructionSelectorTestWithParam<Conversion>
+    InstructionSelectorConversionTest;
+
+
+TEST_P(InstructionSelectorConversionTest, Parameter) {
+  const Conversion conv = GetParam();
+  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
+  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorConversionTest,
+                        ::testing::ValuesIn(kConversionInstructions));
+
+
+// -----------------------------------------------------------------------------
+// Memory access instructions.
+
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode ldr_opcode;
+  ArchOpcode str_opcode;
+  const int32_t immediates[20];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
+  return os << memacc.type;
+}
+
+}  // namespace
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8,
+     kArm64Ldrsb,
+     kArm64Strb,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121,
+      2442, 4093, 4094, 4095}},
+    {kMachUint8,
+     kArm64Ldrb,
+     kArm64Strb,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 257, 258, 1000, 1001, 2121,
+      2442, 4093, 4094, 4095}},
+    {kMachInt16,
+     kArm64Ldrsh,
+     kArm64Strh,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100,
+      4242, 6786, 8188, 8190}},
+    {kMachUint16,
+     kArm64Ldrh,
+     kArm64Strh,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 258, 260, 4096, 4098, 4100,
+      4242, 6786, 8188, 8190}},
+    {kMachInt32,
+     kArm64LdrW,
+     kArm64StrW,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
+      3276, 3280, 16376, 16380}},
+    {kMachUint32,
+     kArm64LdrW,
+     kArm64StrW,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
+      3276, 3280, 16376, 16380}},
+    {kMachInt64,
+     kArm64Ldr,
+     kArm64Str,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
+      16384, 16392, 32752, 32760}},
+    {kMachUint64,
+     kArm64Ldr,
+     kArm64Str,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
+      16384, 16392, 32752, 32760}},
+    {kMachFloat32,
+     kArm64LdrS,
+     kArm64StrS,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 260, 4096, 4100, 8192, 8196,
+      3276, 3280, 16376, 16380}},
+    {kMachFloat64,
+     kArm64LdrD,
+     kArm64StrD,
+     {-256, -255, -3, -2, -1, 0, 1, 2, 3, 255, 256, 264, 4096, 4104, 8192, 8200,
+      16384, 16392, 32752, 32760}}};
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRR, s[0]->addressing_mode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(0U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// -----------------------------------------------------------------------------
+// Comparison instructions.
+
+static const MachInst2 kComparisonInstructions[] = {
+    {&RawMachineAssembler::Word32Equal, "Word32Equal", kArm64Cmp32, kMachInt32},
+    {&RawMachineAssembler::Word64Equal, "Word64Equal", kArm64Cmp, kMachInt64},
+};
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorComparisonTest;
+
+
+TEST_P(InstructionSelectorComparisonTest, WithParameters) {
+  const MachInst2 cmp = GetParam();
+  const MachineType type = cmp.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(kEqual, s[0]->flags_condition());
+}
+
+
+TEST_P(InstructionSelectorComparisonTest, WithImmediate) {
+  const MachInst2 cmp = GetParam();
+  const MachineType type = cmp.machine_type;
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    // Compare with 0 are turned into tst instruction.
+    if (imm == 0) continue;
+    StreamBuilder m(this, type, type);
+    m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type, imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
+    // Compare with 0 are turned into tst instruction.
+    if (imm == 0) continue;
+    StreamBuilder m(this, type, type);
+    m.Return((m.*cmp.constructor)(BuildConstant(m, type, imm), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorComparisonTest,
+                        ::testing::ValuesIn(kComparisonInstructions));
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Equal(m.Int64Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Tst, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Miscellaneous
+
+
+static const MachInst2 kLogicalWithNotRHSs[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32, kMachInt32},
+    {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, kMachInt64},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32, kMachInt32},
+    {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn, kMachInt64},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32, kMachInt32},
+    {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon, kMachInt64}};
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorLogicalWithNotRHSTest;
+
+
+TEST_P(InstructionSelectorLogicalWithNotRHSTest, Parameter) {
+  const MachInst2 inst = GetParam();
+  const MachineType type = inst.machine_type;
+  // Test cases where RHS is Xor(x, -1).
+  {
+    StreamBuilder m(this, type, type, type);
+    if (type == kMachInt32) {
+      m.Return((m.*inst.constructor)(
+          m.Parameter(0), m.Word32Xor(m.Parameter(1), m.Int32Constant(-1))));
+    } else {
+      ASSERT_EQ(kMachInt64, type);
+      m.Return((m.*inst.constructor)(
+          m.Parameter(0), m.Word64Xor(m.Parameter(1), m.Int64Constant(-1))));
+    }
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, type, type, type);
+    if (type == kMachInt32) {
+      m.Return((m.*inst.constructor)(
+          m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), m.Parameter(1)));
+    } else {
+      ASSERT_EQ(kMachInt64, type);
+      m.Return((m.*inst.constructor)(
+          m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)), m.Parameter(1)));
+    }
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  // Test cases where RHS is Not(x).
+  {
+    StreamBuilder m(this, type, type, type);
+    if (type == kMachInt32) {
+      m.Return(
+          (m.*inst.constructor)(m.Parameter(0), m.Word32Not(m.Parameter(1))));
+    } else {
+      ASSERT_EQ(kMachInt64, type);
+      m.Return(
+          (m.*inst.constructor)(m.Parameter(0), m.Word64Not(m.Parameter(1))));
+    }
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, type, type, type);
+    if (type == kMachInt32) {
+      m.Return(
+          (m.*inst.constructor)(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
+    } else {
+      ASSERT_EQ(kMachInt64, type);
+      m.Return(
+          (m.*inst.constructor)(m.Word64Not(m.Parameter(0)), m.Parameter(1)));
+    }
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorLogicalWithNotRHSTest,
+                        ::testing::ValuesIn(kLogicalWithNotRHSs));
+
+
+TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  m.Return(m.Word32Not(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Word64NotWithParameter) {
+  StreamBuilder m(this, kMachInt64, kMachInt64);
+  m.Return(m.Word64Not(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) {
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+    EXPECT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediate) {
+  TRACED_FORRANGE(int32_t, lsb, 1, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      uint32_t jnk = rng()->NextInt();
+      jnk >>= 32 - lsb;
+      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
+                           m.Int32Constant(lsb)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 1, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
+      uint32_t jnk = rng()->NextInt();
+      jnk >>= 32 - lsb;
+      uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
+                           m.Int32Constant(lsb)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) {
+  TRACED_FORRANGE(int32_t, lsb, 1, 63) {
+    TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
+      uint64_t jnk = rng()->NextInt64();
+      jnk >>= 64 - lsb;
+      uint64_t msk =
+          ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Word64Shr(m.Word64And(m.Parameter(0), m.Int64Constant(msk)),
+                           m.Int64Constant(lsb)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 1, 63) {
+    TRACED_FORRANGE(int32_t, width, 1, 64 - lsb) {
+      uint64_t jnk = rng()->NextInt64();
+      jnk >>= 64 - lsb;
+      uint64_t msk =
+          ((V8_UINT64_C(0xffffffffffffffff) >> (64 - width)) << lsb) | jnk;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Word64Shr(m.Word64And(m.Int64Constant(msk), m.Parameter(0)),
+                           m.Int64Constant(lsb)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
+      EXPECT_EQ(width, s.ToInt64(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) {
+  TRACED_FORRANGE(int32_t, lsb, 1, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 31) {
+      uint32_t msk = (1 << width) - 1;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
+                           m.Int32Constant(msk)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
+      EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, lsb, 1, 31) {
+    TRACED_FORRANGE(int32_t, width, 1, 31) {
+      uint32_t msk = (1 << width) - 1;
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Word32And(m.Int32Constant(msk),
+                           m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx32, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
+      int32_t actual_width = (lsb + width > 32) ? (32 - lsb) : width;
+      EXPECT_EQ(actual_width, s.ToInt32(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) {
+  TRACED_FORRANGE(int64_t, lsb, 1, 63) {
+    TRACED_FORRANGE(int64_t, width, 1, 63) {
+      uint64_t msk = (V8_UINT64_C(1) << width) - 1;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Word64And(m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb)),
+                           m.Int64Constant(msk)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
+      int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
+      EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
+    }
+  }
+  TRACED_FORRANGE(int64_t, lsb, 1, 63) {
+    TRACED_FORRANGE(int64_t, width, 1, 63) {
+      uint64_t msk = (V8_UINT64_C(1) << width) - 1;
+      StreamBuilder m(this, kMachInt64, kMachInt64);
+      m.Return(m.Word64And(m.Int64Constant(msk),
+                           m.Word64Shr(m.Parameter(0), m.Int64Constant(lsb))));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kArm64Ubfx, s[0]->arch_opcode());
+      ASSERT_EQ(3U, s[0]->InputCount());
+      EXPECT_EQ(lsb, s.ToInt64(s[0]->InputAt(1)));
+      int64_t actual_width = (lsb + width > 64) ? (64 - lsb) : width;
+      EXPECT_EQ(actual_width, s.ToInt64(s[0]->InputAt(2)));
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArm64Smull, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArm64Asr, s[1]->arch_opcode());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(1)));
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output()));
+}
+
+
+TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r =
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Sxtb32, s[0]->arch_opcode());
+    ASSERT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const r =
+        m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
+    m.Return(r);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArm64Sxth32, s[0]->arch_opcode());
+    ASSERT_EQ(1U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/change-lowering-unittest.cc b/test/unittests/compiler/change-lowering-unittest.cc
new file mode 100644
index 0000000..060b1c1
--- /dev/null
+++ b/test/unittests/compiler/change-lowering-unittest.cc
@@ -0,0 +1,463 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/code-stubs.h"
+#include "src/compiler/change-lowering.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/linkage.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::_;
+using testing::AllOf;
+using testing::BitEq;
+using testing::Capture;
+using testing::CaptureEq;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class ChangeLoweringTest : public GraphTest {
+ public:
+  ChangeLoweringTest() : simplified_(zone()) {}
+  ~ChangeLoweringTest() OVERRIDE {}
+
+  virtual MachineType WordRepresentation() const = 0;
+
+ protected:
+  int HeapNumberValueOffset() const {
+    STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
+    return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() -
+           kHeapObjectTag;
+  }
+  bool Is32() const { return WordRepresentation() == kRepWord32; }
+  int PointerSize() const {
+    switch (WordRepresentation()) {
+      case kRepWord32:
+        return 4;
+      case kRepWord64:
+        return 8;
+      default:
+        break;
+    }
+    UNREACHABLE();
+    return 0;
+  }
+  int SmiMaxValue() const { return -(SmiMinValue() + 1); }
+  int SmiMinValue() const {
+    return static_cast<int>(0xffffffffu << (SmiValueSize() - 1));
+  }
+  int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
+  int SmiShiftSize() const {
+    return Is32() ? SmiTagging<4>::SmiShiftSize()
+                  : SmiTagging<8>::SmiShiftSize();
+  }
+  int SmiValueSize() const {
+    return Is32() ? SmiTagging<4>::SmiValueSize()
+                  : SmiTagging<8>::SmiValueSize();
+  }
+
+  Reduction Reduce(Node* node) {
+    MachineOperatorBuilder machine(zone(), WordRepresentation());
+    JSOperatorBuilder javascript(zone());
+    JSGraph jsgraph(graph(), common(), &javascript, &machine);
+    CompilationInfo info(isolate(), zone());
+    Linkage linkage(zone(), &info);
+    ChangeLowering reducer(&jsgraph, &linkage);
+    return reducer.Reduce(node);
+  }
+
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
+
+  Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
+                                      const Matcher<Node*>& control_matcher) {
+    return IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
+                         AllocateHeapNumberStub(isolate()).GetCode())),
+                  IsNumberConstant(BitEq(0.0)), effect_matcher,
+                  control_matcher);
+  }
+  Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher,
+                                  const Matcher<Node*>& control_matcher) {
+    return IsLoad(kMachFloat64, value_matcher,
+                  IsIntPtrConstant(HeapNumberValueOffset()), graph()->start(),
+                  control_matcher);
+  }
+  Matcher<Node*> IsIntPtrConstant(int value) {
+    return Is32() ? IsInt32Constant(value) : IsInt64Constant(value);
+  }
+  Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher) {
+    return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher)
+                  : IsWord64Equal(lhs_matcher, rhs_matcher);
+  }
+
+ private:
+  SimplifiedOperatorBuilder simplified_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Common.
+
+
+class ChangeLoweringCommonTest
+    : public ChangeLoweringTest,
+      public ::testing::WithParamInterface<MachineType> {
+ public:
+  ~ChangeLoweringCommonTest() OVERRIDE {}
+
+  MachineType WordRepresentation() const FINAL { return GetParam(); }
+};
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeBitToBool(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(),
+              IsSelect(static_cast<MachineType>(kTypeBool | kRepTagged), val,
+                       IsTrueConstant(), IsFalseConstant()));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBoolToBit) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant()));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, ChangeFloat64ToTagged) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeFloat64ToTagged(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* finish = reduction.replacement();
+  Capture<Node*> heap_number;
+  EXPECT_THAT(
+      finish,
+      IsFinish(
+          AllOf(CaptureEq(&heap_number),
+                IsAllocateHeapNumber(IsValueEffect(val), graph()->start())),
+          IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
+                  CaptureEq(&heap_number),
+                  IsIntPtrConstant(HeapNumberValueOffset()), val,
+                  CaptureEq(&heap_number), graph()->start())));
+}
+
+
+TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) {
+  Node* node =
+      graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
+  Reduction reduction = Reduce(node);
+  EXPECT_FALSE(reduction.Changed());
+}
+
+
+INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
+                        ::testing::Values(kRepWord32, kRepWord64));
+
+
+// -----------------------------------------------------------------------------
+// 32-bit
+
+
+class ChangeLowering32Test : public ChangeLoweringTest {
+ public:
+  ~ChangeLowering32Test() OVERRIDE {}
+  MachineType WordRepresentation() const FINAL { return kRepWord32; }
+};
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
+  NodeProperties::SetBounds(val, Bounds(Type::None(), Type::Signed32()));
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> add, branch, heap_number, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachAnyTagged,
+            IsFinish(AllOf(CaptureEq(&heap_number),
+                           IsAllocateHeapNumber(_, CaptureEq(&if_true))),
+                     IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
+                             CaptureEq(&heap_number),
+                             IsIntPtrConstant(HeapNumberValueOffset()),
+                             IsChangeInt32ToFloat64(val),
+                             CaptureEq(&heap_number), CaptureEq(&if_true))),
+            IsProjection(
+                0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(CaptureEq(&branch),
+                                    IsBranch(IsProjection(1, CaptureEq(&add)),
+                                             graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTaggedSmall) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
+  NodeProperties::SetBounds(val, Bounds(Type::None(), Type::SignedSmall()));
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* change = reduction.replacement();
+  Capture<Node*> add, branch, heap_number, if_true;
+  EXPECT_THAT(change, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)),
+          IsChangeInt32ToFloat64(
+              IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
+          IsMerge(
+              AllOf(CaptureEq(&if_true),
+                    IsIfTrue(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start())))),
+              IsIfFalse(CaptureEq(&branch)))));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachInt32,
+            IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
+            IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachUint32,
+            IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
+            IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, heap_number, if_false;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())),
+          IsFinish(AllOf(CaptureEq(&heap_number),
+                         IsAllocateHeapNumber(_, CaptureEq(&if_false))),
+                   IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
+                           CaptureEq(&heap_number),
+                           IsInt32Constant(HeapNumberValueOffset()),
+                           IsChangeUint32ToFloat64(val),
+                           CaptureEq(&heap_number), CaptureEq(&if_false))),
+          IsMerge(
+              IsIfTrue(AllOf(CaptureEq(&branch),
+                             IsBranch(IsUint32LessThanOrEqual(
+                                          val, IsInt32Constant(SmiMaxValue())),
+                                      graph()->start()))),
+              AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
+}
+
+
+// -----------------------------------------------------------------------------
+// 64-bit
+
+
+class ChangeLowering64Test : public ChangeLoweringTest {
+ public:
+  ~ChangeLowering64Test() OVERRIDE {}
+  MachineType WordRepresentation() const FINAL { return kRepWord64; }
+};
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  EXPECT_THAT(reduction.replacement(),
+              IsWord64Shl(IsChangeInt32ToInt64(val),
+                          IsInt64Constant(SmiShiftAmount())));
+}
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)),
+          IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(
+              IsWord64Sar(val, IsInt64Constant(SmiShiftAmount())))),
+          IsMerge(
+              AllOf(CaptureEq(&if_true),
+                    IsIfTrue(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
+                                 graph()->start())))),
+              IsIfFalse(CaptureEq(&branch)))));
+}
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachInt32,
+            IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
+            IsTruncateInt64ToInt32(
+                IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(kMachUint32,
+            IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
+            IsTruncateInt64ToInt32(
+                IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, heap_number, if_false;
+  EXPECT_THAT(
+      phi,
+      IsPhi(
+          kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val),
+                                      IsInt64Constant(SmiShiftAmount())),
+          IsFinish(AllOf(CaptureEq(&heap_number),
+                         IsAllocateHeapNumber(_, CaptureEq(&if_false))),
+                   IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
+                           CaptureEq(&heap_number),
+                           IsInt64Constant(HeapNumberValueOffset()),
+                           IsChangeUint32ToFloat64(val),
+                           CaptureEq(&heap_number), CaptureEq(&if_false))),
+          IsMerge(
+              IsIfTrue(AllOf(CaptureEq(&branch),
+                             IsBranch(IsUint32LessThanOrEqual(
+                                          val, IsInt32Constant(SmiMaxValue())),
+                                      graph()->start()))),
+              AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/common-operator-reducer-unittest.cc b/test/unittests/compiler/common-operator-reducer-unittest.cc
new file mode 100644
index 0000000..c713815
--- /dev/null
+++ b/test/unittests/compiler/common-operator-reducer-unittest.cc
@@ -0,0 +1,110 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/common-operator-reducer.h"
+#include "src/compiler/machine-type.h"
+#include "test/unittests/compiler/graph-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class CommonOperatorReducerTest : public GraphTest {
+ public:
+  explicit CommonOperatorReducerTest(int num_parameters = 1)
+      : GraphTest(num_parameters) {}
+  ~CommonOperatorReducerTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    CommonOperatorReducer reducer;
+    return reducer.Reduce(node);
+  }
+};
+
+
+namespace {
+
+const BranchHint kBranchHints[] = {BranchHint::kNone, BranchHint::kFalse,
+                                   BranchHint::kTrue};
+
+
+const MachineType kMachineTypes[] = {
+    kMachFloat32, kMachFloat64,   kMachInt8,   kMachUint8,  kMachInt16,
+    kMachUint16,  kMachInt32,     kMachUint32, kMachInt64,  kMachUint64,
+    kMachPtr,     kMachAnyTagged, kRepBit,     kRepWord8,   kRepWord16,
+    kRepWord32,   kRepWord64,     kRepFloat32, kRepFloat64, kRepTagged};
+
+
+const Operator kOp0(0, Operator::kNoProperties, "Op0", 0, 0, 0, 1, 1, 0);
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// EffectPhi
+
+
+TEST_F(CommonOperatorReducerTest, RedundantEffectPhi) {
+  const int kMaxInputs = 64;
+  Node* inputs[kMaxInputs];
+  Node* const input = graph()->NewNode(&kOp0);
+  TRACED_FORRANGE(int, input_count, 2, kMaxInputs - 1) {
+    int const value_input_count = input_count - 1;
+    for (int i = 0; i < value_input_count; ++i) {
+      inputs[i] = input;
+    }
+    inputs[value_input_count] = graph()->start();
+    Reduction r = Reduce(graph()->NewNode(
+        common()->EffectPhi(value_input_count), input_count, inputs));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(input, r.replacement());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Phi
+
+
+TEST_F(CommonOperatorReducerTest, RedundantPhi) {
+  const int kMaxInputs = 64;
+  Node* inputs[kMaxInputs];
+  Node* const input = graph()->NewNode(&kOp0);
+  TRACED_FORRANGE(int, input_count, 2, kMaxInputs - 1) {
+    int const value_input_count = input_count - 1;
+    TRACED_FOREACH(MachineType, type, kMachineTypes) {
+      for (int i = 0; i < value_input_count; ++i) {
+        inputs[i] = input;
+      }
+      inputs[value_input_count] = graph()->start();
+      Reduction r = Reduce(graph()->NewNode(
+          common()->Phi(type, value_input_count), input_count, inputs));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_EQ(input, r.replacement());
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Select
+
+
+TEST_F(CommonOperatorReducerTest, RedundantSelect) {
+  Node* const input = graph()->NewNode(&kOp0);
+  TRACED_FOREACH(BranchHint, hint, kBranchHints) {
+    TRACED_FOREACH(MachineType, type, kMachineTypes) {
+      Reduction r = Reduce(
+          graph()->NewNode(common()->Select(type, hint), input, input, input));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_EQ(input, r.replacement());
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/common-operator-unittest.cc b/test/unittests/compiler/common-operator-unittest.cc
new file mode 100644
index 0000000..d0ac145
--- /dev/null
+++ b/test/unittests/compiler/common-operator-unittest.cc
@@ -0,0 +1,293 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+
+// -----------------------------------------------------------------------------
+// Shared operators.
+
+
+namespace {
+
+struct SharedOperator {
+  const Operator* (CommonOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  Operator::Properties properties;
+  int value_input_count;
+  int effect_input_count;
+  int control_input_count;
+  int effect_output_count;
+  int control_output_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const SharedOperator& fop) {
+  return os << IrOpcode::Mnemonic(fop.opcode);
+}
+
+
+const SharedOperator kSharedOperators[] = {
+#define SHARED(Name, properties, value_input_count, effect_input_count,        \
+               control_input_count, effect_output_count, control_output_count) \
+  {                                                                            \
+    &CommonOperatorBuilder::Name, IrOpcode::k##Name, properties,               \
+        value_input_count, effect_input_count, control_input_count,            \
+        effect_output_count, control_output_count                              \
+  }
+    SHARED(Dead, Operator::kFoldable, 0, 0, 0, 0, 1),
+    SHARED(End, Operator::kFoldable, 0, 0, 1, 0, 0),
+    SHARED(IfTrue, Operator::kFoldable, 0, 0, 1, 0, 1),
+    SHARED(IfFalse, Operator::kFoldable, 0, 0, 1, 0, 1),
+    SHARED(Throw, Operator::kFoldable, 1, 1, 1, 0, 1),
+    SHARED(Return, Operator::kNoProperties, 1, 1, 1, 0, 1)
+#undef SHARED
+};
+
+
+class CommonSharedOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<SharedOperator> {};
+
+}  // namespace
+
+
+TEST_P(CommonSharedOperatorTest, InstancesAreGloballyShared) {
+  const SharedOperator& sop = GetParam();
+  CommonOperatorBuilder common1(zone());
+  CommonOperatorBuilder common2(zone());
+  EXPECT_EQ((common1.*sop.constructor)(), (common2.*sop.constructor)());
+}
+
+
+TEST_P(CommonSharedOperatorTest, NumberOfInputsAndOutputs) {
+  CommonOperatorBuilder common(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (common.*sop.constructor)();
+
+  EXPECT_EQ(sop.value_input_count, op->ValueInputCount());
+  EXPECT_EQ(sop.effect_input_count, op->EffectInputCount());
+  EXPECT_EQ(sop.control_input_count, op->ControlInputCount());
+  EXPECT_EQ(
+      sop.value_input_count + sop.effect_input_count + sop.control_input_count,
+      OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(sop.effect_output_count, op->EffectOutputCount());
+  EXPECT_EQ(sop.control_output_count, op->ControlOutputCount());
+}
+
+
+TEST_P(CommonSharedOperatorTest, OpcodeIsCorrect) {
+  CommonOperatorBuilder common(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (common.*sop.constructor)();
+  EXPECT_EQ(sop.opcode, op->opcode());
+}
+
+
+TEST_P(CommonSharedOperatorTest, Properties) {
+  CommonOperatorBuilder common(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (common.*sop.constructor)();
+  EXPECT_EQ(sop.properties, op->properties());
+}
+
+
+INSTANTIATE_TEST_CASE_P(CommonOperatorTest, CommonSharedOperatorTest,
+                        ::testing::ValuesIn(kSharedOperators));
+
+
+// -----------------------------------------------------------------------------
+// Other operators.
+
+
+namespace {
+
+class CommonOperatorTest : public TestWithZone {
+ public:
+  CommonOperatorTest() : common_(zone()) {}
+  ~CommonOperatorTest() OVERRIDE {}
+
+  CommonOperatorBuilder* common() { return &common_; }
+
+ private:
+  CommonOperatorBuilder common_;
+};
+
+
+const int kArguments[] = {1, 5, 6, 42, 100, 10000, 65000};
+
+
+const float kFloatValues[] = {-std::numeric_limits<float>::infinity(),
+                              std::numeric_limits<float>::min(),
+                              -1.0f,
+                              -0.0f,
+                              0.0f,
+                              1.0f,
+                              std::numeric_limits<float>::max(),
+                              std::numeric_limits<float>::infinity(),
+                              std::numeric_limits<float>::quiet_NaN(),
+                              std::numeric_limits<float>::signaling_NaN()};
+
+
+const double kDoubleValues[] = {-std::numeric_limits<double>::infinity(),
+                                std::numeric_limits<double>::min(),
+                                -1.0,
+                                -0.0,
+                                0.0,
+                                1.0,
+                                std::numeric_limits<double>::max(),
+                                std::numeric_limits<double>::infinity(),
+                                std::numeric_limits<double>::quiet_NaN(),
+                                std::numeric_limits<double>::signaling_NaN()};
+
+
+const BranchHint kHints[] = {BranchHint::kNone, BranchHint::kTrue,
+                             BranchHint::kFalse};
+
+}  // namespace
+
+
+TEST_F(CommonOperatorTest, Branch) {
+  TRACED_FOREACH(BranchHint, hint, kHints) {
+    const Operator* const op = common()->Branch(hint);
+    EXPECT_EQ(IrOpcode::kBranch, op->opcode());
+    EXPECT_EQ(Operator::kFoldable, op->properties());
+    EXPECT_EQ(hint, BranchHintOf(op));
+    EXPECT_EQ(1, op->ValueInputCount());
+    EXPECT_EQ(0, op->EffectInputCount());
+    EXPECT_EQ(1, op->ControlInputCount());
+    EXPECT_EQ(2, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ValueOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(2, op->ControlOutputCount());
+  }
+}
+
+
+TEST_F(CommonOperatorTest, Select) {
+  static const MachineType kTypes[] = {
+      kMachInt8,    kMachUint8,   kMachInt16,    kMachUint16,
+      kMachInt32,   kMachUint32,  kMachInt64,    kMachUint64,
+      kMachFloat32, kMachFloat64, kMachAnyTagged};
+  TRACED_FOREACH(MachineType, type, kTypes) {
+    TRACED_FOREACH(BranchHint, hint, kHints) {
+      const Operator* const op = common()->Select(type, hint);
+      EXPECT_EQ(IrOpcode::kSelect, op->opcode());
+      EXPECT_EQ(Operator::kPure, op->properties());
+      EXPECT_EQ(type, SelectParametersOf(op).type());
+      EXPECT_EQ(hint, SelectParametersOf(op).hint());
+      EXPECT_EQ(3, op->ValueInputCount());
+      EXPECT_EQ(0, op->EffectInputCount());
+      EXPECT_EQ(0, op->ControlInputCount());
+      EXPECT_EQ(3, OperatorProperties::GetTotalInputCount(op));
+      EXPECT_EQ(1, op->ValueOutputCount());
+      EXPECT_EQ(0, op->EffectOutputCount());
+      EXPECT_EQ(0, op->ControlOutputCount());
+    }
+  }
+}
+
+
+TEST_F(CommonOperatorTest, Float32Constant) {
+  TRACED_FOREACH(float, value, kFloatValues) {
+    const Operator* op = common()->Float32Constant(value);
+    EXPECT_PRED2(base::bit_equal_to<float>(), value, OpParameter<float>(op));
+    EXPECT_EQ(0, op->ValueInputCount());
+    EXPECT_EQ(0, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->ValueOutputCount());
+  }
+  TRACED_FOREACH(float, v1, kFloatValues) {
+    TRACED_FOREACH(float, v2, kFloatValues) {
+      const Operator* op1 = common()->Float32Constant(v1);
+      const Operator* op2 = common()->Float32Constant(v2);
+      EXPECT_EQ(bit_cast<uint32_t>(v1) == bit_cast<uint32_t>(v2),
+                op1->Equals(op2));
+    }
+  }
+}
+
+
+TEST_F(CommonOperatorTest, Float64Constant) {
+  TRACED_FOREACH(double, value, kFloatValues) {
+    const Operator* op = common()->Float64Constant(value);
+    EXPECT_PRED2(base::bit_equal_to<double>(), value, OpParameter<double>(op));
+    EXPECT_EQ(0, op->ValueInputCount());
+    EXPECT_EQ(0, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->ValueOutputCount());
+  }
+  TRACED_FOREACH(double, v1, kFloatValues) {
+    TRACED_FOREACH(double, v2, kFloatValues) {
+      const Operator* op1 = common()->Float64Constant(v1);
+      const Operator* op2 = common()->Float64Constant(v2);
+      EXPECT_EQ(bit_cast<uint64_t>(v1) == bit_cast<uint64_t>(v2),
+                op1->Equals(op2));
+    }
+  }
+}
+
+
+TEST_F(CommonOperatorTest, NumberConstant) {
+  TRACED_FOREACH(double, value, kFloatValues) {
+    const Operator* op = common()->NumberConstant(value);
+    EXPECT_PRED2(base::bit_equal_to<double>(), value, OpParameter<double>(op));
+    EXPECT_EQ(0, op->ValueInputCount());
+    EXPECT_EQ(0, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->ValueOutputCount());
+  }
+  TRACED_FOREACH(double, v1, kFloatValues) {
+    TRACED_FOREACH(double, v2, kFloatValues) {
+      const Operator* op1 = common()->NumberConstant(v1);
+      const Operator* op2 = common()->NumberConstant(v2);
+      EXPECT_EQ(bit_cast<uint64_t>(v1) == bit_cast<uint64_t>(v2),
+                op1->Equals(op2));
+    }
+  }
+}
+
+
+TEST_F(CommonOperatorTest, ValueEffect) {
+  TRACED_FOREACH(int, arguments, kArguments) {
+    const Operator* op = common()->ValueEffect(arguments);
+    EXPECT_EQ(arguments, op->ValueInputCount());
+    EXPECT_EQ(arguments, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(1, op->EffectOutputCount());
+    EXPECT_EQ(0, op->ValueOutputCount());
+  }
+}
+
+
+TEST_F(CommonOperatorTest, Finish) {
+  TRACED_FOREACH(int, arguments, kArguments) {
+    const Operator* op = common()->Finish(arguments);
+    EXPECT_EQ(1, op->ValueInputCount());
+    EXPECT_EQ(arguments, op->EffectInputCount());
+    EXPECT_EQ(arguments + 1, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, op->ControlOutputCount());
+    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->ValueOutputCount());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/compiler-test-utils.h b/test/unittests/compiler/compiler-test-utils.h
new file mode 100644
index 0000000..6ce28f9
--- /dev/null
+++ b/test/unittests/compiler/compiler-test-utils.h
@@ -0,0 +1,57 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_COMPILER_TEST_UTILS_H_
+#define V8_UNITTESTS_COMPILER_COMPILER_TEST_UTILS_H_
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// The TARGET_TEST(Case, Name) macro works just like
+// TEST(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TEST(Case, Name) TEST(Case, Name)
+#else
+#define TARGET_TEST(Case, Name) TEST(Case, DISABLED_##Name)
+#endif
+
+
+// The TARGET_TEST_F(Case, Name) macro works just like
+// TEST_F(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TEST_F(Case, Name) TEST_F(Case, Name)
+#else
+#define TARGET_TEST_F(Case, Name) TEST_F(Case, DISABLED_##Name)
+#endif
+
+
+// The TARGET_TEST_P(Case, Name) macro works just like
+// TEST_P(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TEST_P(Case, Name) TEST_P(Case, Name)
+#else
+#define TARGET_TEST_P(Case, Name) TEST_P(Case, DISABLED_##Name)
+#endif
+
+
+// The TARGET_TYPED_TEST(Case, Name) macro works just like
+// TYPED_TEST(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TYPED_TEST(Case, Name) TYPED_TEST(Case, Name)
+#else
+#define TARGET_TYPED_TEST(Case, Name) TYPED_TEST(Case, DISABLED_##Name)
+#endif
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_COMPILER_TEST_UTILS_H_
diff --git a/test/unittests/compiler/control-equivalence-unittest.cc b/test/unittests/compiler/control-equivalence-unittest.cc
new file mode 100644
index 0000000..56b4a2b
--- /dev/null
+++ b/test/unittests/compiler/control-equivalence-unittest.cc
@@ -0,0 +1,255 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/bit-vector.h"
+#include "src/compiler/control-equivalence.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/zone-containers.h"
+#include "test/unittests/compiler/graph-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#define ASSERT_EQUIVALENCE(...)                           \
+  do {                                                    \
+    Node* __n[] = {__VA_ARGS__};                          \
+    ASSERT_TRUE(IsEquivalenceClass(arraysize(__n), __n)); \
+  } while (false);
+
+class ControlEquivalenceTest : public GraphTest {
+ public:
+  ControlEquivalenceTest() : all_nodes_(zone()), classes_(zone()) {
+    Store(graph()->start());
+  }
+
+ protected:
+  void ComputeEquivalence(Node* node) {
+    graph()->SetEnd(graph()->NewNode(common()->End(), node));
+    if (FLAG_trace_turbo) {
+      OFStream os(stdout);
+      os << AsDOT(*graph());
+    }
+    ControlEquivalence equivalence(zone(), graph());
+    equivalence.Run(node);
+    classes_.resize(graph()->NodeCount());
+    for (Node* node : all_nodes_) {
+      classes_[node->id()] = equivalence.ClassOf(node);
+    }
+  }
+
+  bool IsEquivalenceClass(size_t length, Node** nodes) {
+    BitVector in_class(graph()->NodeCount(), zone());
+    size_t expected_class = classes_[nodes[0]->id()];
+    for (size_t i = 0; i < length; ++i) {
+      in_class.Add(nodes[i]->id());
+    }
+    for (Node* node : all_nodes_) {
+      if (in_class.Contains(node->id())) {
+        if (classes_[node->id()] != expected_class) return false;
+      } else {
+        if (classes_[node->id()] == expected_class) return false;
+      }
+    }
+    return true;
+  }
+
+  Node* Value() { return NumberConstant(0.0); }
+
+  Node* Branch(Node* control) {
+    return Store(graph()->NewNode(common()->Branch(), Value(), control));
+  }
+
+  Node* IfTrue(Node* control) {
+    return Store(graph()->NewNode(common()->IfTrue(), control));
+  }
+
+  Node* IfFalse(Node* control) {
+    return Store(graph()->NewNode(common()->IfFalse(), control));
+  }
+
+  Node* Merge2(Node* control1, Node* control2) {
+    return Store(graph()->NewNode(common()->Merge(2), control1, control2));
+  }
+
+  Node* Loop2(Node* control) {
+    return Store(graph()->NewNode(common()->Loop(2), control, control));
+  }
+
+  Node* End(Node* control) {
+    return Store(graph()->NewNode(common()->End(), control));
+  }
+
+ private:
+  Node* Store(Node* node) {
+    all_nodes_.push_back(node);
+    return node;
+  }
+
+  ZoneVector<Node*> all_nodes_;
+  ZoneVector<size_t> classes_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Test cases.
+
+
+TEST_F(ControlEquivalenceTest, Empty1) {
+  Node* start = graph()->start();
+  ComputeEquivalence(start);
+
+  ASSERT_EQUIVALENCE(start);
+}
+
+
+TEST_F(ControlEquivalenceTest, Empty2) {
+  Node* start = graph()->start();
+  Node* end = End(start);
+  ComputeEquivalence(end);
+
+  ASSERT_EQUIVALENCE(start, end);
+}
+
+
+TEST_F(ControlEquivalenceTest, Diamond1) {
+  Node* start = graph()->start();
+  Node* b = Branch(start);
+  Node* t = IfTrue(b);
+  Node* f = IfFalse(b);
+  Node* m = Merge2(t, f);
+  ComputeEquivalence(m);
+
+  ASSERT_EQUIVALENCE(b, m, start);
+  ASSERT_EQUIVALENCE(f);
+  ASSERT_EQUIVALENCE(t);
+}
+
+
+TEST_F(ControlEquivalenceTest, Diamond2) {
+  Node* start = graph()->start();
+  Node* b1 = Branch(start);
+  Node* t1 = IfTrue(b1);
+  Node* f1 = IfFalse(b1);
+  Node* b2 = Branch(f1);
+  Node* t2 = IfTrue(b2);
+  Node* f2 = IfFalse(b2);
+  Node* m2 = Merge2(t2, f2);
+  Node* m1 = Merge2(t1, m2);
+  ComputeEquivalence(m1);
+
+  ASSERT_EQUIVALENCE(b1, m1, start);
+  ASSERT_EQUIVALENCE(t1);
+  ASSERT_EQUIVALENCE(f1, b2, m2);
+  ASSERT_EQUIVALENCE(t2);
+  ASSERT_EQUIVALENCE(f2);
+}
+
+
+TEST_F(ControlEquivalenceTest, Diamond3) {
+  Node* start = graph()->start();
+  Node* b1 = Branch(start);
+  Node* t1 = IfTrue(b1);
+  Node* f1 = IfFalse(b1);
+  Node* m1 = Merge2(t1, f1);
+  Node* b2 = Branch(m1);
+  Node* t2 = IfTrue(b2);
+  Node* f2 = IfFalse(b2);
+  Node* m2 = Merge2(t2, f2);
+  ComputeEquivalence(m2);
+
+  ASSERT_EQUIVALENCE(b1, m1, b2, m2, start);
+  ASSERT_EQUIVALENCE(t1);
+  ASSERT_EQUIVALENCE(f1);
+  ASSERT_EQUIVALENCE(t2);
+  ASSERT_EQUIVALENCE(f2);
+}
+
+
+TEST_F(ControlEquivalenceTest, Switch1) {
+  Node* start = graph()->start();
+  Node* b1 = Branch(start);
+  Node* t1 = IfTrue(b1);
+  Node* f1 = IfFalse(b1);
+  Node* b2 = Branch(f1);
+  Node* t2 = IfTrue(b2);
+  Node* f2 = IfFalse(b2);
+  Node* b3 = Branch(f2);
+  Node* t3 = IfTrue(b3);
+  Node* f3 = IfFalse(b3);
+  Node* m1 = Merge2(t1, t2);
+  Node* m2 = Merge2(m1, t3);
+  Node* m3 = Merge2(m2, f3);
+  ComputeEquivalence(m3);
+
+  ASSERT_EQUIVALENCE(b1, m3, start);
+  ASSERT_EQUIVALENCE(t1);
+  ASSERT_EQUIVALENCE(f1, b2);
+  ASSERT_EQUIVALENCE(t2);
+  ASSERT_EQUIVALENCE(f2, b3);
+  ASSERT_EQUIVALENCE(t3);
+  ASSERT_EQUIVALENCE(f3);
+  ASSERT_EQUIVALENCE(m1);
+  ASSERT_EQUIVALENCE(m2);
+}
+
+
+TEST_F(ControlEquivalenceTest, Loop1) {
+  Node* start = graph()->start();
+  Node* l = Loop2(start);
+  l->ReplaceInput(1, l);
+  ComputeEquivalence(l);
+
+  ASSERT_EQUIVALENCE(start);
+  ASSERT_EQUIVALENCE(l);
+}
+
+
+TEST_F(ControlEquivalenceTest, Loop2) {
+  Node* start = graph()->start();
+  Node* l = Loop2(start);
+  Node* b = Branch(l);
+  Node* t = IfTrue(b);
+  Node* f = IfFalse(b);
+  l->ReplaceInput(1, t);
+  ComputeEquivalence(f);
+
+  ASSERT_EQUIVALENCE(f, start);
+  ASSERT_EQUIVALENCE(t);
+  ASSERT_EQUIVALENCE(l, b);
+}
+
+
+TEST_F(ControlEquivalenceTest, Irreducible) {
+  Node* start = graph()->start();
+  Node* b1 = Branch(start);
+  Node* t1 = IfTrue(b1);
+  Node* f1 = IfFalse(b1);
+  Node* lp = Loop2(f1);
+  Node* m1 = Merge2(t1, lp);
+  Node* b2 = Branch(m1);
+  Node* t2 = IfTrue(b2);
+  Node* f2 = IfFalse(b2);
+  Node* m2 = Merge2(t2, f2);
+  Node* b3 = Branch(m2);
+  Node* t3 = IfTrue(b3);
+  Node* f3 = IfFalse(b3);
+  lp->ReplaceInput(1, f3);
+  ComputeEquivalence(t3);
+
+  ASSERT_EQUIVALENCE(b1, t3, start);
+  ASSERT_EQUIVALENCE(t1);
+  ASSERT_EQUIVALENCE(f1);
+  ASSERT_EQUIVALENCE(m1, b2, m2, b3);
+  ASSERT_EQUIVALENCE(t2);
+  ASSERT_EQUIVALENCE(f2);
+  ASSERT_EQUIVALENCE(f3);
+  ASSERT_EQUIVALENCE(lp);
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/diamond-unittest.cc b/test/unittests/compiler/diamond-unittest.cc
new file mode 100644
index 0000000..c14886f
--- /dev/null
+++ b/test/unittests/compiler/diamond-unittest.cc
@@ -0,0 +1,161 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::AllOf;
+using testing::Capture;
+using testing::CaptureEq;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class DiamondTest : public GraphTest {
+ public:
+  DiamondTest() : GraphTest(5) {}
+};
+
+
+TEST_F(DiamondTest, SimpleDiamond) {
+  Node* p = Parameter(0);
+  Diamond d(graph(), common(), p);
+  EXPECT_THAT(d.branch, IsBranch(p, graph()->start()));
+  EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+  EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+  EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondChainDiamond) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Diamond d0(graph(), common(), p0);
+  Diamond d1(graph(), common(), p1);
+  d1.Chain(d0);
+  EXPECT_THAT(d1.branch, IsBranch(p1, d0.merge));
+  EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+}
+
+
+TEST_F(DiamondTest, DiamondChainNode) {
+  Node* p1 = Parameter(1);
+  Diamond d1(graph(), common(), p1);
+  Node* other = graph()->NewNode(common()->Merge(0));
+  d1.Chain(other);
+  EXPECT_THAT(d1.branch, IsBranch(p1, other));
+}
+
+
+TEST_F(DiamondTest, DiamondChainN) {
+  Node* params[5] = {Parameter(0), Parameter(1), Parameter(2), Parameter(3),
+                     Parameter(4)};
+  Diamond d[5] = {Diamond(graph(), common(), params[0]),
+                  Diamond(graph(), common(), params[1]),
+                  Diamond(graph(), common(), params[2]),
+                  Diamond(graph(), common(), params[3]),
+                  Diamond(graph(), common(), params[4])};
+
+  for (int i = 1; i < 5; i++) {
+    d[i].Chain(d[i - 1]);
+    EXPECT_THAT(d[i].branch, IsBranch(params[i], d[i - 1].merge));
+  }
+}
+
+
+TEST_F(DiamondTest, DiamondNested_true) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Diamond d0(graph(), common(), p0);
+  Diamond d1(graph(), common(), p1);
+
+  d1.Nest(d0, true);
+
+  EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+  EXPECT_THAT(d0.if_true, IsIfTrue(d0.branch));
+  EXPECT_THAT(d0.if_false, IsIfFalse(d0.branch));
+  EXPECT_THAT(d0.merge, IsMerge(d1.merge, d0.if_false));
+
+  EXPECT_THAT(d1.branch, IsBranch(p1, d0.if_true));
+  EXPECT_THAT(d1.if_true, IsIfTrue(d1.branch));
+  EXPECT_THAT(d1.if_false, IsIfFalse(d1.branch));
+  EXPECT_THAT(d1.merge, IsMerge(d1.if_true, d1.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondNested_false) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Diamond d0(graph(), common(), p0);
+  Diamond d1(graph(), common(), p1);
+
+  d1.Nest(d0, false);
+
+  EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+  EXPECT_THAT(d0.if_true, IsIfTrue(d0.branch));
+  EXPECT_THAT(d0.if_false, IsIfFalse(d0.branch));
+  EXPECT_THAT(d0.merge, IsMerge(d0.if_true, d1.merge));
+
+  EXPECT_THAT(d1.branch, IsBranch(p1, d0.if_false));
+  EXPECT_THAT(d1.if_true, IsIfTrue(d1.branch));
+  EXPECT_THAT(d1.if_false, IsIfFalse(d1.branch));
+  EXPECT_THAT(d1.merge, IsMerge(d1.if_true, d1.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondPhis) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* p2 = Parameter(2);
+  Diamond d(graph(), common(), p0);
+
+  MachineType types[] = {kMachAnyTagged, kMachUint32, kMachInt32};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    Node* phi = d.Phi(types[i], p1, p2);
+
+    EXPECT_THAT(d.branch, IsBranch(p0, graph()->start()));
+    EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+    EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+    EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+    EXPECT_THAT(phi, IsPhi(types[i], p1, p2, d.merge));
+  }
+}
+
+
+TEST_F(DiamondTest, DiamondEffectPhis) {
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* p2 = Parameter(2);
+  Diamond d(graph(), common(), p0);
+
+  Node* phi = d.EffectPhi(p1, p2);
+
+  EXPECT_THAT(d.branch, IsBranch(p0, graph()->start()));
+  EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+  EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+  EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+  EXPECT_THAT(phi, IsEffectPhi(p1, p2, d.merge));
+}
+
+
+TEST_F(DiamondTest, BranchHint) {
+  Diamond dn(graph(), common(), Parameter(0));
+  CHECK(BranchHint::kNone == BranchHintOf(dn.branch->op()));
+
+  Diamond dt(graph(), common(), Parameter(0), BranchHint::kTrue);
+  CHECK(BranchHint::kTrue == BranchHintOf(dt.branch->op()));
+
+  Diamond df(graph(), common(), Parameter(0), BranchHint::kFalse);
+  CHECK(BranchHint::kFalse == BranchHintOf(df.branch->op()));
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/graph-reducer-unittest.cc b/test/unittests/compiler/graph-reducer-unittest.cc
new file mode 100644
index 0000000..dbdd4bb
--- /dev/null
+++ b/test/unittests/compiler/graph-reducer-unittest.cc
@@ -0,0 +1,123 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-reducer.h"
+#include "src/compiler/operator.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::_;
+using testing::DefaultValue;
+using testing::Return;
+using testing::Sequence;
+using testing::StrictMock;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+struct TestOperator : public Operator {
+  TestOperator(Operator::Opcode opcode, Operator::Properties properties,
+               size_t value_in, size_t value_out)
+      : Operator(opcode, properties, "TestOp", value_in, 0, 0, value_out, 0,
+                 0) {}
+};
+
+
+namespace {
+
+TestOperator OP0(0, Operator::kNoWrite, 0, 1);
+TestOperator OP1(1, Operator::kNoProperties, 1, 1);
+
+
+struct MockReducer : public Reducer {
+  MOCK_METHOD1(Reduce, Reduction(Node*));
+};
+
+}  // namespace
+
+
+class GraphReducerTest : public TestWithZone {
+ public:
+  GraphReducerTest() : graph_(zone()) {}
+
+  static void SetUpTestCase() {
+    TestWithZone::SetUpTestCase();
+    DefaultValue<Reduction>::Set(Reducer::NoChange());
+  }
+
+  static void TearDownTestCase() {
+    DefaultValue<Reduction>::Clear();
+    TestWithZone::TearDownTestCase();
+  }
+
+ protected:
+  void ReduceNode(Node* node, Reducer* r) {
+    GraphReducer reducer(graph(), zone());
+    reducer.AddReducer(r);
+    reducer.ReduceNode(node);
+  }
+
+  void ReduceNode(Node* node, Reducer* r1, Reducer* r2) {
+    GraphReducer reducer(graph(), zone());
+    reducer.AddReducer(r1);
+    reducer.AddReducer(r2);
+    reducer.ReduceNode(node);
+  }
+
+  void ReduceNode(Node* node, Reducer* r1, Reducer* r2, Reducer* r3) {
+    GraphReducer reducer(graph(), zone());
+    reducer.AddReducer(r1);
+    reducer.AddReducer(r2);
+    reducer.AddReducer(r3);
+    reducer.ReduceNode(node);
+  }
+
+  Graph* graph() { return &graph_; }
+
+ private:
+  Graph graph_;
+};
+
+
+TEST_F(GraphReducerTest, NodeIsDeadAfterReplace) {
+  StrictMock<MockReducer> r;
+  Node* node0 = graph()->NewNode(&OP0);
+  Node* node1 = graph()->NewNode(&OP1, node0);
+  Node* node2 = graph()->NewNode(&OP1, node0);
+  EXPECT_CALL(r, Reduce(node0)).WillOnce(Return(Reducer::NoChange()));
+  EXPECT_CALL(r, Reduce(node1)).WillOnce(Return(Reducer::Replace(node2)));
+  ReduceNode(node1, &r);
+  EXPECT_FALSE(node0->IsDead());
+  EXPECT_TRUE(node1->IsDead());
+  EXPECT_FALSE(node2->IsDead());
+}
+
+
+TEST_F(GraphReducerTest, ReduceOnceForEveryReducer) {
+  StrictMock<MockReducer> r1, r2;
+  Node* node0 = graph()->NewNode(&OP0);
+  EXPECT_CALL(r1, Reduce(node0));
+  EXPECT_CALL(r2, Reduce(node0));
+  ReduceNode(node0, &r1, &r2);
+}
+
+
+TEST_F(GraphReducerTest, ReduceAgainAfterChanged) {
+  Sequence s1, s2, s3;
+  StrictMock<MockReducer> r1, r2, r3;
+  Node* node0 = graph()->NewNode(&OP0);
+  EXPECT_CALL(r1, Reduce(node0));
+  EXPECT_CALL(r2, Reduce(node0));
+  EXPECT_CALL(r3, Reduce(node0)).InSequence(s1, s2, s3).WillOnce(
+      Return(Reducer::Changed(node0)));
+  EXPECT_CALL(r1, Reduce(node0)).InSequence(s1);
+  EXPECT_CALL(r2, Reduce(node0)).InSequence(s2);
+  ReduceNode(node0, &r1, &r2, &r3);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/graph-unittest.cc b/test/unittests/compiler/graph-unittest.cc
new file mode 100644
index 0000000..9543258
--- /dev/null
+++ b/test/unittests/compiler/graph-unittest.cc
@@ -0,0 +1,110 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/graph-unittest.h"
+
+#include "src/compiler/node-properties-inl.h"
+#include "test/unittests/compiler/node-test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+GraphTest::GraphTest(int num_parameters) : common_(zone()), graph_(zone()) {
+  graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
+}
+
+
+GraphTest::~GraphTest() {}
+
+
+Node* GraphTest::Parameter(int32_t index) {
+  return graph()->NewNode(common()->Parameter(index), graph()->start());
+}
+
+
+Node* GraphTest::Float32Constant(volatile float value) {
+  return graph()->NewNode(common()->Float32Constant(value));
+}
+
+
+Node* GraphTest::Float64Constant(volatile double value) {
+  return graph()->NewNode(common()->Float64Constant(value));
+}
+
+
+Node* GraphTest::Int32Constant(int32_t value) {
+  return graph()->NewNode(common()->Int32Constant(value));
+}
+
+
+Node* GraphTest::Int64Constant(int64_t value) {
+  return graph()->NewNode(common()->Int64Constant(value));
+}
+
+
+Node* GraphTest::NumberConstant(volatile double value) {
+  return graph()->NewNode(common()->NumberConstant(value));
+}
+
+
+Node* GraphTest::HeapConstant(const Handle<HeapObject>& value) {
+  return HeapConstant(Unique<HeapObject>::CreateUninitialized(value));
+}
+
+
+Node* GraphTest::HeapConstant(const Unique<HeapObject>& value) {
+  Node* node = graph()->NewNode(common()->HeapConstant(value));
+  Type* type = Type::Constant(value.handle(), zone());
+  NodeProperties::SetBounds(node, Bounds(type));
+  return node;
+}
+
+
+Node* GraphTest::FalseConstant() {
+  return HeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->false_value()));
+}
+
+
+Node* GraphTest::TrueConstant() {
+  return HeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->true_value()));
+}
+
+
+Node* GraphTest::UndefinedConstant() {
+  return HeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
+}
+
+
+Matcher<Node*> GraphTest::IsFalseConstant() {
+  return IsHeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->false_value()));
+}
+
+
+Matcher<Node*> GraphTest::IsTrueConstant() {
+  return IsHeapConstant(
+      Unique<HeapObject>::CreateImmovable(factory()->true_value()));
+}
+
+
+TypedGraphTest::TypedGraphTest(int num_parameters)
+    : GraphTest(num_parameters), typer_(graph(), MaybeHandle<Context>()) {}
+
+
+TypedGraphTest::~TypedGraphTest() {}
+
+
+Node* TypedGraphTest::Parameter(Type* type, int32_t index) {
+  Node* node = GraphTest::Parameter(index);
+  NodeProperties::SetBounds(node, Bounds(type));
+  return node;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/graph-unittest.h b/test/unittests/compiler/graph-unittest.h
new file mode 100644
index 0000000..7c75161
--- /dev/null
+++ b/test/unittests/compiler/graph-unittest.h
@@ -0,0 +1,81 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_GRAPH_UNITTEST_H_
+#define V8_UNITTESTS_COMPILER_GRAPH_UNITTEST_H_
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/typer.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+template <class T>
+class Handle;
+class HeapObject;
+template <class T>
+class Unique;
+
+namespace compiler {
+
+using ::testing::Matcher;
+
+
+class GraphTest : public TestWithContext, public TestWithZone {
+ public:
+  explicit GraphTest(int num_parameters = 1);
+  ~GraphTest() OVERRIDE;
+
+ protected:
+  Node* Parameter(int32_t index = 0);
+  Node* Float32Constant(volatile float value);
+  Node* Float64Constant(volatile double value);
+  Node* Int32Constant(int32_t value);
+  Node* Uint32Constant(uint32_t value) {
+    return Int32Constant(bit_cast<int32_t>(value));
+  }
+  Node* Int64Constant(int64_t value);
+  Node* NumberConstant(volatile double value);
+  Node* HeapConstant(const Handle<HeapObject>& value);
+  Node* HeapConstant(const Unique<HeapObject>& value);
+  Node* FalseConstant();
+  Node* TrueConstant();
+  Node* UndefinedConstant();
+
+  Matcher<Node*> IsFalseConstant();
+  Matcher<Node*> IsTrueConstant();
+
+  CommonOperatorBuilder* common() { return &common_; }
+  Graph* graph() { return &graph_; }
+
+ private:
+  CommonOperatorBuilder common_;
+  Graph graph_;
+};
+
+
+class TypedGraphTest : public GraphTest {
+ public:
+  explicit TypedGraphTest(int num_parameters = 1);
+  ~TypedGraphTest() OVERRIDE;
+
+ protected:
+  Node* Parameter(int32_t index = 0) { return GraphTest::Parameter(index); }
+  Node* Parameter(Type* type, int32_t index = 0);
+
+  Typer* typer() { return &typer_; }
+
+ private:
+  Typer typer_;
+};
+
+}  //  namespace compiler
+}  //  namespace internal
+}  //  namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_GRAPH_UNITTEST_H_
diff --git a/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
new file mode 100644
index 0000000..afa1e94
--- /dev/null
+++ b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
@@ -0,0 +1,671 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+// Immediates (random subset).
+static const int32_t kImmediates[] = {
+    kMinInt, -42, -1, 0,  1,  2,    3,      4,          5,
+    6,       7,   8,  16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt};
+
+}  // namespace
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithImmediate) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+      if (imm == 0) {
+        ASSERT_EQ(1U, s[0]->InputCount());
+      } else {
+        ASSERT_EQ(2U, s[0]->InputCount());
+        EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      }
+    }
+    {
+      StreamBuilder m(this, kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)));
+      Stream s = m.Build();
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+      if (imm == 0) {
+        ASSERT_EQ(1U, s[0]->InputCount());
+      } else {
+        ASSERT_EQ(2U, s[0]->InputCount());
+        EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+      }
+    }
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(m.Int32Sub(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32Sub, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithImmediate) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kIA32Sub, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat64);
+  m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat32);
+  m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSECvtsd2ss, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+// -----------------------------------------------------------------------------
+// Better left operand for commutative binops
+
+
+TEST_F(InstructionSelectorTest, BetterLeftOperandTestAddBinop) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* param1 = m.Parameter(0);
+  Node* param2 = m.Parameter(1);
+  Node* add = m.Int32Add(param1, param2);
+  m.Return(m.Int32Add(add, param1));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
+  EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(param2), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, BetterLeftOperandTestMulBinop) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* param1 = m.Parameter(0);
+  Node* param2 = m.Parameter(1);
+  Node* mul = m.Int32Mul(param1, param2);
+  m.Return(m.Int32Mul(mul, param1));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
+  EXPECT_EQ(s.ToVreg(param2), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(param1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachUint32);
+  m.Return(m.ChangeUint32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode());
+}
+
+
+// -----------------------------------------------------------------------------
+// Loads and stores
+
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
+  return os << memacc.type;
+}
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8, kIA32Movsxbl, kIA32Movb},
+    {kMachUint8, kIA32Movzxbl, kIA32Movb},
+    {kMachInt16, kIA32Movsxwl, kIA32Movw},
+    {kMachUint16, kIA32Movzxwl, kIA32Movw},
+    {kMachInt32, kIA32Movl, kIA32Movl},
+    {kMachUint32, kIA32Movl, kIA32Movl},
+    {kMachFloat32, kIA32Movss, kIA32Movss},
+    {kMachFloat64, kIA32Movsd, kIA32Movsd}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateBase) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, base, kImmediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Int32Constant(base), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+    if (base == 0) {
+      ASSERT_EQ(1U, s[0]->InputCount());
+    } else {
+      ASSERT_EQ(2U, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+      EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1)));
+    }
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, kImmediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+    if (index == 0) {
+      ASSERT_EQ(1U, s[0]->InputCount());
+    } else {
+      ASSERT_EQ(2U, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+      EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    }
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(0U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateBase) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, base, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachInt32, memacc.type);
+    m.Store(memacc.type, m.Int32Constant(base), m.Parameter(0), m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+    if (base == 0) {
+      ASSERT_EQ(2U, s[0]->InputCount());
+    } else {
+      ASSERT_EQ(3U, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+      EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1)));
+    }
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
+  const MemoryAccess memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, kImmediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+    if (index == 0) {
+      ASSERT_EQ(2U, s[0]->InputCount());
+    } else {
+      ASSERT_EQ(3U, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+      EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    }
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// -----------------------------------------------------------------------------
+// AddressingMode for loads and stores.
+
+
+class AddressingModeUnitTest : public InstructionSelectorTest {
+ public:
+  AddressingModeUnitTest() : m(NULL) { Reset(); }
+  ~AddressingModeUnitTest() { delete m; }
+
+  void Run(Node* base, Node* load_index, Node* store_index,
+           AddressingMode mode) {
+    Node* load = m->Load(kMachInt32, base, load_index);
+    m->Store(kMachInt32, base, store_index, load);
+    m->Return(m->Int32Constant(0));
+    Stream s = m->Build();
+    ASSERT_EQ(2U, s.size());
+    EXPECT_EQ(mode, s[0]->addressing_mode());
+    EXPECT_EQ(mode, s[1]->addressing_mode());
+  }
+
+  Node* zero;
+  Node* null_ptr;
+  Node* non_zero;
+  Node* base_reg;   // opaque value to generate base as register
+  Node* index_reg;  // opaque value to generate index as register
+  Node* scales[4];
+  StreamBuilder* m;
+
+  void Reset() {
+    delete m;
+    m = new StreamBuilder(this, kMachInt32, kMachInt32, kMachInt32);
+    zero = m->Int32Constant(0);
+    null_ptr = m->Int32Constant(0);
+    non_zero = m->Int32Constant(127);
+    base_reg = m->Parameter(0);
+    index_reg = m->Parameter(0);
+
+    scales[0] = m->Int32Constant(1);
+    scales[1] = m->Int32Constant(2);
+    scales[2] = m->Int32Constant(4);
+    scales[3] = m->Int32Constant(8);
+  }
+};
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MR) {
+  Node* base = base_reg;
+  Node* index = zero;
+  Run(base, index, index, kMode_MR);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MRI) {
+  Node* base = base_reg;
+  Node* index = non_zero;
+  Run(base, index, index, kMode_MRI);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MR1) {
+  Node* base = base_reg;
+  Node* index = index_reg;
+  Run(base, index, index, kMode_MR1);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MRN) {
+  AddressingMode expected[] = {kMode_MR1, kMode_MR2, kMode_MR4, kMode_MR8};
+  for (size_t i = 0; i < arraysize(scales); ++i) {
+    Reset();
+    Node* base = base_reg;
+    Node* load_index = m->Int32Mul(index_reg, scales[i]);
+    Node* store_index = m->Int32Mul(index_reg, scales[i]);
+    Run(base, load_index, store_index, expected[i]);
+  }
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MR1I) {
+  Node* base = base_reg;
+  Node* load_index = m->Int32Add(index_reg, non_zero);
+  Node* store_index = m->Int32Add(index_reg, non_zero);
+  Run(base, load_index, store_index, kMode_MR1I);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MRNI) {
+  AddressingMode expected[] = {kMode_MR1I, kMode_MR2I, kMode_MR4I, kMode_MR8I};
+  for (size_t i = 0; i < arraysize(scales); ++i) {
+    Reset();
+    Node* base = base_reg;
+    Node* load_index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
+    Node* store_index =
+        m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
+    Run(base, load_index, store_index, expected[i]);
+  }
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_M1ToMR) {
+  Node* base = null_ptr;
+  Node* index = index_reg;
+  // M1 maps to MR
+  Run(base, index, index, kMode_MR);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MN) {
+  AddressingMode expected[] = {kMode_MR, kMode_M2, kMode_M4, kMode_M8};
+  for (size_t i = 0; i < arraysize(scales); ++i) {
+    Reset();
+    Node* base = null_ptr;
+    Node* load_index = m->Int32Mul(index_reg, scales[i]);
+    Node* store_index = m->Int32Mul(index_reg, scales[i]);
+    Run(base, load_index, store_index, expected[i]);
+  }
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_M1IToMRI) {
+  Node* base = null_ptr;
+  Node* load_index = m->Int32Add(index_reg, non_zero);
+  Node* store_index = m->Int32Add(index_reg, non_zero);
+  // M1I maps to MRI
+  Run(base, load_index, store_index, kMode_MRI);
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MNI) {
+  AddressingMode expected[] = {kMode_MRI, kMode_M2I, kMode_M4I, kMode_M8I};
+  for (size_t i = 0; i < arraysize(scales); ++i) {
+    Reset();
+    Node* base = null_ptr;
+    Node* load_index = m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
+    Node* store_index =
+        m->Int32Add(m->Int32Mul(index_reg, scales[i]), non_zero);
+    Run(base, load_index, store_index, expected[i]);
+  }
+}
+
+
+TEST_F(AddressingModeUnitTest, AddressingMode_MI) {
+  Node* bases[] = {null_ptr, non_zero};
+  Node* indices[] = {zero, non_zero};
+  for (size_t i = 0; i < arraysize(bases); ++i) {
+    for (size_t j = 0; j < arraysize(indices); ++j) {
+      Reset();
+      Node* base = bases[i];
+      Node* index = indices[j];
+      Run(base, index, index, kMode_MI);
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Multiplication.
+
+
+namespace {
+
+struct MultParam {
+  int value;
+  bool lea_expected;
+  AddressingMode addressing_mode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MultParam& m) {
+  return os << m.value << "." << m.lea_expected << "." << m.addressing_mode;
+}
+
+
+const MultParam kMultParams[] = {{-1, false, kMode_None},
+                                 {0, false, kMode_None},
+                                 {1, true, kMode_MR},
+                                 {2, true, kMode_M2},
+                                 {3, true, kMode_MR2},
+                                 {4, true, kMode_M4},
+                                 {5, true, kMode_MR4},
+                                 {6, false, kMode_None},
+                                 {7, false, kMode_None},
+                                 {8, true, kMode_M8},
+                                 {9, true, kMode_MR8},
+                                 {10, false, kMode_None},
+                                 {11, false, kMode_None}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MultParam> InstructionSelectorMultTest;
+
+
+static unsigned InputCountForLea(AddressingMode mode) {
+  switch (mode) {
+    case kMode_MR1I:
+    case kMode_MR2I:
+    case kMode_MR4I:
+    case kMode_MR8I:
+      return 3U;
+    case kMode_M1I:
+    case kMode_M2I:
+    case kMode_M4I:
+    case kMode_M8I:
+      return 2U;
+    case kMode_MR1:
+    case kMode_MR2:
+    case kMode_MR4:
+    case kMode_MR8:
+    case kMode_MRI:
+      return 2U;
+    case kMode_M1:
+    case kMode_M2:
+    case kMode_M4:
+    case kMode_M8:
+    case kMode_MI:
+    case kMode_MR:
+      return 1U;
+    default:
+      UNREACHABLE();
+      return 0U;
+  }
+}
+
+
+static AddressingMode AddressingModeForAddMult(int32_t imm,
+                                               const MultParam& m) {
+  if (imm == 0) return m.addressing_mode;
+  switch (m.addressing_mode) {
+    case kMode_MR1:
+      return kMode_MR1I;
+    case kMode_MR2:
+      return kMode_MR2I;
+    case kMode_MR4:
+      return kMode_MR4I;
+    case kMode_MR8:
+      return kMode_MR8I;
+    case kMode_M1:
+      return kMode_M1I;
+    case kMode_M2:
+      return kMode_M2I;
+    case kMode_M4:
+      return kMode_M4I;
+    case kMode_M8:
+      return kMode_M8I;
+    case kMode_MR:
+      return kMode_MRI;
+    default:
+      UNREACHABLE();
+      return kMode_None;
+  }
+}
+
+
+TEST_P(InstructionSelectorMultTest, Mult32) {
+  const MultParam m_param = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* param = m.Parameter(0);
+  Node* mult = m.Int32Mul(param, m.Int32Constant(m_param.value));
+  m.Return(mult);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode());
+  if (m_param.lea_expected) {
+    EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+    ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount());
+  } else {
+    EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+  }
+  EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_P(InstructionSelectorMultTest, MultAdd32) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    const MultParam m_param = GetParam();
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* param = m.Parameter(0);
+    Node* mult = m.Int32Add(m.Int32Mul(param, m.Int32Constant(m_param.value)),
+                            m.Int32Constant(imm));
+    m.Return(mult);
+    Stream s = m.Build();
+    if (m_param.lea_expected) {
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+      EXPECT_EQ(AddressingModeForAddMult(imm, m_param),
+                s[0]->addressing_mode());
+      unsigned input_count = InputCountForLea(s[0]->addressing_mode());
+      ASSERT_EQ(input_count, s[0]->InputCount());
+      if (imm != 0) {
+        ASSERT_EQ(InstructionOperand::IMMEDIATE,
+                  s[0]->InputAt(input_count - 1)->kind());
+        EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(input_count - 1)));
+      }
+    } else {
+      ASSERT_EQ(2U, s.size());
+      EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
+      EXPECT_EQ(kIA32Lea, s[1]->arch_opcode());
+    }
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest,
+                        ::testing::ValuesIn(kMultParams));
+
+
+TEST_F(InstructionSelectorTest, Int32MulHigh) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32ImulHigh, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), eax));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), edx));
+}
+
+
+TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
+    Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
+    Node* mul = m.Float64Mul(add, m.Parameter(1));
+    Node* sub = m.Float64Sub(mul, add);
+    Node* ret = m.Float64Div(mul, sub);
+    m.Return(ret);
+    Stream s = m.Build(AVX);
+    ASSERT_EQ(4U, s.size());
+    EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode());
+  }
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
+    Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
+    Node* mul = m.Float64Mul(add, m.Parameter(1));
+    Node* sub = m.Float64Sub(mul, add);
+    Node* ret = m.Float64Div(mul, sub);
+    m.Return(ret);
+    Stream s = m.Build();
+    ASSERT_EQ(4U, s.size());
+    EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/instruction-selector-unittest.cc b/test/unittests/compiler/instruction-selector-unittest.cc
new file mode 100644
index 0000000..c79a9e4
--- /dev/null
+++ b/test/unittests/compiler/instruction-selector-unittest.cc
@@ -0,0 +1,589 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+#include "src/compiler/graph-inl.h"
+#include "src/flags.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+typedef RawMachineAssembler::Label MLabel;
+
+}  // namespace
+
+
+InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {}
+
+
+InstructionSelectorTest::~InstructionSelectorTest() {}
+
+
+InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
+    InstructionSelector::Features features,
+    InstructionSelectorTest::StreamBuilderMode mode) {
+  Schedule* schedule = Export();
+  if (FLAG_trace_turbo) {
+    OFStream out(stdout);
+    out << "=== Schedule before instruction selection ===" << std::endl
+        << *schedule;
+  }
+  EXPECT_NE(0, graph()->NodeCount());
+  int initial_node_count = graph()->NodeCount();
+  Linkage linkage(test_->zone(), call_descriptor());
+  InstructionBlocks* instruction_blocks =
+      InstructionSequence::InstructionBlocksFor(test_->zone(), schedule);
+  InstructionSequence sequence(test_->zone(), instruction_blocks);
+  SourcePositionTable source_position_table(graph());
+  InstructionSelector selector(test_->zone(), graph(), &linkage, &sequence,
+                               schedule, &source_position_table, features);
+  selector.SelectInstructions();
+  if (FLAG_trace_turbo) {
+    OFStream out(stdout);
+    PrintableInstructionSequence printable = {
+        RegisterConfiguration::ArchDefault(), &sequence};
+    out << "=== Code sequence after instruction selection ===" << std::endl
+        << printable;
+  }
+  Stream s;
+  // Map virtual registers.
+  {
+    const NodeToVregMap& node_map = selector.GetNodeMapForTesting();
+    for (int i = 0; i < initial_node_count; ++i) {
+      if (node_map[i] != InstructionSelector::kNodeUnmapped) {
+        s.virtual_registers_.insert(std::make_pair(i, node_map[i]));
+      }
+    }
+  }
+  std::set<int> virtual_registers;
+  for (InstructionSequence::const_iterator i = sequence.begin();
+       i != sequence.end(); ++i) {
+    Instruction* instr = *i;
+    if (instr->opcode() < 0) continue;
+    if (mode == kTargetInstructions) {
+      switch (instr->arch_opcode()) {
+#define CASE(Name) \
+  case k##Name:    \
+    break;
+        TARGET_ARCH_OPCODE_LIST(CASE)
+#undef CASE
+        default:
+          continue;
+      }
+    }
+    if (mode == kAllExceptNopInstructions && instr->arch_opcode() == kArchNop) {
+      continue;
+    }
+    for (size_t i = 0; i < instr->OutputCount(); ++i) {
+      InstructionOperand* output = instr->OutputAt(i);
+      EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
+      if (output->IsConstant()) {
+        s.constants_.insert(std::make_pair(
+            output->index(), sequence.GetConstant(output->index())));
+        virtual_registers.insert(output->index());
+      } else if (output->IsUnallocated()) {
+        virtual_registers.insert(
+            UnallocatedOperand::cast(output)->virtual_register());
+      }
+    }
+    for (size_t i = 0; i < instr->InputCount(); ++i) {
+      InstructionOperand* input = instr->InputAt(i);
+      EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
+      if (input->IsImmediate()) {
+        s.immediates_.insert(std::make_pair(
+            input->index(), sequence.GetImmediate(input->index())));
+      } else if (input->IsUnallocated()) {
+        virtual_registers.insert(
+            UnallocatedOperand::cast(input)->virtual_register());
+      }
+    }
+    s.instructions_.push_back(instr);
+  }
+  for (std::set<int>::const_iterator i = virtual_registers.begin();
+       i != virtual_registers.end(); ++i) {
+    int virtual_register = *i;
+    if (sequence.IsDouble(virtual_register)) {
+      EXPECT_FALSE(sequence.IsReference(virtual_register));
+      s.doubles_.insert(virtual_register);
+    }
+    if (sequence.IsReference(virtual_register)) {
+      EXPECT_FALSE(sequence.IsDouble(virtual_register));
+      s.references_.insert(virtual_register);
+    }
+  }
+  for (int i = 0; i < sequence.GetFrameStateDescriptorCount(); i++) {
+    s.deoptimization_entries_.push_back(sequence.GetFrameStateDescriptor(
+        InstructionSequence::StateId::FromInt(i)));
+  }
+  return s;
+}
+
+
+int InstructionSelectorTest::Stream::ToVreg(const Node* node) const {
+  VirtualRegisters::const_iterator i = virtual_registers_.find(node->id());
+  CHECK(i != virtual_registers_.end());
+  return i->second;
+}
+
+
+bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand,
+                                              Register reg) const {
+  if (!operand->IsUnallocated()) return false;
+  const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
+  if (!unallocated->HasFixedRegisterPolicy()) return false;
+  const int index = Register::ToAllocationIndex(reg);
+  return unallocated->fixed_register_index() == index;
+}
+
+
+bool InstructionSelectorTest::Stream::IsSameAsFirst(
+    const InstructionOperand* operand) const {
+  if (!operand->IsUnallocated()) return false;
+  const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
+  return unallocated->HasSameAsInputPolicy();
+}
+
+
+bool InstructionSelectorTest::Stream::IsUsedAtStart(
+    const InstructionOperand* operand) const {
+  if (!operand->IsUnallocated()) return false;
+  const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
+  return unallocated->IsUsedAtStart();
+}
+
+
+// -----------------------------------------------------------------------------
+// Return.
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReturnFloat32Constant) {
+  const float kValue = 4.2f;
+  StreamBuilder m(this, kMachFloat32);
+  m.Return(m.Float32Constant(kValue));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
+  EXPECT_FLOAT_EQ(kValue, s.ToFloat32(s[0]->OutputAt(0)));
+  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  m.Return(m.Parameter(0));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReturnZero) {
+  StreamBuilder m(this, kMachInt32);
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
+  EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0)));
+  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+}
+
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachFloat64);
+  m.Return(m.TruncateFloat64ToInt32(m.Parameter(0)));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+  EXPECT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArchRet, s[2]->arch_opcode());
+}
+
+
+// -----------------------------------------------------------------------------
+// Parameters.
+
+
+TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* param = m.Parameter(0);
+  m.Return(param);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_TRUE(s.IsDouble(param));
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
+  Node* param = m.Parameter(0);
+  m.Return(param);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_TRUE(s.IsReference(param));
+}
+
+
+// -----------------------------------------------------------------------------
+// Finish.
+
+
+TARGET_TEST_F(InstructionSelectorTest, Finish) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
+  Node* param = m.Parameter(0);
+  Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
+  m.Return(finish);
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_TRUE(s[0]->Output()->IsUnallocated());
+  EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->Output()));
+  EXPECT_EQ(kArchNop, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->InputCount());
+  ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated());
+  EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[1]->InputAt(0)));
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_TRUE(s[1]->Output()->IsUnallocated());
+  EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy());
+  EXPECT_EQ(s.ToVreg(finish), s.ToVreg(s[1]->Output()));
+  EXPECT_TRUE(s.IsReference(finish));
+}
+
+
+// -----------------------------------------------------------------------------
+// Phi.
+
+
+typedef InstructionSelectorTestWithParam<MachineType>
+    InstructionSelectorPhiTest;
+
+
+TARGET_TEST_P(InstructionSelectorPhiTest, Doubleness) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type, type);
+  Node* param0 = m.Parameter(0);
+  Node* param1 = m.Parameter(1);
+  MLabel a, b, c;
+  m.Branch(m.Int32Constant(0), &a, &b);
+  m.Bind(&a);
+  m.Goto(&c);
+  m.Bind(&b);
+  m.Goto(&c);
+  m.Bind(&c);
+  Node* phi = m.Phi(type, param0, param1);
+  m.Return(phi);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param0));
+  EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param1));
+}
+
+
+TARGET_TEST_P(InstructionSelectorPhiTest, Referenceness) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type, type);
+  Node* param0 = m.Parameter(0);
+  Node* param1 = m.Parameter(1);
+  MLabel a, b, c;
+  m.Branch(m.Int32Constant(1), &a, &b);
+  m.Bind(&a);
+  m.Goto(&c);
+  m.Bind(&b);
+  m.Goto(&c);
+  m.Bind(&c);
+  Node* phi = m.Phi(type, param0, param1);
+  m.Return(phi);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_EQ(s.IsReference(phi), s.IsReference(param0));
+  EXPECT_EQ(s.IsReference(phi), s.IsReference(param1));
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorPhiTest,
+                        ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
+                                          kMachInt16, kMachUint16, kMachInt32,
+                                          kMachUint32, kMachInt64, kMachUint64,
+                                          kMachPtr, kMachAnyTagged));
+
+
+// -----------------------------------------------------------------------------
+// ValueEffect.
+
+
+TARGET_TEST_F(InstructionSelectorTest, ValueEffect) {
+  StreamBuilder m1(this, kMachInt32, kMachPtr);
+  Node* p1 = m1.Parameter(0);
+  m1.Return(m1.Load(kMachInt32, p1, m1.Int32Constant(0)));
+  Stream s1 = m1.Build(kAllInstructions);
+  StreamBuilder m2(this, kMachInt32, kMachPtr);
+  Node* p2 = m2.Parameter(0);
+  m2.Return(m2.NewNode(m2.machine()->Load(kMachInt32), p2, m2.Int32Constant(0),
+                       m2.NewNode(m2.common()->ValueEffect(1), p2)));
+  Stream s2 = m2.Build(kAllInstructions);
+  EXPECT_LE(3U, s1.size());
+  ASSERT_EQ(s1.size(), s2.size());
+  TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) {
+    const Instruction* i1 = s1[i];
+    const Instruction* i2 = s2[i];
+    EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode());
+    EXPECT_EQ(i1->InputCount(), i2->InputCount());
+    EXPECT_EQ(i1->OutputCount(), i2->OutputCount());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Calls with deoptimization.
+
+
+TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
+                  kMachAnyTagged);
+
+  BailoutId bailout_id(42);
+
+  Node* function_node = m.Parameter(0);
+  Node* receiver = m.Parameter(1);
+  Node* context = m.Parameter(2);
+
+  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1));
+  Node* locals = m.NewNode(m.common()->StateValues(0));
+  Node* stack = m.NewNode(m.common()->StateValues(0));
+  Node* context_dummy = m.Int32Constant(0);
+
+  Node* state_node = m.NewNode(
+      m.common()->FrameState(JS_FRAME, bailout_id,
+                             OutputFrameStateCombine::Push()),
+      parameters, locals, stack, context_dummy, m.UndefinedConstant());
+  Node* call = m.CallJS0(function_node, receiver, context, state_node);
+  m.Return(call);
+
+  Stream s = m.Build(kAllExceptNopInstructions);
+
+  // Skip until kArchCallJSFunction.
+  size_t index = 0;
+  for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction;
+       index++) {
+  }
+  // Now we should have two instructions: call and return.
+  ASSERT_EQ(index + 2, s.size());
+
+  EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode());
+  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
+
+  // TODO(jarin) Check deoptimization table.
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
+                  kMachAnyTagged);
+
+  BailoutId bailout_id_before(42);
+
+  // Some arguments for the call node.
+  Node* function_node = m.Parameter(0);
+  Node* receiver = m.Parameter(1);
+  Node* context = m.Int32Constant(1);  // Context is ignored.
+
+  // Build frame state for the state before the call.
+  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
+  Node* locals = m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.5));
+  Node* stack = m.NewNode(m.common()->StateValues(1), m.UndefinedConstant());
+
+  Node* context_sentinel = m.Int32Constant(0);
+  Node* frame_state_before = m.NewNode(
+      m.common()->FrameState(JS_FRAME, bailout_id_before,
+                             OutputFrameStateCombine::Push()),
+      parameters, locals, stack, context_sentinel, m.UndefinedConstant());
+
+  // Build the call.
+  Node* call = m.CallFunctionStub0(function_node, receiver, context,
+                                   frame_state_before, CALL_AS_METHOD);
+
+  m.Return(call);
+
+  Stream s = m.Build(kAllExceptNopInstructions);
+
+  // Skip until kArchCallJSFunction.
+  size_t index = 0;
+  for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
+       index++) {
+  }
+  // Now we should have two instructions: call, return.
+  ASSERT_EQ(index + 2, s.size());
+
+  // Check the call instruction
+  const Instruction* call_instr = s[index++];
+  EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
+  size_t num_operands =
+      1 +  // Code object.
+      1 +
+      4 +  // Frame state deopt id + one input for each value in frame state.
+      1 +  // Function.
+      1;   // Context.
+  ASSERT_EQ(num_operands, call_instr->InputCount());
+
+  // Code object.
+  EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
+
+  // Deoptimization id.
+  int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
+  FrameStateDescriptor* desc_before =
+      s.GetFrameStateDescriptor(deopt_id_before);
+  EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
+  EXPECT_EQ(OutputFrameStateCombine::kPushOutput,
+            desc_before->state_combine().kind());
+  EXPECT_EQ(1u, desc_before->parameters_count());
+  EXPECT_EQ(1u, desc_before->locals_count());
+  EXPECT_EQ(1u, desc_before->stack_count());
+  EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
+  EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3)));  // This should be a context.
+                                                    // We inserted 0 here.
+  EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(4)));
+  EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(5))->IsUndefined());
+  EXPECT_EQ(kMachInt32, desc_before->GetType(0));
+  EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1));  // context is always
+                                                       // tagged/any.
+  EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
+  EXPECT_EQ(kMachAnyTagged, desc_before->GetType(3));
+
+  // Function.
+  EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6)));
+  // Context.
+  EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(7)));
+
+  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
+
+  EXPECT_EQ(index, s.size());
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest,
+              CallFunctionStubDeoptRecursiveFrameState) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
+                  kMachAnyTagged);
+
+  BailoutId bailout_id_before(42);
+  BailoutId bailout_id_parent(62);
+
+  // Some arguments for the call node.
+  Node* function_node = m.Parameter(0);
+  Node* receiver = m.Parameter(1);
+  Node* context = m.Int32Constant(66);
+
+  // Build frame state for the state before the call.
+  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
+  Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
+  Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
+  Node* frame_state_parent =
+      m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent,
+                                       OutputFrameStateCombine::Ignore()),
+                parameters, locals, stack, context, m.UndefinedConstant());
+
+  Node* context2 = m.Int32Constant(46);
+  Node* parameters2 =
+      m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
+  Node* locals2 =
+      m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.25));
+  Node* stack2 = m.NewNode(m.common()->StateValues(2), m.Int32Constant(44),
+                           m.Int32Constant(45));
+  Node* frame_state_before =
+      m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
+                                       OutputFrameStateCombine::Push()),
+                parameters2, locals2, stack2, context2, frame_state_parent);
+
+  // Build the call.
+  Node* call = m.CallFunctionStub0(function_node, receiver, context2,
+                                   frame_state_before, CALL_AS_METHOD);
+
+  m.Return(call);
+
+  Stream s = m.Build(kAllExceptNopInstructions);
+
+  // Skip until kArchCallJSFunction.
+  size_t index = 0;
+  for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
+       index++) {
+  }
+  // Now we should have three instructions: call, return.
+  EXPECT_EQ(index + 2, s.size());
+
+  // Check the call instruction
+  const Instruction* call_instr = s[index++];
+  EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
+  size_t num_operands =
+      1 +  // Code object.
+      1 +  // Frame state deopt id
+      5 +  // One input for each value in frame state + context.
+      4 +  // One input for each value in the parent frame state + context.
+      1 +  // Function.
+      1;   // Context.
+  EXPECT_EQ(num_operands, call_instr->InputCount());
+  // Code object.
+  EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
+
+  // Deoptimization id.
+  int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
+  FrameStateDescriptor* desc_before =
+      s.GetFrameStateDescriptor(deopt_id_before);
+  FrameStateDescriptor* desc_before_outer = desc_before->outer_state();
+  EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
+  EXPECT_EQ(1u, desc_before_outer->parameters_count());
+  EXPECT_EQ(1u, desc_before_outer->locals_count());
+  EXPECT_EQ(1u, desc_before_outer->stack_count());
+  // Values from parent environment.
+  EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
+  EXPECT_EQ(kMachInt32, desc_before_outer->GetType(0));
+  // Context:
+  EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
+  EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(1));
+  EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4)));
+  EXPECT_EQ(kMachInt32, desc_before_outer->GetType(2));
+  EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5)));
+  EXPECT_EQ(kMachInt32, desc_before_outer->GetType(3));
+  // Values from the nested frame.
+  EXPECT_EQ(1u, desc_before->parameters_count());
+  EXPECT_EQ(1u, desc_before->locals_count());
+  EXPECT_EQ(2u, desc_before->stack_count());
+  EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6)));
+  EXPECT_EQ(kMachInt32, desc_before->GetType(0));
+  EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
+  EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1));
+  EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(8)));
+  EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
+  EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(9)));
+  EXPECT_EQ(kMachInt32, desc_before->GetType(3));
+  EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(10)));
+  EXPECT_EQ(kMachInt32, desc_before->GetType(4));
+
+  // Function.
+  EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(11)));
+  // Context.
+  EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(12)));
+  // Continuation.
+
+  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
+  EXPECT_EQ(index, s.size());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/instruction-selector-unittest.h b/test/unittests/compiler/instruction-selector-unittest.h
new file mode 100644
index 0000000..e65d68b
--- /dev/null
+++ b/test/unittests/compiler/instruction-selector-unittest.h
@@ -0,0 +1,241 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
+#define V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
+
+#include <deque>
+#include <set>
+
+#include "src/base/utils/random-number-generator.h"
+#include "src/compiler/instruction-selector.h"
+#include "src/compiler/raw-machine-assembler.h"
+#include "src/macro-assembler.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class InstructionSelectorTest : public TestWithContext, public TestWithZone {
+ public:
+  InstructionSelectorTest();
+  ~InstructionSelectorTest() OVERRIDE;
+
+  base::RandomNumberGenerator* rng() { return &rng_; }
+
+  class Stream;
+
+  enum StreamBuilderMode {
+    kAllInstructions,
+    kTargetInstructions,
+    kAllExceptNopInstructions
+  };
+
+  class StreamBuilder FINAL : public RawMachineAssembler {
+   public:
+    StreamBuilder(InstructionSelectorTest* test, MachineType return_type)
+        : RawMachineAssembler(new (test->zone()) Graph(test->zone()),
+                              MakeMachineSignature(test->zone(), return_type)),
+          test_(test) {}
+    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
+                  MachineType parameter0_type)
+        : RawMachineAssembler(
+              new (test->zone()) Graph(test->zone()),
+              MakeMachineSignature(test->zone(), return_type, parameter0_type)),
+          test_(test) {}
+    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
+                  MachineType parameter0_type, MachineType parameter1_type)
+        : RawMachineAssembler(
+              new (test->zone()) Graph(test->zone()),
+              MakeMachineSignature(test->zone(), return_type, parameter0_type,
+                                   parameter1_type)),
+          test_(test) {}
+    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
+                  MachineType parameter0_type, MachineType parameter1_type,
+                  MachineType parameter2_type)
+        : RawMachineAssembler(
+              new (test->zone()) Graph(test->zone()),
+              MakeMachineSignature(test->zone(), return_type, parameter0_type,
+                                   parameter1_type, parameter2_type)),
+          test_(test) {}
+
+    Stream Build(CpuFeature feature) {
+      return Build(InstructionSelector::Features(feature));
+    }
+    Stream Build(CpuFeature feature1, CpuFeature feature2) {
+      return Build(InstructionSelector::Features(feature1, feature2));
+    }
+    Stream Build(StreamBuilderMode mode = kTargetInstructions) {
+      return Build(InstructionSelector::Features(), mode);
+    }
+    Stream Build(InstructionSelector::Features features,
+                 StreamBuilderMode mode = kTargetInstructions);
+
+   private:
+    MachineSignature* MakeMachineSignature(Zone* zone,
+                                           MachineType return_type) {
+      MachineSignature::Builder builder(zone, 1, 0);
+      builder.AddReturn(return_type);
+      return builder.Build();
+    }
+
+    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
+                                           MachineType parameter0_type) {
+      MachineSignature::Builder builder(zone, 1, 1);
+      builder.AddReturn(return_type);
+      builder.AddParam(parameter0_type);
+      return builder.Build();
+    }
+
+    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
+                                           MachineType parameter0_type,
+                                           MachineType parameter1_type) {
+      MachineSignature::Builder builder(zone, 1, 2);
+      builder.AddReturn(return_type);
+      builder.AddParam(parameter0_type);
+      builder.AddParam(parameter1_type);
+      return builder.Build();
+    }
+
+    MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
+                                           MachineType parameter0_type,
+                                           MachineType parameter1_type,
+                                           MachineType parameter2_type) {
+      MachineSignature::Builder builder(zone, 1, 3);
+      builder.AddReturn(return_type);
+      builder.AddParam(parameter0_type);
+      builder.AddParam(parameter1_type);
+      builder.AddParam(parameter2_type);
+      return builder.Build();
+    }
+
+   private:
+    InstructionSelectorTest* test_;
+  };
+
+  class Stream FINAL {
+   public:
+    size_t size() const { return instructions_.size(); }
+    const Instruction* operator[](size_t index) const {
+      EXPECT_LT(index, size());
+      return instructions_[index];
+    }
+
+    bool IsDouble(const InstructionOperand* operand) const {
+      return IsDouble(ToVreg(operand));
+    }
+
+    bool IsDouble(const Node* node) const { return IsDouble(ToVreg(node)); }
+
+    bool IsInteger(const InstructionOperand* operand) const {
+      return IsInteger(ToVreg(operand));
+    }
+
+    bool IsInteger(const Node* node) const { return IsInteger(ToVreg(node)); }
+
+    bool IsReference(const InstructionOperand* operand) const {
+      return IsReference(ToVreg(operand));
+    }
+
+    bool IsReference(const Node* node) const {
+      return IsReference(ToVreg(node));
+    }
+
+    float ToFloat32(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToFloat32();
+    }
+
+    double ToFloat64(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToFloat64();
+    }
+
+    int32_t ToInt32(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToInt32();
+    }
+
+    int64_t ToInt64(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToInt64();
+    }
+
+    Handle<HeapObject> ToHeapObject(const InstructionOperand* operand) const {
+      return ToConstant(operand).ToHeapObject();
+    }
+
+    int ToVreg(const InstructionOperand* operand) const {
+      if (operand->IsConstant()) return operand->index();
+      EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());
+      return UnallocatedOperand::cast(operand)->virtual_register();
+    }
+
+    int ToVreg(const Node* node) const;
+
+    bool IsFixed(const InstructionOperand* operand, Register reg) const;
+    bool IsSameAsFirst(const InstructionOperand* operand) const;
+    bool IsUsedAtStart(const InstructionOperand* operand) const;
+
+    FrameStateDescriptor* GetFrameStateDescriptor(int deoptimization_id) {
+      EXPECT_LT(deoptimization_id, GetFrameStateDescriptorCount());
+      return deoptimization_entries_[deoptimization_id];
+    }
+
+    int GetFrameStateDescriptorCount() {
+      return static_cast<int>(deoptimization_entries_.size());
+    }
+
+   private:
+    bool IsDouble(int virtual_register) const {
+      return doubles_.find(virtual_register) != doubles_.end();
+    }
+
+    bool IsInteger(int virtual_register) const {
+      return !IsDouble(virtual_register) && !IsReference(virtual_register);
+    }
+
+    bool IsReference(int virtual_register) const {
+      return references_.find(virtual_register) != references_.end();
+    }
+
+    Constant ToConstant(const InstructionOperand* operand) const {
+      ConstantMap::const_iterator i;
+      if (operand->IsConstant()) {
+        i = constants_.find(operand->index());
+        EXPECT_FALSE(constants_.end() == i);
+      } else {
+        EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind());
+        i = immediates_.find(operand->index());
+        EXPECT_FALSE(immediates_.end() == i);
+      }
+      EXPECT_EQ(operand->index(), i->first);
+      return i->second;
+    }
+
+    friend class StreamBuilder;
+
+    typedef std::map<int, Constant> ConstantMap;
+    typedef std::map<NodeId, int> VirtualRegisters;
+
+    ConstantMap constants_;
+    ConstantMap immediates_;
+    std::deque<Instruction*> instructions_;
+    std::set<int> doubles_;
+    std::set<int> references_;
+    VirtualRegisters virtual_registers_;
+    std::deque<FrameStateDescriptor*> deoptimization_entries_;
+  };
+
+  base::RandomNumberGenerator rng_;
+};
+
+
+template <typename T>
+class InstructionSelectorTestWithParam
+    : public InstructionSelectorTest,
+      public ::testing::WithParamInterface<T> {};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
diff --git a/test/unittests/compiler/instruction-sequence-unittest.cc b/test/unittests/compiler/instruction-sequence-unittest.cc
new file mode 100644
index 0000000..9546376
--- /dev/null
+++ b/test/unittests/compiler/instruction-sequence-unittest.cc
@@ -0,0 +1,475 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/utils/random-number-generator.h"
+#include "src/compiler/pipeline.h"
+#include "test/unittests/compiler/instruction-sequence-unittest.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+static const char*
+    general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
+static const char*
+    double_register_names_[RegisterConfiguration::kMaxDoubleRegisters];
+static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
+                                  RegisterConfiguration::kMaxDoubleRegisters)];
+
+
+static void InitializeRegisterNames() {
+  char* loc = register_names_;
+  for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
+    general_register_names_[i] = loc;
+    loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
+    *loc++ = 0;
+  }
+  for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) {
+    double_register_names_[i] = loc;
+    loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
+    *loc++ = 0;
+  }
+}
+
+
+InstructionSequenceTest::InstructionSequenceTest()
+    : sequence_(nullptr),
+      num_general_registers_(kDefaultNRegs),
+      num_double_registers_(kDefaultNRegs),
+      instruction_blocks_(zone()),
+      current_instruction_index_(-1),
+      current_block_(nullptr),
+      block_returns_(false) {
+  InitializeRegisterNames();
+}
+
+
+void InstructionSequenceTest::SetNumRegs(int num_general_registers,
+                                         int num_double_registers) {
+  CHECK(config_.is_empty());
+  CHECK(instructions_.empty());
+  CHECK(instruction_blocks_.empty());
+  num_general_registers_ = num_general_registers;
+  num_double_registers_ = num_double_registers;
+}
+
+
+RegisterConfiguration* InstructionSequenceTest::config() {
+  if (config_.is_empty()) {
+    config_.Reset(new RegisterConfiguration(
+        num_general_registers_, num_double_registers_, num_double_registers_,
+        general_register_names_, double_register_names_));
+  }
+  return config_.get();
+}
+
+
+InstructionSequence* InstructionSequenceTest::sequence() {
+  if (sequence_ == nullptr) {
+    sequence_ = new (zone()) InstructionSequence(zone(), &instruction_blocks_);
+  }
+  return sequence_;
+}
+
+
+void InstructionSequenceTest::StartLoop(int loop_blocks) {
+  CHECK(current_block_ == nullptr);
+  if (!loop_blocks_.empty()) {
+    CHECK(!loop_blocks_.back().loop_header_.IsValid());
+  }
+  LoopData loop_data = {Rpo::Invalid(), loop_blocks};
+  loop_blocks_.push_back(loop_data);
+}
+
+
+void InstructionSequenceTest::EndLoop() {
+  CHECK(current_block_ == nullptr);
+  CHECK(!loop_blocks_.empty());
+  CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
+  loop_blocks_.pop_back();
+}
+
+
+void InstructionSequenceTest::StartBlock() {
+  block_returns_ = false;
+  NewBlock();
+}
+
+
+int InstructionSequenceTest::EndBlock(BlockCompletion completion) {
+  int instruction_index = kMinInt;
+  if (block_returns_) {
+    CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
+    completion.type_ = kBlockEnd;
+  }
+  switch (completion.type_) {
+    case kBlockEnd:
+      break;
+    case kFallThrough:
+      instruction_index = EmitFallThrough();
+      break;
+    case kJump:
+      CHECK(!block_returns_);
+      instruction_index = EmitJump();
+      break;
+    case kBranch:
+      CHECK(!block_returns_);
+      instruction_index = EmitBranch(completion.op_);
+      break;
+  }
+  completions_.push_back(completion);
+  CHECK(current_block_ != nullptr);
+  sequence()->EndBlock(current_block_->rpo_number());
+  current_block_ = nullptr;
+  return instruction_index;
+}
+
+
+InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) {
+  int index = sequence()->AddImmediate(Constant(imm));
+  return TestOperand(kImmediate, index);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::Define(
+    TestOperand output_op) {
+  VReg vreg = NewReg();
+  InstructionOperand* outputs[1]{ConvertOutputOp(vreg, output_op)};
+  Emit(vreg.value_, kArchNop, 1, outputs);
+  return vreg;
+}
+
+
+int InstructionSequenceTest::Return(TestOperand input_op_0) {
+  block_returns_ = true;
+  InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
+  return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
+}
+
+
+PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
+                                             VReg incoming_vreg_1,
+                                             VReg incoming_vreg_2,
+                                             VReg incoming_vreg_3) {
+  auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, 10);
+  VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2,
+                   incoming_vreg_3};
+  for (size_t i = 0; i < arraysize(inputs); ++i) {
+    if (inputs[i].value_ == kNoValue) break;
+    Extend(phi, inputs[i]);
+  }
+  current_block_->AddPhi(phi);
+  return phi;
+}
+
+
+void InstructionSequenceTest::Extend(PhiInstruction* phi, VReg vreg) {
+  phi->Extend(zone(), vreg.value_);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
+    int32_t imm) {
+  VReg vreg = NewReg();
+  sequence()->AddConstant(vreg.value_, Constant(imm));
+  InstructionOperand* outputs[1]{ConstantOperand::Create(vreg.value_, zone())};
+  Emit(vreg.value_, kArchNop, 1, outputs);
+  return vreg;
+}
+
+
+int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); }
+
+
+static size_t CountInputs(size_t size,
+                          InstructionSequenceTest::TestOperand* inputs) {
+  size_t i = 0;
+  for (; i < size; ++i) {
+    if (inputs[i].type_ == InstructionSequenceTest::kInvalid) break;
+  }
+  return i;
+}
+
+
+int InstructionSequenceTest::EmitI(size_t input_size, TestOperand* inputs) {
+  InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
+  return Emit(NewIndex(), kArchNop, 0, nullptr, input_size, mapped_inputs);
+}
+
+
+int InstructionSequenceTest::EmitI(TestOperand input_op_0,
+                                   TestOperand input_op_1,
+                                   TestOperand input_op_2,
+                                   TestOperand input_op_3) {
+  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
+  return EmitI(CountInputs(arraysize(inputs), inputs), inputs);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
+    TestOperand output_op, size_t input_size, TestOperand* inputs) {
+  VReg output_vreg = NewReg();
+  InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
+  InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
+  Emit(output_vreg.value_, kArchNop, 1, outputs, input_size, mapped_inputs);
+  return output_vreg;
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
+    TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
+    TestOperand input_op_2, TestOperand input_op_3) {
+  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
+  return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
+    TestOperand output_op, size_t input_size, TestOperand* inputs) {
+  VReg output_vreg = NewReg();
+  InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
+  CHECK(UnallocatedOperand::cast(outputs[0])->HasFixedPolicy());
+  InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
+  Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size,
+       mapped_inputs, 0, nullptr, true);
+  return output_vreg;
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
+    TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
+    TestOperand input_op_2, TestOperand input_op_3) {
+  TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
+  return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs);
+}
+
+
+const Instruction* InstructionSequenceTest::GetInstruction(
+    int instruction_index) {
+  auto it = instructions_.find(instruction_index);
+  CHECK(it != instructions_.end());
+  return it->second;
+}
+
+
+int InstructionSequenceTest::EmitBranch(TestOperand input_op) {
+  InstructionOperand* inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()),
+                                ConvertInputOp(Imm()), ConvertInputOp(Imm())};
+  InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
+                           FlagsConditionField::encode(kEqual);
+  auto instruction =
+      NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
+  return AddInstruction(NewIndex(), instruction);
+}
+
+
+int InstructionSequenceTest::EmitFallThrough() {
+  auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
+  return AddInstruction(NewIndex(), instruction);
+}
+
+
+int InstructionSequenceTest::EmitJump() {
+  InstructionOperand* inputs[1]{ConvertInputOp(Imm())};
+  auto instruction =
+      NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
+  return AddInstruction(NewIndex(), instruction);
+}
+
+
+Instruction* InstructionSequenceTest::NewInstruction(
+    InstructionCode code, size_t outputs_size, InstructionOperand** outputs,
+    size_t inputs_size, InstructionOperand** inputs, size_t temps_size,
+    InstructionOperand** temps) {
+  CHECK_NE(nullptr, current_block_);
+  return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
+                          inputs, temps_size, temps);
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+    TestOperand op, UnallocatedOperand::ExtendedPolicy policy) {
+  auto unallocated = new (zone()) UnallocatedOperand(policy);
+  unallocated->set_virtual_register(op.vreg_.value_);
+  return unallocated;
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+    TestOperand op, UnallocatedOperand::ExtendedPolicy policy,
+    UnallocatedOperand::Lifetime lifetime) {
+  auto unallocated = new (zone()) UnallocatedOperand(policy, lifetime);
+  unallocated->set_virtual_register(op.vreg_.value_);
+  return unallocated;
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+    TestOperand op, UnallocatedOperand::ExtendedPolicy policy, int index) {
+  auto unallocated = new (zone()) UnallocatedOperand(policy, index);
+  unallocated->set_virtual_register(op.vreg_.value_);
+  return unallocated;
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+    TestOperand op, UnallocatedOperand::BasicPolicy policy, int index) {
+  auto unallocated = new (zone()) UnallocatedOperand(policy, index);
+  unallocated->set_virtual_register(op.vreg_.value_);
+  return unallocated;
+}
+
+
+InstructionOperand** InstructionSequenceTest::ConvertInputs(
+    size_t input_size, TestOperand* inputs) {
+  InstructionOperand** mapped_inputs =
+      zone()->NewArray<InstructionOperand*>(static_cast<int>(input_size));
+  for (size_t i = 0; i < input_size; ++i) {
+    mapped_inputs[i] = ConvertInputOp(inputs[i]);
+  }
+  return mapped_inputs;
+}
+
+
+InstructionOperand* InstructionSequenceTest::ConvertInputOp(TestOperand op) {
+  if (op.type_ == kImmediate) {
+    CHECK_EQ(op.vreg_.value_, kNoValue);
+    return ImmediateOperand::Create(op.value_, zone());
+  }
+  CHECK_NE(op.vreg_.value_, kNoValue);
+  switch (op.type_) {
+    case kNone:
+      return Unallocated(op, UnallocatedOperand::NONE,
+                         UnallocatedOperand::USED_AT_START);
+    case kUnique:
+      return Unallocated(op, UnallocatedOperand::NONE);
+    case kUniqueRegister:
+      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
+    case kRegister:
+      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
+                         UnallocatedOperand::USED_AT_START);
+    case kFixedRegister:
+      CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
+      return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
+    case kFixedSlot:
+      return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
+    default:
+      break;
+  }
+  CHECK(false);
+  return NULL;
+}
+
+
+InstructionOperand* InstructionSequenceTest::ConvertOutputOp(VReg vreg,
+                                                             TestOperand op) {
+  CHECK_EQ(op.vreg_.value_, kNoValue);
+  op.vreg_ = vreg;
+  switch (op.type_) {
+    case kSameAsFirst:
+      return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
+    case kRegister:
+      return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
+    case kFixedSlot:
+      return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
+    case kFixedRegister:
+      CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
+      return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
+    default:
+      break;
+  }
+  CHECK(false);
+  return NULL;
+}
+
+
+InstructionBlock* InstructionSequenceTest::NewBlock() {
+  CHECK(current_block_ == nullptr);
+  auto block_id = BasicBlock::Id::FromSize(instruction_blocks_.size());
+  Rpo rpo = Rpo::FromInt(block_id.ToInt());
+  Rpo loop_header = Rpo::Invalid();
+  Rpo loop_end = Rpo::Invalid();
+  if (!loop_blocks_.empty()) {
+    auto& loop_data = loop_blocks_.back();
+    // This is a loop header.
+    if (!loop_data.loop_header_.IsValid()) {
+      loop_end = Rpo::FromInt(block_id.ToInt() + loop_data.expected_blocks_);
+      loop_data.expected_blocks_--;
+      loop_data.loop_header_ = rpo;
+    } else {
+      // This is a loop body.
+      CHECK_NE(0, loop_data.expected_blocks_);
+      // TODO(dcarney): handle nested loops.
+      loop_data.expected_blocks_--;
+      loop_header = loop_data.loop_header_;
+    }
+  }
+  // Construct instruction block.
+  auto instruction_block = new (zone())
+      InstructionBlock(zone(), block_id, rpo, loop_header, loop_end, false);
+  instruction_blocks_.push_back(instruction_block);
+  current_block_ = instruction_block;
+  sequence()->StartBlock(rpo);
+  return instruction_block;
+}
+
+
+void InstructionSequenceTest::WireBlocks() {
+  CHECK_EQ(nullptr, current_block());
+  CHECK(instruction_blocks_.size() == completions_.size());
+  size_t offset = 0;
+  for (const auto& completion : completions_) {
+    switch (completion.type_) {
+      case kBlockEnd:
+        break;
+      case kFallThrough:  // Fallthrough.
+      case kJump:
+        WireBlock(offset, completion.offset_0_);
+        break;
+      case kBranch:
+        WireBlock(offset, completion.offset_0_);
+        WireBlock(offset, completion.offset_1_);
+        break;
+    }
+    ++offset;
+  }
+}
+
+
+void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
+  size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset);
+  CHECK(block_offset < instruction_blocks_.size());
+  CHECK(target_block_offset < instruction_blocks_.size());
+  auto block = instruction_blocks_[block_offset];
+  auto target = instruction_blocks_[target_block_offset];
+  block->successors().push_back(target->rpo_number());
+  target->predecessors().push_back(block->rpo_number());
+}
+
+
+int InstructionSequenceTest::Emit(int instruction_index, InstructionCode code,
+                                  size_t outputs_size,
+                                  InstructionOperand** outputs,
+                                  size_t inputs_size,
+                                  InstructionOperand** inputs,
+                                  size_t temps_size, InstructionOperand** temps,
+                                  bool is_call) {
+  auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
+                                    inputs, temps_size, temps);
+  if (is_call) instruction->MarkAsCall();
+  return AddInstruction(instruction_index, instruction);
+}
+
+
+int InstructionSequenceTest::AddInstruction(int instruction_index,
+                                            Instruction* instruction) {
+  sequence()->AddInstruction(instruction);
+  return instruction_index;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/instruction-sequence-unittest.h b/test/unittests/compiler/instruction-sequence-unittest.h
new file mode 100644
index 0000000..ce0a5b4
--- /dev/null
+++ b/test/unittests/compiler/instruction-sequence-unittest.h
@@ -0,0 +1,239 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
+#define V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
+
+#include "src/compiler/instruction.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class InstructionSequenceTest : public TestWithZone {
+ public:
+  static const int kDefaultNRegs = 4;
+  static const int kNoValue = kMinInt;
+
+  typedef BasicBlock::RpoNumber Rpo;
+
+  struct VReg {
+    VReg() : value_(kNoValue) {}
+    VReg(PhiInstruction* phi) : value_(phi->virtual_register()) {}  // NOLINT
+    explicit VReg(int value) : value_(value) {}
+    int value_;
+  };
+
+  enum TestOperandType {
+    kInvalid,
+    kSameAsFirst,
+    kRegister,
+    kFixedRegister,
+    kSlot,
+    kFixedSlot,
+    kImmediate,
+    kNone,
+    kConstant,
+    kUnique,
+    kUniqueRegister
+  };
+
+  struct TestOperand {
+    TestOperand() : type_(kInvalid), vreg_(), value_(kNoValue) {}
+    TestOperand(TestOperandType type, int imm)
+        : type_(type), vreg_(), value_(imm) {}
+    TestOperand(TestOperandType type, VReg vreg, int value = kNoValue)
+        : type_(type), vreg_(vreg), value_(value) {}
+
+    TestOperandType type_;
+    VReg vreg_;
+    int value_;
+  };
+
+  static TestOperand Same() { return TestOperand(kSameAsFirst, VReg()); }
+
+  static TestOperand Reg(VReg vreg, int index = kNoValue) {
+    TestOperandType type = kRegister;
+    if (index != kNoValue) type = kFixedRegister;
+    return TestOperand(type, vreg, index);
+  }
+
+  static TestOperand Reg(int index = kNoValue) { return Reg(VReg(), index); }
+
+  static TestOperand Slot(VReg vreg, int index = kNoValue) {
+    TestOperandType type = kSlot;
+    if (index != kNoValue) type = kFixedSlot;
+    return TestOperand(type, vreg, index);
+  }
+
+  static TestOperand Slot(int index = kNoValue) { return Slot(VReg(), index); }
+
+  static TestOperand Const(int index) {
+    CHECK_NE(kNoValue, index);
+    return TestOperand(kConstant, VReg(), index);
+  }
+
+  static TestOperand Use(VReg vreg) { return TestOperand(kNone, vreg); }
+
+  static TestOperand Use() { return Use(VReg()); }
+
+  static TestOperand Unique(VReg vreg) { return TestOperand(kUnique, vreg); }
+
+  static TestOperand UniqueReg(VReg vreg) {
+    return TestOperand(kUniqueRegister, vreg);
+  }
+
+  enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
+
+  struct BlockCompletion {
+    BlockCompletionType type_;
+    TestOperand op_;
+    int offset_0_;
+    int offset_1_;
+  };
+
+  static BlockCompletion FallThrough() {
+    BlockCompletion completion = {kFallThrough, TestOperand(), 1, kNoValue};
+    return completion;
+  }
+
+  static BlockCompletion Jump(int offset) {
+    BlockCompletion completion = {kJump, TestOperand(), offset, kNoValue};
+    return completion;
+  }
+
+  static BlockCompletion Branch(TestOperand op, int left_offset,
+                                int right_offset) {
+    BlockCompletion completion = {kBranch, op, left_offset, right_offset};
+    return completion;
+  }
+
+  static BlockCompletion Last() {
+    BlockCompletion completion = {kBlockEnd, TestOperand(), kNoValue, kNoValue};
+    return completion;
+  }
+
+  InstructionSequenceTest();
+
+  void SetNumRegs(int num_general_registers, int num_double_registers);
+  RegisterConfiguration* config();
+  InstructionSequence* sequence();
+
+  void StartLoop(int loop_blocks);
+  void EndLoop();
+  void StartBlock();
+  int EndBlock(BlockCompletion completion = FallThrough());
+
+  TestOperand Imm(int32_t imm = 0);
+  VReg Define(TestOperand output_op);
+  VReg Parameter(TestOperand output_op = Reg()) { return Define(output_op); }
+
+  int Return(TestOperand input_op_0);
+  int Return(VReg vreg) { return Return(Reg(vreg, 0)); }
+
+  PhiInstruction* Phi(VReg incoming_vreg_0 = VReg(),
+                      VReg incoming_vreg_1 = VReg(),
+                      VReg incoming_vreg_2 = VReg(),
+                      VReg incoming_vreg_3 = VReg());
+  void Extend(PhiInstruction* phi, VReg vreg);
+
+  VReg DefineConstant(int32_t imm = 0);
+  int EmitNop();
+  int EmitI(size_t input_size, TestOperand* inputs);
+  int EmitI(TestOperand input_op_0 = TestOperand(),
+            TestOperand input_op_1 = TestOperand(),
+            TestOperand input_op_2 = TestOperand(),
+            TestOperand input_op_3 = TestOperand());
+  VReg EmitOI(TestOperand output_op, size_t input_size, TestOperand* inputs);
+  VReg EmitOI(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
+              TestOperand input_op_1 = TestOperand(),
+              TestOperand input_op_2 = TestOperand(),
+              TestOperand input_op_3 = TestOperand());
+  VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs);
+  VReg EmitCall(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
+                TestOperand input_op_1 = TestOperand(),
+                TestOperand input_op_2 = TestOperand(),
+                TestOperand input_op_3 = TestOperand());
+
+  // Get defining instruction vreg or value returned at instruction creation
+  // time when there is no return value.
+  const Instruction* GetInstruction(int instruction_index);
+
+  InstructionBlock* current_block() const { return current_block_; }
+  int num_general_registers() const { return num_general_registers_; }
+  int num_double_registers() const { return num_double_registers_; }
+
+  // Called after all instructions have been inserted.
+  void WireBlocks();
+
+ private:
+  VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); }
+  int NewIndex() { return current_instruction_index_--; }
+
+  static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); }
+
+  int EmitBranch(TestOperand input_op);
+  int EmitFallThrough();
+  int EmitJump();
+  Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
+                              InstructionOperand** outputs,
+                              size_t inputs_size = 0,
+                              InstructionOperand* *inputs = nullptr,
+                              size_t temps_size = 0,
+                              InstructionOperand* *temps = nullptr);
+  InstructionOperand* Unallocated(TestOperand op,
+                                  UnallocatedOperand::ExtendedPolicy policy);
+  InstructionOperand* Unallocated(TestOperand op,
+                                  UnallocatedOperand::ExtendedPolicy policy,
+                                  UnallocatedOperand::Lifetime lifetime);
+  InstructionOperand* Unallocated(TestOperand op,
+                                  UnallocatedOperand::ExtendedPolicy policy,
+                                  int index);
+  InstructionOperand* Unallocated(TestOperand op,
+                                  UnallocatedOperand::BasicPolicy policy,
+                                  int index);
+  InstructionOperand** ConvertInputs(size_t input_size, TestOperand* inputs);
+  InstructionOperand* ConvertInputOp(TestOperand op);
+  InstructionOperand* ConvertOutputOp(VReg vreg, TestOperand op);
+  InstructionBlock* NewBlock();
+  void WireBlock(size_t block_offset, int jump_offset);
+
+  int Emit(int instruction_index, InstructionCode code, size_t outputs_size = 0,
+           InstructionOperand* *outputs = nullptr, size_t inputs_size = 0,
+           InstructionOperand* *inputs = nullptr, size_t temps_size = 0,
+           InstructionOperand* *temps = nullptr, bool is_call = false);
+
+  int AddInstruction(int instruction_index, Instruction* instruction);
+
+  struct LoopData {
+    Rpo loop_header_;
+    int expected_blocks_;
+  };
+
+  typedef std::vector<LoopData> LoopBlocks;
+  typedef std::map<int, const Instruction*> Instructions;
+  typedef std::vector<BlockCompletion> Completions;
+
+  SmartPointer<RegisterConfiguration> config_;
+  InstructionSequence* sequence_;
+  int num_general_registers_;
+  int num_double_registers_;
+
+  // Block building state.
+  InstructionBlocks instruction_blocks_;
+  Instructions instructions_;
+  int current_instruction_index_;
+  Completions completions_;
+  LoopBlocks loop_blocks_;
+  InstructionBlock* current_block_;
+  bool block_returns_;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_INSTRUCTION_SEQUENCE_UNITTEST_H_
diff --git a/test/unittests/compiler/js-builtin-reducer-unittest.cc b/test/unittests/compiler/js-builtin-reducer-unittest.cc
new file mode 100644
index 0000000..9c57282
--- /dev/null
+++ b/test/unittests/compiler/js-builtin-reducer-unittest.cc
@@ -0,0 +1,303 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/js-builtin-reducer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/typer.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::BitEq;
+using testing::Capture;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class JSBuiltinReducerTest : public TypedGraphTest {
+ public:
+  JSBuiltinReducerTest() : javascript_(zone()) {}
+
+ protected:
+  Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
+                                   MachineOperatorBuilder::Flag::kNoFlags) {
+    MachineOperatorBuilder machine(zone(), kMachPtr, flags);
+    JSGraph jsgraph(graph(), common(), javascript(), &machine);
+    JSBuiltinReducer reducer(&jsgraph);
+    return reducer.Reduce(node);
+  }
+
+  Handle<JSFunction> MathFunction(const char* name) {
+    Handle<Object> m =
+        JSObject::GetProperty(isolate()->global_object(),
+                              isolate()->factory()->NewStringFromAsciiChecked(
+                                  "Math")).ToHandleChecked();
+    Handle<JSFunction> f = Handle<JSFunction>::cast(
+        JSObject::GetProperty(
+            m, isolate()->factory()->NewStringFromAsciiChecked(name))
+            .ToHandleChecked());
+    return f;
+  }
+
+  JSOperatorBuilder* javascript() { return &javascript_; }
+
+ private:
+  JSOperatorBuilder javascript_;
+};
+
+
+namespace {
+
+// TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
+Type* const kNumberTypes[] = {
+    Type::UnsignedSmall(),       Type::NegativeSigned32(),
+    Type::NonNegativeSigned32(), Type::SignedSmall(),
+    Type::Signed32(),            Type::Unsigned32(),
+    Type::Integral32(),          Type::MinusZero(),
+    Type::NaN(),                 Type::OrderedNumber(),
+    Type::PlainNumber(),         Type::Number()};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Math.abs
+
+
+TEST_F(JSBuiltinReducerTest, MathAbs) {
+  Handle<JSFunction> f = MathFunction("abs");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call);
+
+    if (t0->Is(Type::Unsigned32())) {
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), p0);
+    } else {
+      Capture<Node*> branch;
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsSelect(kMachNone,
+                   IsNumberLessThan(IsNumberConstant(BitEq(0.0)), p0), p0,
+                   IsNumberSubtract(IsNumberConstant(BitEq(0.0)), p0)));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.sqrt
+
+
+TEST_F(JSBuiltinReducerTest, MathSqrt) {
+  Handle<JSFunction> f = MathFunction("sqrt");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.max
+
+
+TEST_F(JSBuiltinReducerTest, MathMax0) {
+  Handle<JSFunction> f = MathFunction("max");
+
+  Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+  Node* call =
+      graph()->NewNode(javascript()->CallFunction(2, NO_CALL_FUNCTION_FLAGS),
+                       fun, UndefinedConstant());
+  Reduction r = Reduce(call);
+
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
+}
+
+
+TEST_F(JSBuiltinReducerTest, MathMax1) {
+  Handle<JSFunction> f = MathFunction("max");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), p0);
+  }
+}
+
+
+TEST_F(JSBuiltinReducerTest, MathMax2) {
+  Handle<JSFunction> f = MathFunction("max");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    TRACED_FOREACH(Type*, t1, kNumberTypes) {
+      Node* p0 = Parameter(t0, 0);
+      Node* p1 = Parameter(t1, 1);
+      Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+      Node* call = graph()->NewNode(
+          javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
+          UndefinedConstant(), p0, p1);
+      Reduction r = Reduce(call);
+
+      if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
+        ASSERT_TRUE(r.Changed());
+        EXPECT_THAT(r.replacement(),
+                    IsSelect(kMachNone, IsNumberLessThan(p1, p0), p1, p0));
+      } else {
+        ASSERT_FALSE(r.Changed());
+        EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
+      }
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.imul
+
+
+TEST_F(JSBuiltinReducerTest, MathImul) {
+  Handle<JSFunction> f = MathFunction("imul");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    TRACED_FOREACH(Type*, t1, kNumberTypes) {
+      Node* p0 = Parameter(t0, 0);
+      Node* p1 = Parameter(t1, 1);
+      Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+      Node* call = graph()->NewNode(
+          javascript()->CallFunction(4, NO_CALL_FUNCTION_FLAGS), fun,
+          UndefinedConstant(), p0, p1);
+      Reduction r = Reduce(call);
+
+      if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
+        ASSERT_TRUE(r.Changed());
+        EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
+      } else {
+        ASSERT_FALSE(r.Changed());
+        EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
+      }
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.fround
+
+
+TEST_F(JSBuiltinReducerTest, MathFround) {
+  Handle<JSFunction> f = MathFunction("fround");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.floor
+
+
+TEST_F(JSBuiltinReducerTest, MathFloorAvailable) {
+  Handle<JSFunction> f = MathFunction("floor");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Floor);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsFloat64Floor(p0));
+  }
+}
+
+
+TEST_F(JSBuiltinReducerTest, MathFloorUnavailable) {
+  Handle<JSFunction> f = MathFunction("floor");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags);
+
+    ASSERT_FALSE(r.Changed());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Math.ceil
+
+
+TEST_F(JSBuiltinReducerTest, MathCeilAvailable) {
+  Handle<JSFunction> f = MathFunction("ceil");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Ceil);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsFloat64Ceil(p0));
+  }
+}
+
+
+TEST_F(JSBuiltinReducerTest, MathCeilUnavailable) {
+  Handle<JSFunction> f = MathFunction("ceil");
+
+  TRACED_FOREACH(Type*, t0, kNumberTypes) {
+    Node* p0 = Parameter(t0, 0);
+    Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
+    Node* call =
+        graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
+                         fun, UndefinedConstant(), p0);
+    Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags);
+
+    ASSERT_FALSE(r.Changed());
+  }
+}
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/js-operator-unittest.cc b/test/unittests/compiler/js-operator-unittest.cc
new file mode 100644
index 0000000..7aa0c64
--- /dev/null
+++ b/test/unittests/compiler/js-operator-unittest.cc
@@ -0,0 +1,217 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/js-operator.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// -----------------------------------------------------------------------------
+// Shared operators.
+
+
+namespace {
+
+struct SharedOperator {
+  const Operator* (JSOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  Operator::Properties properties;
+  int value_input_count;
+  int frame_state_input_count;
+  int effect_input_count;
+  int control_input_count;
+  int value_output_count;
+  int effect_output_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const SharedOperator& sop) {
+  return os << IrOpcode::Mnemonic(sop.opcode);
+}
+
+
+const SharedOperator kSharedOperators[] = {
+#define SHARED(Name, properties, value_input_count, frame_state_input_count, \
+               effect_input_count, control_input_count, value_output_count,  \
+               effect_output_count)                                          \
+  {                                                                          \
+    &JSOperatorBuilder::Name, IrOpcode::kJS##Name, properties,               \
+        value_input_count, frame_state_input_count, effect_input_count,      \
+        control_input_count, value_output_count, effect_output_count         \
+  }
+    SHARED(Equal, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(StrictEqual, Operator::kPure, 2, 0, 0, 0, 1, 0),
+    SHARED(StrictNotEqual, Operator::kPure, 2, 0, 0, 0, 1, 0),
+    SHARED(LessThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseOr, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseXor, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(BitwiseAnd, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftLeft, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftRight, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Add, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Subtract, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Multiply, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Divide, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Modulus, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(UnaryNot, Operator::kPure, 1, 0, 0, 0, 1, 0),
+    SHARED(ToBoolean, Operator::kPure, 1, 0, 0, 0, 1, 0),
+    SHARED(ToNumber, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToString, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToName, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(ToObject, Operator::kNoProperties, 1, 1, 1, 1, 1, 1),
+    SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(Create, Operator::kEliminatable, 0, 0, 1, 1, 1, 1),
+    SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0),
+    SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1),
+    SHARED(Debugger, Operator::kNoProperties, 0, 0, 1, 1, 0, 1),
+    SHARED(CreateFunctionContext, Operator::kNoProperties, 1, 0, 1, 1, 1, 1),
+    SHARED(CreateWithContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateBlockContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1),
+    SHARED(CreateScriptContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1)
+#undef SHARED
+};
+
+}  // namespace
+
+
+class JSSharedOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<SharedOperator> {};
+
+
+TEST_P(JSSharedOperatorTest, InstancesAreGloballyShared) {
+  const SharedOperator& sop = GetParam();
+  JSOperatorBuilder javascript1(zone());
+  JSOperatorBuilder javascript2(zone());
+  EXPECT_EQ((javascript1.*sop.constructor)(), (javascript2.*sop.constructor)());
+}
+
+
+TEST_P(JSSharedOperatorTest, NumberOfInputsAndOutputs) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+
+  const int context_input_count = 1;
+  // TODO(jarin): Get rid of this hack.
+  const int frame_state_input_count =
+      FLAG_turbo_deoptimization ? sop.frame_state_input_count : 0;
+  EXPECT_EQ(sop.value_input_count, op->ValueInputCount());
+  EXPECT_EQ(context_input_count, OperatorProperties::GetContextInputCount(op));
+  EXPECT_EQ(frame_state_input_count,
+            OperatorProperties::GetFrameStateInputCount(op));
+  EXPECT_EQ(sop.effect_input_count, op->EffectInputCount());
+  EXPECT_EQ(sop.control_input_count, op->ControlInputCount());
+  EXPECT_EQ(sop.value_input_count + context_input_count +
+                frame_state_input_count + sop.effect_input_count +
+                sop.control_input_count,
+            OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(sop.value_output_count, op->ValueOutputCount());
+  EXPECT_EQ(sop.effect_output_count, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(JSSharedOperatorTest, OpcodeIsCorrect) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+  EXPECT_EQ(sop.opcode, op->opcode());
+}
+
+
+TEST_P(JSSharedOperatorTest, Properties) {
+  JSOperatorBuilder javascript(zone());
+  const SharedOperator& sop = GetParam();
+  const Operator* op = (javascript.*sop.constructor)();
+  EXPECT_EQ(sop.properties, op->properties());
+}
+
+
+INSTANTIATE_TEST_CASE_P(JSOperatorTest, JSSharedOperatorTest,
+                        ::testing::ValuesIn(kSharedOperators));
+
+
+// -----------------------------------------------------------------------------
+// JSStoreProperty.
+
+
+class JSStorePropertyOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<StrictMode> {};
+
+
+TEST_P(JSStorePropertyOperatorTest, InstancesAreGloballyShared) {
+  const StrictMode mode = GetParam();
+  JSOperatorBuilder javascript1(zone());
+  JSOperatorBuilder javascript2(zone());
+  EXPECT_EQ(javascript1.StoreProperty(mode), javascript2.StoreProperty(mode));
+}
+
+
+TEST_P(JSStorePropertyOperatorTest, NumberOfInputsAndOutputs) {
+  JSOperatorBuilder javascript(zone());
+  const StrictMode mode = GetParam();
+  const Operator* op = javascript.StoreProperty(mode);
+
+  // TODO(jarin): Get rid of this hack.
+  const int frame_state_input_count = FLAG_turbo_deoptimization ? 1 : 0;
+  EXPECT_EQ(3, op->ValueInputCount());
+  EXPECT_EQ(1, OperatorProperties::GetContextInputCount(op));
+  EXPECT_EQ(frame_state_input_count,
+            OperatorProperties::GetFrameStateInputCount(op));
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(6 + frame_state_input_count,
+            OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(JSStorePropertyOperatorTest, OpcodeIsCorrect) {
+  JSOperatorBuilder javascript(zone());
+  const StrictMode mode = GetParam();
+  const Operator* op = javascript.StoreProperty(mode);
+  EXPECT_EQ(IrOpcode::kJSStoreProperty, op->opcode());
+}
+
+
+TEST_P(JSStorePropertyOperatorTest, OpParameter) {
+  JSOperatorBuilder javascript(zone());
+  const StrictMode mode = GetParam();
+  const Operator* op = javascript.StoreProperty(mode);
+  EXPECT_EQ(mode, OpParameter<StrictMode>(op));
+}
+
+
+TEST_P(JSStorePropertyOperatorTest, Properties) {
+  JSOperatorBuilder javascript(zone());
+  const StrictMode mode = GetParam();
+  const Operator* op = javascript.StoreProperty(mode);
+  EXPECT_EQ(Operator::kNoProperties, op->properties());
+}
+
+
+INSTANTIATE_TEST_CASE_P(JSOperatorTest, JSStorePropertyOperatorTest,
+                        ::testing::Values(SLOPPY, STRICT));
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/js-typed-lowering-unittest.cc b/test/unittests/compiler/js-typed-lowering-unittest.cc
new file mode 100644
index 0000000..97ff106
--- /dev/null
+++ b/test/unittests/compiler/js-typed-lowering-unittest.cc
@@ -0,0 +1,808 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node-properties-inl.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::BitEq;
+using testing::IsNaN;
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+const ExternalArrayType kExternalArrayTypes[] = {
+    kExternalUint8Array,   kExternalInt8Array,   kExternalUint16Array,
+    kExternalInt16Array,   kExternalUint32Array, kExternalInt32Array,
+    kExternalFloat32Array, kExternalFloat64Array};
+
+
+const double kFloat64Values[] = {
+    -V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
+    -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
+    -1.67813e+72, -2.3382e+55, -3.179e+30, -1.441e+09, -1.0647e+09,
+    -7.99361e+08, -5.77375e+08, -2.20984e+08, -32757, -13171, -9970, -3984,
+    -107, -105, -92, -77, -61, -0.000208163, -1.86685e-06, -1.17296e-10,
+    -9.26358e-11, -5.08004e-60, -1.74753e-65, -1.06561e-71, -5.67879e-79,
+    -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
+    -4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, -2.03855e-282,
+    -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0, 0.0, 2.22507e-308,
+    1.30127e-270, 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228,
+    2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, 1.35292e-90,
+    2.85394e-83, 1.78323e-77, 5.4967e-57, 1.03207e-25, 4.57401e-25, 1.58738e-05,
+    2, 125, 2310, 9636, 14802, 17168, 28945, 29305, 4.81336e+07, 1.41207e+08,
+    4.65962e+08, 1.40499e+09, 2.12648e+09, 8.80006e+30, 1.4446e+45, 1.12164e+54,
+    2.48188e+89, 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166,
+    4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, 6.63277e+243,
+    1.56192e+261, 1.23202e+269, 5.72883e+289, 8.5798e+290, 1.40256e+294,
+    1.79769e+308, V8_INFINITY};
+
+
+const size_t kIndices[] = {0, 1, 42, 100, 1024};
+
+
+const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0,  -42.0,
+                                 -1.0,         0.0,     1.0,      42.0,
+                                 1000.0,       INT_MAX, UINT_MAX, V8_INFINITY};
+
+
+Type* const kJSTypes[] = {Type::Undefined(), Type::Null(),   Type::Boolean(),
+                          Type::Number(),    Type::String(), Type::Object()};
+
+
+const StrictMode kStrictModes[] = {SLOPPY, STRICT};
+
+}  // namespace
+
+
+class JSTypedLoweringTest : public TypedGraphTest {
+ public:
+  JSTypedLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
+  ~JSTypedLoweringTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    MachineOperatorBuilder machine(zone());
+    JSGraph jsgraph(graph(), common(), javascript(), &machine);
+    JSTypedLowering reducer(&jsgraph, zone());
+    return reducer.Reduce(node);
+  }
+
+  Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) {
+    Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer();
+    Runtime::SetupArrayBuffer(isolate(), buffer, true, bytes, byte_length);
+    return buffer;
+  }
+
+  Matcher<Node*> IsIntPtrConstant(intptr_t value) {
+    return sizeof(value) == 4 ? IsInt32Constant(static_cast<int32_t>(value))
+                              : IsInt64Constant(static_cast<int64_t>(value));
+  }
+
+  JSOperatorBuilder* javascript() { return &javascript_; }
+
+ private:
+  JSOperatorBuilder javascript_;
+};
+
+
+// -----------------------------------------------------------------------------
+// JSUnaryNot
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
+  Node* input = Parameter(Type::Boolean(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsBooleanNot(input));
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
+  Handle<Object> zero = factory()->NewNumber(0);
+  Node* input = Parameter(
+      Type::Union(
+          Type::MinusZero(),
+          Type::Union(
+              Type::NaN(),
+              Type::Union(
+                  Type::Null(),
+                  Type::Union(
+                      Type::Undefined(),
+                      Type::Union(
+                          Type::Undetectable(),
+                          Type::Union(
+                              Type::Constant(factory()->false_value(), zone()),
+                              Type::Range(zero, zero, zone()), zone()),
+                          zone()),
+                      zone()),
+                  zone()),
+              zone()),
+          zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) {
+  Node* input = Parameter(
+      Type::Union(
+          Type::Constant(factory()->true_value(), zone()),
+          Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
+          zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
+  Node* input = Parameter(
+      Type::Range(factory()->NewNumber(1), factory()->NewNumber(42), zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) {
+  Node* input = Parameter(Type::Any(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsBooleanNot(IsAnyToBoolean(input)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Constant propagation
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
+  {
+    Reduction r = Reduce(
+        Parameter(Type::Constant(factory()->minus_zero_value(), zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
+  }
+  {
+    Reduction r = Reduce(Parameter(Type::MinusZero()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
+  }
+  {
+    Reduction r = Reduce(Parameter(
+        Type::Union(Type::MinusZero(),
+                    Type::Constant(factory()->NewNumber(0), zone()), zone())));
+    EXPECT_FALSE(r.Changed());
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithNull) {
+  Handle<HeapObject> null = factory()->null_value();
+  {
+    Reduction r = Reduce(Parameter(Type::Constant(null, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
+  }
+  {
+    Reduction r = Reduce(Parameter(Type::Null()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithNaN) {
+  const double kNaNs[] = {base::OS::nan_value(),
+                          std::numeric_limits<double>::quiet_NaN(),
+                          std::numeric_limits<double>::signaling_NaN()};
+  TRACED_FOREACH(double, nan, kNaNs) {
+    Handle<Object> constant = factory()->NewNumber(nan);
+    Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+  }
+  {
+    Reduction r =
+        Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+  }
+  {
+    Reduction r = Reduce(Parameter(Type::NaN()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) {
+  TRACED_FOREACH(double, value, kFloat64Values) {
+    Handle<Object> constant = factory()->NewNumber(value);
+    Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(value));
+  }
+  TRACED_FOREACH(double, value, kIntegerValues) {
+    Handle<Object> constant = factory()->NewNumber(value);
+    Reduction r = Reduce(Parameter(Type::Range(constant, constant, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsNumberConstant(value));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
+  Handle<HeapObject> undefined = factory()->undefined_value();
+  {
+    Reduction r = Reduce(Parameter(Type::Undefined()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
+  }
+  {
+    Reduction r = Reduce(Parameter(Type::Constant(undefined, zone())));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSToBoolean
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
+  Node* input = Parameter(Type::Boolean(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_EQ(input, r.replacement());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
+  Handle<Object> zero = factory()->NewNumber(0);
+  Node* input = Parameter(
+      Type::Union(
+          Type::MinusZero(),
+          Type::Union(
+              Type::NaN(),
+              Type::Union(
+                  Type::Null(),
+                  Type::Union(
+                      Type::Undefined(),
+                      Type::Union(
+                          Type::Undetectable(),
+                          Type::Union(
+                              Type::Constant(factory()->false_value(), zone()),
+                              Type::Range(zero, zero, zone()), zone()),
+                          zone()),
+                      zone()),
+                  zone()),
+              zone()),
+          zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
+  Node* input = Parameter(
+      Type::Union(
+          Type::Constant(factory()->true_value(), zone()),
+          Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
+          zone()),
+      0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
+  Node* input =
+      Parameter(Type::Range(factory()->NewNumber(1),
+                            factory()->NewNumber(V8_INFINITY), zone()),
+                0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
+  Node* input = Parameter(Type::Any(), 0);
+  Node* context = Parameter(Type::Any(), 1);
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsAnyToBoolean(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSToNumber
+
+
+TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
+  Node* const input = Parameter(Type::PlainPrimitive(), 0);
+  Node* const context = Parameter(Type::Any(), 1);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction r = Reduce(graph()->NewNode(javascript()->ToNumber(), input,
+                                        context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
+                                          graph()->start(), control));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStrictEqual
+
+
+TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
+  Node* const the_hole = HeapConstant(factory()->the_hole_value());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(Type*, type, kJSTypes) {
+    Node* const lhs = Parameter(type);
+    Reduction r = Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs,
+                                          the_hole, context, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsFalseConstant());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftLeft
+
+
+TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
+  Node* const lhs = Parameter(Type::Signed32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(double, rhs, 0, 31) {
+    Reduction r =
+        Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs,
+                                NumberConstant(rhs), context, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs))));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
+  Node* const lhs = Parameter(Type::Signed32());
+  Node* const rhs = Parameter(Type::Unsigned32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs, rhs,
+                                        context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsWord32Shl(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftRight
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
+  Node* const lhs = Parameter(Type::Signed32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(double, rhs, 0, 31) {
+    Reduction r =
+        Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs,
+                                NumberConstant(rhs), context, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs))));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
+  Node* const lhs = Parameter(Type::Signed32());
+  Node* const rhs = Parameter(Type::Unsigned32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs, rhs,
+                                        context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsWord32Sar(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftRightLogical
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndConstant) {
+  Node* const lhs = Parameter(Type::Unsigned32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(double, rhs, 0, 31) {
+    Reduction r =
+        Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
+                                NumberConstant(rhs), context, effect, control));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs))));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
+  Node* const lhs = Parameter(Type::Unsigned32());
+  Node* const rhs = Parameter(Type::Unsigned32());
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
+                                        rhs, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsWord32Shr(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSLoadContext
+
+
+TEST_F(JSTypedLoweringTest, JSLoadContext) {
+  Node* const context = Parameter(Type::Any());
+  Node* const effect = graph()->start();
+  static bool kBooleans[] = {false, true};
+  TRACED_FOREACH(size_t, index, kIndices) {
+    TRACED_FOREACH(bool, immutable, kBooleans) {
+      Reduction const r1 = Reduce(
+          graph()->NewNode(javascript()->LoadContext(0, index, immutable),
+                           context, context, effect));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(),
+                  IsLoadField(AccessBuilder::ForContextSlot(index), context,
+                              effect, graph()->start()));
+
+      Reduction const r2 = Reduce(
+          graph()->NewNode(javascript()->LoadContext(1, index, immutable),
+                           context, context, effect));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(),
+                  IsLoadField(AccessBuilder::ForContextSlot(index),
+                              IsLoadField(AccessBuilder::ForContextSlot(
+                                              Context::PREVIOUS_INDEX),
+                                          context, effect, graph()->start()),
+                              effect, graph()->start()));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStoreContext
+
+
+TEST_F(JSTypedLoweringTest, JSStoreContext) {
+  Node* const context = Parameter(Type::Any());
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(size_t, index, kIndices) {
+    TRACED_FOREACH(Type*, type, kJSTypes) {
+      Node* const value = Parameter(type);
+
+      Reduction const r1 =
+          Reduce(graph()->NewNode(javascript()->StoreContext(0, index), context,
+                                  value, context, effect, control));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(),
+                  IsStoreField(AccessBuilder::ForContextSlot(index), context,
+                               value, effect, control));
+
+      Reduction const r2 =
+          Reduce(graph()->NewNode(javascript()->StoreContext(1, index), context,
+                                  value, context, effect, control));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(),
+                  IsStoreField(AccessBuilder::ForContextSlot(index),
+                               IsLoadField(AccessBuilder::ForContextSlot(
+                                               Context::PREVIOUS_INDEX),
+                                           context, effect, graph()->start()),
+                               value, effect, control));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSLoadProperty
+
+
+TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
+                          FeedbackVectorICSlot::Invalid());
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    Handle<JSTypedArray> array =
+        factory()->NewJSTypedArray(type, buffer, 0, kLength);
+    int const element_size = static_cast<int>(array->element_size());
+
+    Node* key = Parameter(
+        Type::Range(factory()->NewNumber(kMinInt / element_size),
+                    factory()->NewNumber(kMaxInt / element_size), zone()));
+    Node* base = HeapConstant(array);
+    Node* context = UndefinedConstant();
+    Node* effect = graph()->start();
+    Node* control = graph()->start();
+    Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base,
+                                  key, context);
+    if (FLAG_turbo_deoptimization) {
+      node->AppendInput(zone(), UndefinedConstant());
+    }
+    node->AppendInput(zone(), effect);
+    node->AppendInput(zone(), control);
+    Reduction r = Reduce(node);
+
+    Matcher<Node*> offset_matcher =
+        element_size == 1
+            ? key
+            : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsLoadBuffer(BufferAccess(type),
+                     IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+                     offset_matcher,
+                     IsNumberConstant(array->byte_length()->Number()), effect,
+                     control));
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
+                          FeedbackVectorICSlot::Invalid());
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    Handle<JSTypedArray> array =
+        factory()->NewJSTypedArray(type, buffer, 0, kLength);
+    ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
+
+    int min = random_number_generator()->NextInt(static_cast<int>(kLength));
+    int max = random_number_generator()->NextInt(static_cast<int>(kLength));
+    if (min > max) std::swap(min, max);
+    Node* key = Parameter(Type::Range(factory()->NewNumber(min),
+                                      factory()->NewNumber(max), zone()));
+    Node* base = HeapConstant(array);
+    Node* context = UndefinedConstant();
+    Node* effect = graph()->start();
+    Node* control = graph()->start();
+    Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base,
+                                  key, context);
+    if (FLAG_turbo_deoptimization) {
+      node->AppendInput(zone(), UndefinedConstant());
+    }
+    node->AppendInput(zone(), effect);
+    node->AppendInput(zone(), control);
+    Reduction r = Reduce(node);
+
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsLoadElement(access,
+                      IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+                      key, effect, control));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStoreProperty
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+      Handle<JSTypedArray> array =
+          factory()->NewJSTypedArray(type, buffer, 0, kLength);
+      int const element_size = static_cast<int>(array->element_size());
+
+      Node* key = Parameter(
+          Type::Range(factory()->NewNumber(kMinInt / element_size),
+                      factory()->NewNumber(kMaxInt / element_size), zone()));
+      Node* base = HeapConstant(array);
+      Node* value =
+          Parameter(AccessBuilder::ForTypedArrayElement(type, true).type);
+      Node* context = UndefinedConstant();
+      Node* effect = graph()->start();
+      Node* control = graph()->start();
+      Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+                                    base, key, value, context);
+      if (FLAG_turbo_deoptimization) {
+        node->AppendInput(zone(), UndefinedConstant());
+      }
+      node->AppendInput(zone(), effect);
+      node->AppendInput(zone(), control);
+      Reduction r = Reduce(node);
+
+      Matcher<Node*> offset_matcher =
+          element_size == 1
+              ? key
+              : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsStoreBuffer(BufferAccess(type),
+                        IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+                        offset_matcher,
+                        IsNumberConstant(array->byte_length()->Number()), value,
+                        effect, control));
+    }
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+      Handle<JSTypedArray> array =
+          factory()->NewJSTypedArray(type, buffer, 0, kLength);
+      int const element_size = static_cast<int>(array->element_size());
+
+      Node* key = Parameter(
+          Type::Range(factory()->NewNumber(kMinInt / element_size),
+                      factory()->NewNumber(kMaxInt / element_size), zone()));
+      Node* base = HeapConstant(array);
+      Node* value = Parameter(Type::Any());
+      Node* context = UndefinedConstant();
+      Node* effect = graph()->start();
+      Node* control = graph()->start();
+      Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+                                    base, key, value, context);
+      if (FLAG_turbo_deoptimization) {
+        node->AppendInput(zone(), UndefinedConstant());
+      }
+      node->AppendInput(zone(), effect);
+      node->AppendInput(zone(), control);
+      Reduction r = Reduce(node);
+
+      Matcher<Node*> offset_matcher =
+          element_size == 1
+              ? key
+              : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+      Matcher<Node*> value_matcher =
+          IsToNumber(value, context, effect, control);
+      Matcher<Node*> effect_matcher = value_matcher;
+      if (AccessBuilder::ForTypedArrayElement(type, true)
+              .type->Is(Type::Signed32())) {
+        value_matcher = IsNumberToInt32(value_matcher);
+      } else if (AccessBuilder::ForTypedArrayElement(type, true)
+                     .type->Is(Type::Unsigned32())) {
+        value_matcher = IsNumberToUint32(value_matcher);
+      }
+
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsStoreBuffer(BufferAccess(type),
+                        IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+                        offset_matcher,
+                        IsNumberConstant(array->byte_length()->Number()),
+                        value_matcher, effect_matcher, control));
+    }
+  }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
+  const size_t kLength = 17;
+  double backing_store[kLength];
+  Handle<JSArrayBuffer> buffer =
+      NewArrayBuffer(backing_store, sizeof(backing_store));
+  TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+    TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+      Handle<JSTypedArray> array =
+          factory()->NewJSTypedArray(type, buffer, 0, kLength);
+      ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
+
+      int min = random_number_generator()->NextInt(static_cast<int>(kLength));
+      int max = random_number_generator()->NextInt(static_cast<int>(kLength));
+      if (min > max) std::swap(min, max);
+      Node* key = Parameter(Type::Range(factory()->NewNumber(min),
+                                        factory()->NewNumber(max), zone()));
+      Node* base = HeapConstant(array);
+      Node* value = Parameter(access.type);
+      Node* context = UndefinedConstant();
+      Node* effect = graph()->start();
+      Node* control = graph()->start();
+      Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+                                    base, key, value, context);
+      if (FLAG_turbo_deoptimization) {
+        node->AppendInput(zone(), UndefinedConstant());
+      }
+      node->AppendInput(zone(), effect);
+      node->AppendInput(zone(), control);
+      Reduction r = Reduce(node);
+
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(
+          r.replacement(),
+          IsStoreElement(
+              access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+              key, value, effect, control));
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/load-elimination-unittest.cc b/test/unittests/compiler/load-elimination-unittest.cc
new file mode 100644
index 0000000..f0cd60e
--- /dev/null
+++ b/test/unittests/compiler/load-elimination-unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/load-elimination.h"
+#include "src/compiler/simplified-operator.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class LoadEliminationTest : public GraphTest {
+ public:
+  LoadEliminationTest() : GraphTest(3), simplified_(zone()) {}
+  ~LoadEliminationTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    LoadElimination reducer;
+    return reducer.Reduce(node);
+  }
+
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
+
+ private:
+  SimplifiedOperatorBuilder simplified_;
+};
+
+
+TEST_F(LoadEliminationTest, LoadFieldWithStoreField) {
+  Node* object1 = Parameter(0);
+  Node* object2 = Parameter(1);
+  Node* value = Parameter(2);
+  Node* effect = graph()->start();
+  Node* control = graph()->start();
+
+  FieldAccess access1 = AccessBuilder::ForContextSlot(42);
+  Node* store1 = graph()->NewNode(simplified()->StoreField(access1), object1,
+                                  value, effect, control);
+  Reduction r1 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
+                                         object1, store1, control));
+  ASSERT_TRUE(r1.Changed());
+  EXPECT_EQ(value, r1.replacement());
+
+  FieldAccess access2 = AccessBuilder::ForMap();
+  Node* store2 = graph()->NewNode(simplified()->StoreField(access2), object1,
+                                  object2, store1, control);
+  Reduction r2 = Reduce(graph()->NewNode(simplified()->LoadField(access2),
+                                         object1, store2, control));
+  ASSERT_TRUE(r2.Changed());
+  EXPECT_EQ(object2, r2.replacement());
+
+  Node* store3 = graph()->NewNode(
+      simplified()->StoreBuffer(BufferAccess(kExternalInt8Array)), object2,
+      value, Int32Constant(10), object1, store2, control);
+
+  Reduction r3 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
+                                         object2, store3, control));
+  ASSERT_FALSE(r3.Changed());
+
+  Reduction r4 = Reduce(graph()->NewNode(simplified()->LoadField(access1),
+                                         object1, store3, control));
+  ASSERT_TRUE(r4.Changed());
+  EXPECT_EQ(value, r4.replacement());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/machine-operator-reducer-unittest.cc b/test/unittests/compiler/machine-operator-reducer-unittest.cc
new file mode 100644
index 0000000..6fdba35
--- /dev/null
+++ b/test/unittests/compiler/machine-operator-reducer-unittest.cc
@@ -0,0 +1,1383 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/bits.h"
+#include "src/base/division-by-constant.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/machine-operator-reducer.h"
+#include "src/compiler/typer.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::AllOf;
+using testing::BitEq;
+using testing::Capture;
+using testing::CaptureEq;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class MachineOperatorReducerTest : public TypedGraphTest {
+ public:
+  explicit MachineOperatorReducerTest(int num_parameters = 2)
+      : TypedGraphTest(num_parameters), machine_(zone()) {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    JSOperatorBuilder javascript(zone());
+    JSGraph jsgraph(graph(), common(), &javascript, &machine_);
+    MachineOperatorReducer reducer(&jsgraph);
+    return reducer.Reduce(node);
+  }
+
+  Matcher<Node*> IsTruncatingDiv(const Matcher<Node*>& dividend_matcher,
+                                 const int32_t divisor) {
+    base::MagicNumbersForDivision<uint32_t> const mag =
+        base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
+    int32_t const multiplier = bit_cast<int32_t>(mag.multiplier);
+    int32_t const shift = bit_cast<int32_t>(mag.shift);
+    Matcher<Node*> quotient_matcher =
+        IsInt32MulHigh(dividend_matcher, IsInt32Constant(multiplier));
+    if (divisor > 0 && multiplier < 0) {
+      quotient_matcher = IsInt32Add(quotient_matcher, dividend_matcher);
+    } else if (divisor < 0 && multiplier > 0) {
+      quotient_matcher = IsInt32Sub(quotient_matcher, dividend_matcher);
+    }
+    if (shift) {
+      quotient_matcher = IsWord32Sar(quotient_matcher, IsInt32Constant(shift));
+    }
+    return IsInt32Add(quotient_matcher,
+                      IsWord32Shr(dividend_matcher, IsInt32Constant(31)));
+  }
+
+  MachineOperatorBuilder* machine() { return &machine_; }
+
+ private:
+  MachineOperatorBuilder machine_;
+};
+
+
+template <typename T>
+class MachineOperatorReducerTestWithParam
+    : public MachineOperatorReducerTest,
+      public ::testing::WithParamInterface<T> {
+ public:
+  explicit MachineOperatorReducerTestWithParam(int num_parameters = 2)
+      : MachineOperatorReducerTest(num_parameters) {}
+  ~MachineOperatorReducerTestWithParam() OVERRIDE {}
+};
+
+
+namespace {
+
+const float kFloat32Values[] = {
+    -std::numeric_limits<float>::infinity(), -2.70497e+38f, -1.4698e+37f,
+    -1.22813e+35f,                           -1.20555e+35f, -1.34584e+34f,
+    -1.0079e+32f,                            -6.49364e+26f, -3.06077e+25f,
+    -1.46821e+25f,                           -1.17658e+23f, -1.9617e+22f,
+    -2.7357e+20f,                            -1.48708e+13f, -1.89633e+12f,
+    -4.66622e+11f,                           -2.22581e+11f, -1.45381e+10f,
+    -1.3956e+09f,                            -1.32951e+09f, -1.30721e+09f,
+    -1.19756e+09f,                           -9.26822e+08f, -6.35647e+08f,
+    -4.00037e+08f,                           -1.81227e+08f, -5.09256e+07f,
+    -964300.0f,                              -192446.0f,    -28455.0f,
+    -27194.0f,                               -26401.0f,     -20575.0f,
+    -17069.0f,                               -9167.0f,      -960.178f,
+    -113.0f,                                 -62.0f,        -15.0f,
+    -7.0f,                                   -0.0256635f,   -4.60374e-07f,
+    -3.63759e-10f,                           -4.30175e-14f, -5.27385e-15f,
+    -1.48084e-15f,                           -1.05755e-19f, -3.2995e-21f,
+    -1.67354e-23f,                           -1.11885e-23f, -1.78506e-30f,
+    -5.07594e-31f,                           -3.65799e-31f, -1.43718e-34f,
+    -1.27126e-38f,                           -0.0f,         0.0f,
+    1.17549e-38f,                            1.56657e-37f,  4.08512e-29f,
+    3.31357e-28f,                            6.25073e-22f,  4.1723e-13f,
+    1.44343e-09f,                            5.27004e-08f,  9.48298e-08f,
+    5.57888e-07f,                            4.89988e-05f,  0.244326f,
+    12.4895f,                                19.0f,         47.0f,
+    106.0f,                                  538.324f,      564.536f,
+    819.124f,                                7048.0f,       12611.0f,
+    19878.0f,                                20309.0f,      797056.0f,
+    1.77219e+09f,                            1.51116e+11f,  4.18193e+13f,
+    3.59167e+16f,                            3.38211e+19f,  2.67488e+20f,
+    1.78831e+21f,                            9.20914e+21f,  8.35654e+23f,
+    1.4495e+24f,                             5.94015e+25f,  4.43608e+30f,
+    2.44502e+33f,                            2.61152e+33f,  1.38178e+37f,
+    1.71306e+37f,                            3.31899e+38f,  3.40282e+38f,
+    std::numeric_limits<float>::infinity()};
+
+
+const double kFloat64Values[] = {
+    -V8_INFINITY,  -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
+    -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
+    -1.67813e+72,  -2.3382e+55,   -3.179e+30,    -1.441e+09,    -1.0647e+09,
+    -7.99361e+08,  -5.77375e+08,  -2.20984e+08,  -32757,        -13171,
+    -9970,         -3984,         -107,          -105,          -92,
+    -77,           -61,           -0.000208163,  -1.86685e-06,  -1.17296e-10,
+    -9.26358e-11,  -5.08004e-60,  -1.74753e-65,  -1.06561e-71,  -5.67879e-79,
+    -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
+    -4.40497e-267, -2.19666e-273, -4.9998e-276,  -5.59821e-278, -2.03855e-282,
+    -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0,          0.0,
+    2.22507e-308,  1.30127e-270,  7.62898e-260,  4.00313e-249,  3.16829e-233,
+    1.85244e-228,  2.03544e-129,  1.35126e-110,  1.01182e-106,  5.26333e-94,
+    1.35292e-90,   2.85394e-83,   1.78323e-77,   5.4967e-57,    1.03207e-25,
+    4.57401e-25,   1.58738e-05,   2,             125,           2310,
+    9636,          14802,         17168,         28945,         29305,
+    4.81336e+07,   1.41207e+08,   4.65962e+08,   1.40499e+09,   2.12648e+09,
+    8.80006e+30,   1.4446e+45,    1.12164e+54,   2.48188e+89,   6.71121e+102,
+    3.074e+112,    4.9699e+152,   5.58383e+166,  4.30654e+172,  7.08824e+185,
+    9.6586e+214,   2.028e+223,    6.63277e+243,  1.56192e+261,  1.23202e+269,
+    5.72883e+289,  8.5798e+290,   1.40256e+294,  1.79769e+308,  V8_INFINITY};
+
+
+const int32_t kInt32Values[] = {
+    std::numeric_limits<int32_t>::min(), -1914954528, -1698749618,
+    -1578693386,                         -1577976073, -1573998034,
+    -1529085059,                         -1499540537, -1299205097,
+    -1090814845,                         -938186388,  -806828902,
+    -750927650,                          -520676892,  -513661538,
+    -453036354,                          -433622833,  -282638793,
+    -28375,                              -27788,      -22770,
+    -18806,                              -14173,      -11956,
+    -11200,                              -10212,      -8160,
+    -3751,                               -2758,       -1522,
+    -121,                                -120,        -118,
+    -117,                                -106,        -84,
+    -80,                                 -74,         -59,
+    -52,                                 -48,         -39,
+    -35,                                 -17,         -11,
+    -10,                                 -9,          -7,
+    -5,                                  0,           9,
+    12,                                  17,          23,
+    29,                                  31,          33,
+    35,                                  40,          47,
+    55,                                  56,          62,
+    64,                                  67,          68,
+    69,                                  74,          79,
+    84,                                  89,          90,
+    97,                                  104,         118,
+    124,                                 126,         127,
+    7278,                                17787,       24136,
+    24202,                               25570,       26680,
+    30242,                               32399,       420886487,
+    642166225,                           821912648,   822577803,
+    851385718,                           1212241078,  1411419304,
+    1589626102,                          1596437184,  1876245816,
+    1954730266,                          2008792749,  2045320228,
+    std::numeric_limits<int32_t>::max()};
+
+
+const int64_t kInt64Values[] = {
+    std::numeric_limits<int64_t>::min(), V8_INT64_C(-8974392461363618006),
+    V8_INT64_C(-8874367046689588135),    V8_INT64_C(-8269197512118230839),
+    V8_INT64_C(-8146091527100606733),    V8_INT64_C(-7550917981466150848),
+    V8_INT64_C(-7216590251577894337),    V8_INT64_C(-6464086891160048440),
+    V8_INT64_C(-6365616494908257190),    V8_INT64_C(-6305630541365849726),
+    V8_INT64_C(-5982222642272245453),    V8_INT64_C(-5510103099058504169),
+    V8_INT64_C(-5496838675802432701),    V8_INT64_C(-4047626578868642657),
+    V8_INT64_C(-4033755046900164544),    V8_INT64_C(-3554299241457877041),
+    V8_INT64_C(-2482258764588614470),    V8_INT64_C(-1688515425526875335),
+    V8_INT64_C(-924784137176548532),     V8_INT64_C(-725316567157391307),
+    V8_INT64_C(-439022654781092241),     V8_INT64_C(-105545757668917080),
+    V8_INT64_C(-2088319373),             V8_INT64_C(-2073699916),
+    V8_INT64_C(-1844949911),             V8_INT64_C(-1831090548),
+    V8_INT64_C(-1756711933),             V8_INT64_C(-1559409497),
+    V8_INT64_C(-1281179700),             V8_INT64_C(-1211513985),
+    V8_INT64_C(-1182371520),             V8_INT64_C(-785934753),
+    V8_INT64_C(-767480697),              V8_INT64_C(-705745662),
+    V8_INT64_C(-514362436),              V8_INT64_C(-459916580),
+    V8_INT64_C(-312328082),              V8_INT64_C(-302949707),
+    V8_INT64_C(-285499304),              V8_INT64_C(-125701262),
+    V8_INT64_C(-95139843),               V8_INT64_C(-32768),
+    V8_INT64_C(-27542),                  V8_INT64_C(-23600),
+    V8_INT64_C(-18582),                  V8_INT64_C(-17770),
+    V8_INT64_C(-9086),                   V8_INT64_C(-9010),
+    V8_INT64_C(-8244),                   V8_INT64_C(-2890),
+    V8_INT64_C(-103),                    V8_INT64_C(-34),
+    V8_INT64_C(-27),                     V8_INT64_C(-25),
+    V8_INT64_C(-9),                      V8_INT64_C(-7),
+    V8_INT64_C(0),                       V8_INT64_C(2),
+    V8_INT64_C(38),                      V8_INT64_C(58),
+    V8_INT64_C(65),                      V8_INT64_C(93),
+    V8_INT64_C(111),                     V8_INT64_C(1003),
+    V8_INT64_C(1267),                    V8_INT64_C(12797),
+    V8_INT64_C(23122),                   V8_INT64_C(28200),
+    V8_INT64_C(30888),                   V8_INT64_C(42648848),
+    V8_INT64_C(116836693),               V8_INT64_C(263003643),
+    V8_INT64_C(571039860),               V8_INT64_C(1079398689),
+    V8_INT64_C(1145196402),              V8_INT64_C(1184846321),
+    V8_INT64_C(1758281648),              V8_INT64_C(1859991374),
+    V8_INT64_C(1960251588),              V8_INT64_C(2042443199),
+    V8_INT64_C(296220586027987448),      V8_INT64_C(1015494173071134726),
+    V8_INT64_C(1151237951914455318),     V8_INT64_C(1331941174616854174),
+    V8_INT64_C(2022020418667972654),     V8_INT64_C(2450251424374977035),
+    V8_INT64_C(3668393562685561486),     V8_INT64_C(4858229301215502171),
+    V8_INT64_C(4919426235170669383),     V8_INT64_C(5034286595330341762),
+    V8_INT64_C(5055797915536941182),     V8_INT64_C(6072389716149252074),
+    V8_INT64_C(6185309910199801210),     V8_INT64_C(6297328311011094138),
+    V8_INT64_C(6932372858072165827),     V8_INT64_C(8483640924987737210),
+    V8_INT64_C(8663764179455849203),     V8_INT64_C(8877197042645298254),
+    V8_INT64_C(8901543506779157333),     std::numeric_limits<int64_t>::max()};
+
+
+const uint32_t kUint32Values[] = {
+    0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
+    0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
+    0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
+    0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
+    0x761c4761, 0x80000000, 0x88888888, 0xa0000000, 0xdddddddd, 0xe0000000,
+    0xeeeeeeee, 0xfffffffd, 0xf0000000, 0x007fffff, 0x003fffff, 0x001fffff,
+    0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff,
+    0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Unary operators
+
+
+namespace {
+
+struct UnaryOperator {
+  const Operator* (MachineOperatorBuilder::*constructor)();
+  const char* constructor_name;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
+  return os << unop.constructor_name;
+}
+
+
+static const UnaryOperator kUnaryOperators[] = {
+    {&MachineOperatorBuilder::ChangeInt32ToFloat64, "ChangeInt32ToFloat64"},
+    {&MachineOperatorBuilder::ChangeUint32ToFloat64, "ChangeUint32ToFloat64"},
+    {&MachineOperatorBuilder::ChangeFloat64ToInt32, "ChangeFloat64ToInt32"},
+    {&MachineOperatorBuilder::ChangeFloat64ToUint32, "ChangeFloat64ToUint32"},
+    {&MachineOperatorBuilder::ChangeInt32ToInt64, "ChangeInt32ToInt64"},
+    {&MachineOperatorBuilder::ChangeUint32ToUint64, "ChangeUint32ToUint64"},
+    {&MachineOperatorBuilder::TruncateFloat64ToInt32, "TruncateFloat64ToInt32"},
+    {&MachineOperatorBuilder::TruncateInt64ToInt32, "TruncateInt64ToInt32"}};
+
+}  // namespace
+
+
+typedef MachineOperatorReducerTestWithParam<UnaryOperator>
+    MachineUnaryOperatorReducerTest;
+
+
+TEST_P(MachineUnaryOperatorReducerTest, Parameter) {
+  const UnaryOperator unop = GetParam();
+  Reduction reduction =
+      Reduce(graph()->NewNode((machine()->*unop.constructor)(), Parameter(0)));
+  EXPECT_FALSE(reduction.Changed());
+}
+
+
+INSTANTIATE_TEST_CASE_P(MachineOperatorReducerTest,
+                        MachineUnaryOperatorReducerTest,
+                        ::testing::ValuesIn(kUnaryOperators));
+
+
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToFloat32
+
+
+TEST_F(MachineOperatorReducerTest, ChangeFloat64ToFloat32WithConstant) {
+  TRACED_FOREACH(float, x, kFloat32Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->ChangeFloat32ToFloat64(), Float32Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq<double>(x)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToInt32
+
+
+TEST_F(MachineOperatorReducerTest,
+       ChangeFloat64ToInt32WithChangeInt32ToFloat64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->ChangeFloat64ToInt32(),
+      graph()->NewNode(machine()->ChangeInt32ToFloat64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, ChangeFloat64ToInt32WithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->ChangeFloat64ToInt32(), Float64Constant(FastI2D(x))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt32Constant(x));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToUint32
+
+
+TEST_F(MachineOperatorReducerTest,
+       ChangeFloat64ToUint32WithChangeUint32ToFloat64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->ChangeFloat64ToUint32(),
+      graph()->NewNode(machine()->ChangeUint32ToFloat64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, ChangeFloat64ToUint32WithConstant) {
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->ChangeFloat64ToUint32(), Float64Constant(FastUI2D(x))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt32Constant(bit_cast<int32_t>(x)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeInt32ToFloat64
+
+
+TEST_F(MachineOperatorReducerTest, ChangeInt32ToFloat64WithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    Reduction reduction = Reduce(
+        graph()->NewNode(machine()->ChangeInt32ToFloat64(), Int32Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(FastI2D(x))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeInt32ToInt64
+
+
+TEST_F(MachineOperatorReducerTest, ChangeInt32ToInt64WithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    Reduction reduction = Reduce(
+        graph()->NewNode(machine()->ChangeInt32ToInt64(), Int32Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt64Constant(x));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeUint32ToFloat64
+
+
+TEST_F(MachineOperatorReducerTest, ChangeUint32ToFloat64WithConstant) {
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Reduction reduction =
+        Reduce(graph()->NewNode(machine()->ChangeUint32ToFloat64(),
+                                Int32Constant(bit_cast<int32_t>(x))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(FastUI2D(x))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeUint32ToUint64
+
+
+TEST_F(MachineOperatorReducerTest, ChangeUint32ToUint64WithConstant) {
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Reduction reduction =
+        Reduce(graph()->NewNode(machine()->ChangeUint32ToUint64(),
+                                Int32Constant(bit_cast<int32_t>(x))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(),
+                IsInt64Constant(bit_cast<int64_t>(static_cast<uint64_t>(x))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// TruncateFloat64ToFloat32
+
+
+TEST_F(MachineOperatorReducerTest,
+       TruncateFloat64ToFloat32WithChangeFloat32ToFloat64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->TruncateFloat64ToFloat32(),
+      graph()->NewNode(machine()->ChangeFloat32ToFloat64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateFloat64ToFloat32WithConstant) {
+  TRACED_FOREACH(double, x, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->TruncateFloat64ToFloat32(), Float64Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(),
+                IsFloat32Constant(BitEq(DoubleToFloat32(x))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// TruncateFloat64ToInt32
+
+
+TEST_F(MachineOperatorReducerTest,
+       TruncateFloat64ToInt32WithChangeInt32ToFloat64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->TruncateFloat64ToInt32(),
+      graph()->NewNode(machine()->ChangeInt32ToFloat64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithConstant) {
+  TRACED_FOREACH(double, x, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        machine()->TruncateFloat64ToInt32(), Float64Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(x)));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateFloat64ToInt32WithPhi) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+  Node* const merge = graph()->start();
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->TruncateFloat64ToInt32(),
+      graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(),
+              IsPhi(kMachInt32, IsTruncateFloat64ToInt32(p0),
+                    IsTruncateFloat64ToInt32(p1), merge));
+}
+
+
+// -----------------------------------------------------------------------------
+// TruncateInt64ToInt32
+
+
+TEST_F(MachineOperatorReducerTest, TruncateInt64ToInt32WithChangeInt32ToInt64) {
+  Node* value = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      machine()->TruncateInt64ToInt32(),
+      graph()->NewNode(machine()->ChangeInt32ToInt64(), value)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(value, reduction.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, TruncateInt64ToInt32WithConstant) {
+  TRACED_FOREACH(int64_t, x, kInt64Values) {
+    Reduction reduction = Reduce(
+        graph()->NewNode(machine()->TruncateInt64ToInt32(), Int64Constant(x)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(),
+                IsInt32Constant(bit_cast<int32_t>(
+                    static_cast<uint32_t>(bit_cast<uint64_t>(x)))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32And
+
+
+TEST_F(MachineOperatorReducerTest, Word32AndWithWord32AndWithConstant) {
+  Node* const p0 = Parameter(0);
+
+  TRACED_FOREACH(int32_t, k, kInt32Values) {
+    TRACED_FOREACH(int32_t, l, kInt32Values) {
+      if (k == 0 || k == -1 || l == 0 || l == -1) continue;
+
+      // (x & K) & L => x & (K & L)
+      Reduction const r1 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Word32And(), p0, Int32Constant(k)),
+          Int32Constant(l)));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(),
+                  (k & l) ? IsWord32And(p0, IsInt32Constant(k & l))
+                          : IsInt32Constant(0));
+
+      // (K & x) & L => x & (K & L)
+      Reduction const r2 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Word32And(), Int32Constant(k), p0),
+          Int32Constant(l)));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(),
+                  (k & l) ? IsWord32And(p0, IsInt32Constant(k & l))
+                          : IsInt32Constant(0));
+    }
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32AndWithInt32AddAndConstant) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+
+  TRACED_FORRANGE(int32_t, l, 1, 31) {
+    TRACED_FOREACH(int32_t, k, kInt32Values) {
+      if ((k << l) == 0) continue;
+      // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Int32Add(), p0, Int32Constant(k << l)),
+          Int32Constant(-1 << l)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
+                             IsInt32Constant(k << l)));
+    }
+
+    Node* s1 = graph()->NewNode(machine()->Word32Shl(), p1, Int32Constant(l));
+
+    // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
+    Reduction const r1 = Reduce(graph()->NewNode(
+        machine()->Word32And(), graph()->NewNode(machine()->Int32Add(), s1, p0),
+        Int32Constant(-1 << l)));
+    ASSERT_TRUE(r1.Changed());
+    EXPECT_THAT(r1.replacement(),
+                IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)), s1));
+
+    // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
+    Reduction const r2 = Reduce(graph()->NewNode(
+        machine()->Word32And(), graph()->NewNode(machine()->Int32Add(), p0, s1),
+        Int32Constant(-1 << l)));
+    ASSERT_TRUE(r2.Changed());
+    EXPECT_THAT(r2.replacement(),
+                IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)), s1));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest,
+       Word32AndWithInt32AddAndInt32MulAndConstant) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+
+  TRACED_FORRANGE(int32_t, l, 1, 31) {
+    TRACED_FOREACH(int32_t, k, kInt32Values) {
+      if ((k << l) == 0) continue;
+      // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
+      Reduction const r1 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Int32Add(),
+                           graph()->NewNode(machine()->Int32Mul(), p1,
+                                            Int32Constant(k << l)),
+                           p0),
+          Int32Constant(-1 << l)));
+      ASSERT_TRUE(r1.Changed());
+      EXPECT_THAT(r1.replacement(),
+                  IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
+                             IsInt32Mul(p1, IsInt32Constant(k << l))));
+
+      // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
+      Reduction const r2 = Reduce(graph()->NewNode(
+          machine()->Word32And(),
+          graph()->NewNode(machine()->Int32Add(), p0,
+                           graph()->NewNode(machine()->Int32Mul(), p1,
+                                            Int32Constant(k << l))),
+          Int32Constant(-1 << l)));
+      ASSERT_TRUE(r2.Changed());
+      EXPECT_THAT(r2.replacement(),
+                  IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
+                             IsInt32Mul(p1, IsInt32Constant(k << l))));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Xor
+
+
+TEST_F(MachineOperatorReducerTest, Word32XorWithWord32XorAndMinusOne) {
+  Node* const p0 = Parameter(0);
+
+  // (x ^ -1) ^ -1 => x
+  Reduction r1 = Reduce(graph()->NewNode(
+      machine()->Word32Xor(),
+      graph()->NewNode(machine()->Word32Xor(), p0, Int32Constant(-1)),
+      Int32Constant(-1)));
+  ASSERT_TRUE(r1.Changed());
+  EXPECT_EQ(r1.replacement(), p0);
+
+  // -1 ^ (x ^ -1) => x
+  Reduction r2 = Reduce(graph()->NewNode(
+      machine()->Word32Xor(), Int32Constant(-1),
+      graph()->NewNode(machine()->Word32Xor(), p0, Int32Constant(-1))));
+  ASSERT_TRUE(r2.Changed());
+  EXPECT_EQ(r2.replacement(), p0);
+
+  // (-1 ^ x) ^ -1 => x
+  Reduction r3 = Reduce(graph()->NewNode(
+      machine()->Word32Xor(),
+      graph()->NewNode(machine()->Word32Xor(), Int32Constant(-1), p0),
+      Int32Constant(-1)));
+  ASSERT_TRUE(r3.Changed());
+  EXPECT_EQ(r3.replacement(), p0);
+
+  // -1 ^ (-1 ^ x) => x
+  Reduction r4 = Reduce(graph()->NewNode(
+      machine()->Word32Xor(), Int32Constant(-1),
+      graph()->NewNode(machine()->Word32Xor(), Int32Constant(-1), p0)));
+  ASSERT_TRUE(r4.Changed());
+  EXPECT_EQ(r4.replacement(), p0);
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Ror
+
+
+TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithParameters) {
+  Node* value = Parameter(0);
+  Node* shift = Parameter(1);
+  Node* sub = graph()->NewNode(machine()->Int32Sub(), Int32Constant(32), shift);
+
+  // Testing rotate left.
+  Node* shl_l = graph()->NewNode(machine()->Word32Shl(), value, shift);
+  Node* shr_l = graph()->NewNode(machine()->Word32Shr(), value, sub);
+
+  // (x << y) | (x >>> (32 - y)) => x ror (32 - y)
+  Node* node1 = graph()->NewNode(machine()->Word32Or(), shl_l, shr_l);
+  Reduction reduction1 = Reduce(node1);
+  EXPECT_TRUE(reduction1.Changed());
+  EXPECT_EQ(reduction1.replacement(), node1);
+  EXPECT_THAT(reduction1.replacement(), IsWord32Ror(value, sub));
+
+  // (x >>> (32 - y)) | (x << y) => x ror (32 - y)
+  Node* node2 = graph()->NewNode(machine()->Word32Or(), shr_l, shl_l);
+  Reduction reduction2 = Reduce(node2);
+  EXPECT_TRUE(reduction2.Changed());
+  EXPECT_EQ(reduction2.replacement(), node2);
+  EXPECT_THAT(reduction2.replacement(), IsWord32Ror(value, sub));
+
+  // Testing rotate right.
+  Node* shl_r = graph()->NewNode(machine()->Word32Shl(), value, sub);
+  Node* shr_r = graph()->NewNode(machine()->Word32Shr(), value, shift);
+
+  // (x << (32 - y)) | (x >>> y) => x ror y
+  Node* node3 = graph()->NewNode(machine()->Word32Or(), shl_r, shr_r);
+  Reduction reduction3 = Reduce(node3);
+  EXPECT_TRUE(reduction3.Changed());
+  EXPECT_EQ(reduction3.replacement(), node3);
+  EXPECT_THAT(reduction3.replacement(), IsWord32Ror(value, shift));
+
+  // (x >>> y) | (x << (32 - y)) => x ror y
+  Node* node4 = graph()->NewNode(machine()->Word32Or(), shr_r, shl_r);
+  Reduction reduction4 = Reduce(node4);
+  EXPECT_TRUE(reduction4.Changed());
+  EXPECT_EQ(reduction4.replacement(), node4);
+  EXPECT_THAT(reduction4.replacement(), IsWord32Ror(value, shift));
+}
+
+
+TEST_F(MachineOperatorReducerTest, ReduceToWord32RorWithConstant) {
+  Node* value = Parameter(0);
+  TRACED_FORRANGE(int32_t, k, 0, 31) {
+    Node* shl =
+        graph()->NewNode(machine()->Word32Shl(), value, Int32Constant(k));
+    Node* shr =
+        graph()->NewNode(machine()->Word32Shr(), value, Int32Constant(32 - k));
+
+    // (x << K) | (x >>> ((32 - K) - y)) => x ror (32 - K)
+    Node* node1 = graph()->NewNode(machine()->Word32Or(), shl, shr);
+    Reduction reduction1 = Reduce(node1);
+    EXPECT_TRUE(reduction1.Changed());
+    EXPECT_EQ(reduction1.replacement(), node1);
+    EXPECT_THAT(reduction1.replacement(),
+                IsWord32Ror(value, IsInt32Constant(32 - k)));
+
+    // (x >>> (32 - K)) | (x << K) => x ror (32 - K)
+    Node* node2 = graph()->NewNode(machine()->Word32Or(), shr, shl);
+    Reduction reduction2 = Reduce(node2);
+    EXPECT_TRUE(reduction2.Changed());
+    EXPECT_EQ(reduction2.replacement(), node2);
+    EXPECT_THAT(reduction2.replacement(),
+                IsWord32Ror(value, IsInt32Constant(32 - k)));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32RorWithZeroShift) {
+  Node* value = Parameter(0);
+  Node* node =
+      graph()->NewNode(machine()->Word32Ror(), value, Int32Constant(0));
+  Reduction reduction = Reduce(node);
+  EXPECT_TRUE(reduction.Changed());
+  EXPECT_EQ(reduction.replacement(), value);
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32RorWithConstants) {
+  TRACED_FOREACH(int32_t, x, kUint32Values) {
+    TRACED_FORRANGE(int32_t, y, 0, 31) {
+      Node* node = graph()->NewNode(machine()->Word32Ror(), Int32Constant(x),
+                                    Int32Constant(y));
+      Reduction reduction = Reduce(node);
+      EXPECT_TRUE(reduction.Changed());
+      EXPECT_THAT(reduction.replacement(),
+                  IsInt32Constant(base::bits::RotateRight32(x, y)));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Sar
+
+
+TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndLoad) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+  {
+    Node* const l = graph()->NewNode(machine()->Load(kMachInt8), p0, p1,
+                                     graph()->start(), graph()->start());
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Word32Sar(),
+        graph()->NewNode(machine()->Word32Shl(), l, Int32Constant(24)),
+        Int32Constant(24)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(l, r.replacement());
+  }
+  {
+    Node* const l = graph()->NewNode(machine()->Load(kMachInt16), p0, p1,
+                                     graph()->start(), graph()->start());
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Word32Sar(),
+        graph()->NewNode(machine()->Word32Shl(), l, Int32Constant(16)),
+        Int32Constant(16)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(l, r.replacement());
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Shl
+
+
+TEST_F(MachineOperatorReducerTest, Word32ShlWithZeroShift) {
+  Node* p0 = Parameter(0);
+  Node* node = graph()->NewNode(machine()->Word32Shl(), p0, Int32Constant(0));
+  Reduction r = Reduce(node);
+  ASSERT_TRUE(r.Changed());
+  EXPECT_EQ(p0, r.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32ShlWithWord32Sar) {
+  Node* p0 = Parameter(0);
+  TRACED_FORRANGE(int32_t, x, 1, 31) {
+    Node* node = graph()->NewNode(
+        machine()->Word32Shl(),
+        graph()->NewNode(machine()->Word32Sar(), p0, Int32Constant(x)),
+        Int32Constant(x));
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    int32_t m = bit_cast<int32_t>(~((1U << x) - 1U));
+    EXPECT_THAT(r.replacement(), IsWord32And(p0, IsInt32Constant(m)));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest,
+       Word32ShlWithWord32SarAndInt32AddAndConstant) {
+  Node* const p0 = Parameter(0);
+  TRACED_FOREACH(int32_t, k, kInt32Values) {
+    TRACED_FORRANGE(int32_t, l, 1, 31) {
+      if ((k << l) == 0) continue;
+      // (x + (K << L)) >> L << L => (x & (-1 << L)) + (K << L)
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Word32Shl(),
+          graph()->NewNode(machine()->Word32Sar(),
+                           graph()->NewNode(machine()->Int32Add(), p0,
+                                            Int32Constant(k << l)),
+                           Int32Constant(l)),
+          Int32Constant(l)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Add(IsWord32And(p0, IsInt32Constant(-1 << l)),
+                             IsInt32Constant(k << l)));
+    }
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Word32ShlWithWord32Shr) {
+  Node* p0 = Parameter(0);
+  TRACED_FORRANGE(int32_t, x, 1, 31) {
+    Node* node = graph()->NewNode(
+        machine()->Word32Shl(),
+        graph()->NewNode(machine()->Word32Shr(), p0, Int32Constant(x)),
+        Int32Constant(x));
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    int32_t m = bit_cast<int32_t>(~((1U << x) - 1U));
+    EXPECT_THAT(r.replacement(), IsWord32And(p0, IsInt32Constant(m)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32Div
+
+
+TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(0), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(r.replacement(), p0);
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(-1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), p0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(2), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsWord32Sar(IsInt32Add(IsWord32Shr(p0, IsInt32Constant(31)), p0),
+                    IsInt32Constant(1)));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(-2), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsInt32Sub(
+            IsInt32Constant(0),
+            IsWord32Sar(IsInt32Add(IsWord32Shr(p0, IsInt32Constant(31)), p0),
+                        IsInt32Constant(1))));
+  }
+  TRACED_FORRANGE(int32_t, shift, 2, 30) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Div(), p0,
+                                Int32Constant(1 << shift), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsWord32Sar(IsInt32Add(IsWord32Shr(IsWord32Sar(p0, IsInt32Constant(31)),
+                                           IsInt32Constant(32 - shift)),
+                               p0),
+                    IsInt32Constant(shift)));
+  }
+  TRACED_FORRANGE(int32_t, shift, 2, 31) {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0,
+        Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift),
+        graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsInt32Sub(
+            IsInt32Constant(0),
+            IsWord32Sar(
+                IsInt32Add(IsWord32Shr(IsWord32Sar(p0, IsInt32Constant(31)),
+                                       IsInt32Constant(32 - shift)),
+                           p0),
+                IsInt32Constant(shift))));
+  }
+  TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+    if (divisor < 0) {
+      if (base::bits::IsPowerOfTwo32(-divisor)) continue;
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Int32Div(), p0, Int32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0),
+                                              IsTruncatingDiv(p0, -divisor)));
+    } else if (divisor > 0) {
+      if (base::bits::IsPowerOfTwo32(divisor)) continue;
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Int32Div(), p0, Int32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsTruncatingDiv(p0, divisor));
+    }
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Int32DivWithParameters) {
+  Node* const p0 = Parameter(0);
+  Reduction const r =
+      Reduce(graph()->NewNode(machine()->Int32Div(), p0, p0, graph()->start()));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(
+      r.replacement(),
+      IsWord32Equal(IsWord32Equal(p0, IsInt32Constant(0)), IsInt32Constant(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Uint32Div
+
+
+TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), Int32Constant(0), p0, graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), p0, Int32Constant(0), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), p0, Int32Constant(1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(r.replacement(), p0);
+  }
+  TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
+    TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Uint32Div(), Uint32Constant(dividend),
+                           Uint32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(bit_cast<int32_t>(
+                      base::bits::UnsignedDiv32(dividend, divisor))));
+    }
+  }
+  TRACED_FORRANGE(uint32_t, shift, 1, 31) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
+                                Uint32Constant(1u << shift), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32Shr(p0, IsInt32Constant(bit_cast<int32_t>(shift))));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Uint32DivWithParameters) {
+  Node* const p0 = Parameter(0);
+  Reduction const r = Reduce(
+      graph()->NewNode(machine()->Uint32Div(), p0, p0, graph()->start()));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(
+      r.replacement(),
+      IsWord32Equal(IsWord32Equal(p0, IsInt32Constant(0)), IsInt32Constant(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32Mod
+
+
+TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), Int32Constant(0), p0, graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(0), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(-1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  TRACED_FOREACH(int32_t, dividend, kInt32Values) {
+    TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Int32Mod(), Int32Constant(dividend),
+                           Int32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(base::bits::SignedMod32(dividend, divisor)));
+    }
+  }
+  TRACED_FORRANGE(int32_t, shift, 1, 30) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
+                                Int32Constant(1 << shift), graph()->start()));
+    int32_t const mask = (1 << shift) - 1;
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsSelect(kMachInt32, IsInt32LessThan(p0, IsInt32Constant(0)),
+                 IsInt32Sub(IsInt32Constant(0),
+                            IsWord32And(IsInt32Sub(IsInt32Constant(0), p0),
+                                        IsInt32Constant(mask))),
+                 IsWord32And(p0, IsInt32Constant(mask))));
+  }
+  TRACED_FORRANGE(int32_t, shift, 1, 31) {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0,
+        Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift),
+        graph()->start()));
+    int32_t const mask = bit_cast<int32_t, uint32_t>((1U << shift) - 1);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsSelect(kMachInt32, IsInt32LessThan(p0, IsInt32Constant(0)),
+                 IsInt32Sub(IsInt32Constant(0),
+                            IsWord32And(IsInt32Sub(IsInt32Constant(0), p0),
+                                        IsInt32Constant(mask))),
+                 IsWord32And(p0, IsInt32Constant(mask))));
+  }
+  TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+    if (divisor == 0 || base::bits::IsPowerOfTwo32(Abs(divisor))) continue;
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(divisor), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsInt32Sub(p0, IsInt32Mul(IsTruncatingDiv(p0, Abs(divisor)),
+                                          IsInt32Constant(Abs(divisor)))));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Int32ModWithParameters) {
+  Node* const p0 = Parameter(0);
+  Reduction const r =
+      Reduce(graph()->NewNode(machine()->Int32Mod(), p0, p0, graph()->start()));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+}
+
+
+// -----------------------------------------------------------------------------
+// Uint32Mod
+
+
+TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), p0, Int32Constant(0), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), Int32Constant(0), p0, graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), p0, Int32Constant(1), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
+    TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Uint32Mod(), Uint32Constant(dividend),
+                           Uint32Constant(divisor), graph()->start()));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(bit_cast<int32_t>(
+                      base::bits::UnsignedMod32(dividend, divisor))));
+    }
+  }
+  TRACED_FORRANGE(uint32_t, shift, 1, 31) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
+                                Uint32Constant(1u << shift), graph()->start()));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsWord32And(p0, IsInt32Constant(
+                                    bit_cast<int32_t>((1u << shift) - 1u))));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) {
+  Node* const p0 = Parameter(0);
+  Reduction const r = Reduce(
+      graph()->NewNode(machine()->Uint32Mod(), p0, p0, graph()->start()));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32AddWithOverflow
+
+
+TEST_F(MachineOperatorReducerTest, Int32AddWithOverflowWithZero) {
+  Node* p0 = Parameter(0);
+  {
+    Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(),
+                                 Int32Constant(0), p0);
+
+    Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+
+    r = Reduce(graph()->NewNode(common()->Projection(0), add));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(p0, r.replacement());
+  }
+  {
+    Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), p0,
+                                 Int32Constant(0));
+
+    Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+
+    r = Reduce(graph()->NewNode(common()->Projection(0), add));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(p0, r.replacement());
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, Int32AddWithOverflowWithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    TRACED_FOREACH(int32_t, y, kInt32Values) {
+      int32_t z;
+      Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(),
+                                   Int32Constant(x), Int32Constant(y));
+
+      Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(base::bits::SignedAddOverflow32(x, y, &z)));
+
+      r = Reduce(graph()->NewNode(common()->Projection(0), add));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsInt32Constant(z));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32SubWithOverflow
+
+
+TEST_F(MachineOperatorReducerTest, Int32SubWithOverflowWithZero) {
+  Node* p0 = Parameter(0);
+  Node* add =
+      graph()->NewNode(machine()->Int32SubWithOverflow(), p0, Int32Constant(0));
+
+  Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+
+  r = Reduce(graph()->NewNode(common()->Projection(0), add));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_EQ(p0, r.replacement());
+}
+
+
+TEST_F(MachineOperatorReducerTest, Int32SubWithOverflowWithConstant) {
+  TRACED_FOREACH(int32_t, x, kInt32Values) {
+    TRACED_FOREACH(int32_t, y, kInt32Values) {
+      int32_t z;
+      Node* add = graph()->NewNode(machine()->Int32SubWithOverflow(),
+                                   Int32Constant(x), Int32Constant(y));
+
+      Reduction r = Reduce(graph()->NewNode(common()->Projection(1), add));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(),
+                  IsInt32Constant(base::bits::SignedSubOverflow32(x, y, &z)));
+
+      r = Reduce(graph()->NewNode(common()->Projection(0), add));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsInt32Constant(z));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Uint32LessThan
+
+
+TEST_F(MachineOperatorReducerTest, Uint32LessThanWithWord32Sar) {
+  Node* const p0 = Parameter(0);
+  TRACED_FORRANGE(uint32_t, shift, 1, 3) {
+    const uint32_t limit = (kMaxInt >> shift) - 1;
+    Node* const node = graph()->NewNode(
+        machine()->Uint32LessThan(),
+        graph()->NewNode(machine()->Word32Sar(), p0, Uint32Constant(shift)),
+        Uint32Constant(limit));
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsUint32LessThan(
+                    p0, IsInt32Constant(bit_cast<int32_t>(limit << shift))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Float64Mul
+
+
+TEST_F(MachineOperatorReducerTest, Float64MulWithMinusOne) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction r = Reduce(
+        graph()->NewNode(machine()->Float64Mul(), p0, Float64Constant(-1.0)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsFloat64Sub(IsFloat64Constant(BitEq(-0.0)), p0));
+  }
+  {
+    Reduction r = Reduce(
+        graph()->NewNode(machine()->Float64Mul(), Float64Constant(-1.0), p0));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsFloat64Sub(IsFloat64Constant(BitEq(-0.0)), p0));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// Store
+
+
+TEST_F(MachineOperatorReducerTest, StoreRepWord8WithWord32And) {
+  const StoreRepresentation rep(kRepWord8, kNoWriteBarrier);
+  Node* const base = Parameter(0);
+  Node* const index = Parameter(1);
+  Node* const value = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Node* const node =
+        graph()->NewNode(machine()->Store(rep), base, index,
+                         graph()->NewNode(machine()->Word32And(), value,
+                                          Uint32Constant(x | 0xffu)),
+                         effect, control);
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsStore(rep, base, index, value, effect, control));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, StoreRepWord8WithWord32SarAndWord32Shl) {
+  const StoreRepresentation rep(kRepWord8, kNoWriteBarrier);
+  Node* const base = Parameter(0);
+  Node* const index = Parameter(1);
+  Node* const value = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(int32_t, x, 1, 24) {
+    Node* const node = graph()->NewNode(
+        machine()->Store(rep), base, index,
+        graph()->NewNode(
+            machine()->Word32Sar(),
+            graph()->NewNode(machine()->Word32Shl(), value, Int32Constant(x)),
+            Int32Constant(x)),
+        effect, control);
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsStore(rep, base, index, value, effect, control));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, StoreRepWord16WithWord32And) {
+  const StoreRepresentation rep(kRepWord16, kNoWriteBarrier);
+  Node* const base = Parameter(0);
+  Node* const index = Parameter(1);
+  Node* const value = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FOREACH(uint32_t, x, kUint32Values) {
+    Node* const node =
+        graph()->NewNode(machine()->Store(rep), base, index,
+                         graph()->NewNode(machine()->Word32And(), value,
+                                          Uint32Constant(x | 0xffffu)),
+                         effect, control);
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsStore(rep, base, index, value, effect, control));
+  }
+}
+
+
+TEST_F(MachineOperatorReducerTest, StoreRepWord16WithWord32SarAndWord32Shl) {
+  const StoreRepresentation rep(kRepWord16, kNoWriteBarrier);
+  Node* const base = Parameter(0);
+  Node* const index = Parameter(1);
+  Node* const value = Parameter(2);
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  TRACED_FORRANGE(int32_t, x, 1, 16) {
+    Node* const node = graph()->NewNode(
+        machine()->Store(rep), base, index,
+        graph()->NewNode(
+            machine()->Word32Sar(),
+            graph()->NewNode(machine()->Word32Shl(), value, Int32Constant(x)),
+            Int32Constant(x)),
+        effect, control);
+
+    Reduction r = Reduce(node);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsStore(rep, base, index, value, effect, control));
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/machine-operator-unittest.cc b/test/unittests/compiler/machine-operator-unittest.cc
new file mode 100644
index 0000000..6e0df2a
--- /dev/null
+++ b/test/unittests/compiler/machine-operator-unittest.cc
@@ -0,0 +1,324 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#if GTEST_HAS_COMBINE
+
+template <typename T>
+class MachineOperatorTestWithParam
+    : public TestWithZone,
+      public ::testing::WithParamInterface< ::testing::tuple<MachineType, T> > {
+ protected:
+  MachineType type() const { return ::testing::get<0>(B::GetParam()); }
+  const T& GetParam() const { return ::testing::get<1>(B::GetParam()); }
+
+ private:
+  typedef ::testing::WithParamInterface< ::testing::tuple<MachineType, T> > B;
+};
+
+
+namespace {
+
+const MachineType kMachineReps[] = {kRepWord32, kRepWord64};
+
+
+const MachineType kMachineTypes[] = {
+    kMachFloat32, kMachFloat64,   kMachInt8,   kMachUint8,  kMachInt16,
+    kMachUint16,  kMachInt32,     kMachUint32, kMachInt64,  kMachUint64,
+    kMachPtr,     kMachAnyTagged, kRepBit,     kRepWord8,   kRepWord16,
+    kRepWord32,   kRepWord64,     kRepFloat32, kRepFloat64, kRepTagged};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Load operator.
+
+
+typedef MachineOperatorTestWithParam<LoadRepresentation>
+    MachineLoadOperatorTest;
+
+
+TEST_P(MachineLoadOperatorTest, InstancesAreGloballyShared) {
+  MachineOperatorBuilder machine1(zone(), type());
+  MachineOperatorBuilder machine2(zone(), type());
+  EXPECT_EQ(machine1.Load(GetParam()), machine2.Load(GetParam()));
+}
+
+
+TEST_P(MachineLoadOperatorTest, NumberOfInputsAndOutputs) {
+  MachineOperatorBuilder machine(zone(), type());
+  const Operator* op = machine.Load(GetParam());
+
+  EXPECT_EQ(2, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(MachineLoadOperatorTest, OpcodeIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  EXPECT_EQ(IrOpcode::kLoad, machine.Load(GetParam())->opcode());
+}
+
+
+TEST_P(MachineLoadOperatorTest, ParameterIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  EXPECT_EQ(GetParam(),
+            OpParameter<LoadRepresentation>(machine.Load(GetParam())));
+}
+
+
+INSTANTIATE_TEST_CASE_P(MachineOperatorTest, MachineLoadOperatorTest,
+                        ::testing::Combine(::testing::ValuesIn(kMachineReps),
+                                           ::testing::ValuesIn(kMachineTypes)));
+
+
+// -----------------------------------------------------------------------------
+// Store operator.
+
+
+class MachineStoreOperatorTest
+    : public MachineOperatorTestWithParam<
+          ::testing::tuple<MachineType, WriteBarrierKind> > {
+ protected:
+  StoreRepresentation GetParam() const {
+    return StoreRepresentation(
+        ::testing::get<0>(MachineOperatorTestWithParam<
+            ::testing::tuple<MachineType, WriteBarrierKind> >::GetParam()),
+        ::testing::get<1>(MachineOperatorTestWithParam<
+            ::testing::tuple<MachineType, WriteBarrierKind> >::GetParam()));
+  }
+};
+
+
+TEST_P(MachineStoreOperatorTest, InstancesAreGloballyShared) {
+  MachineOperatorBuilder machine1(zone(), type());
+  MachineOperatorBuilder machine2(zone(), type());
+  EXPECT_EQ(machine1.Store(GetParam()), machine2.Store(GetParam()));
+}
+
+
+TEST_P(MachineStoreOperatorTest, NumberOfInputsAndOutputs) {
+  MachineOperatorBuilder machine(zone(), type());
+  const Operator* op = machine.Store(GetParam());
+
+  EXPECT_EQ(3, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(MachineStoreOperatorTest, OpcodeIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  EXPECT_EQ(IrOpcode::kStore, machine.Store(GetParam())->opcode());
+}
+
+
+TEST_P(MachineStoreOperatorTest, ParameterIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  EXPECT_EQ(GetParam(),
+            OpParameter<StoreRepresentation>(machine.Store(GetParam())));
+}
+
+
+INSTANTIATE_TEST_CASE_P(
+    MachineOperatorTest, MachineStoreOperatorTest,
+    ::testing::Combine(
+        ::testing::ValuesIn(kMachineReps),
+        ::testing::Combine(::testing::ValuesIn(kMachineTypes),
+                           ::testing::Values(kNoWriteBarrier,
+                                             kFullWriteBarrier))));
+
+
+// -----------------------------------------------------------------------------
+// Pure operators.
+
+
+namespace {
+
+struct PureOperator {
+  const Operator* (MachineOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  int value_input_count;
+  int control_input_count;
+  int value_output_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
+  return os << IrOpcode::Mnemonic(pop.opcode);
+}
+
+
+const PureOperator kPureOperators[] = {
+#define PURE(Name, value_input_count, control_input_count, value_output_count) \
+  {                                                                            \
+    &MachineOperatorBuilder::Name, IrOpcode::k##Name, value_input_count,       \
+        control_input_count, value_output_count                                \
+  }
+    PURE(Word32And, 2, 0, 1), PURE(Word32Or, 2, 0, 1), PURE(Word32Xor, 2, 0, 1),
+    PURE(Word32Shl, 2, 0, 1), PURE(Word32Shr, 2, 0, 1),
+    PURE(Word32Sar, 2, 0, 1), PURE(Word32Ror, 2, 0, 1),
+    PURE(Word32Equal, 2, 0, 1), PURE(Word64And, 2, 0, 1),
+    PURE(Word64Or, 2, 0, 1), PURE(Word64Xor, 2, 0, 1), PURE(Word64Shl, 2, 0, 1),
+    PURE(Word64Shr, 2, 0, 1), PURE(Word64Sar, 2, 0, 1),
+    PURE(Word64Ror, 2, 0, 1), PURE(Word64Equal, 2, 0, 1),
+    PURE(Int32Add, 2, 0, 1), PURE(Int32AddWithOverflow, 2, 0, 2),
+    PURE(Int32Sub, 2, 0, 1), PURE(Int32SubWithOverflow, 2, 0, 2),
+    PURE(Int32Mul, 2, 0, 1), PURE(Int32MulHigh, 2, 0, 1),
+    PURE(Int32Div, 2, 1, 1), PURE(Uint32Div, 2, 1, 1), PURE(Int32Mod, 2, 1, 1),
+    PURE(Uint32Mod, 2, 1, 1), PURE(Int32LessThan, 2, 0, 1),
+    PURE(Int32LessThanOrEqual, 2, 0, 1), PURE(Uint32LessThan, 2, 0, 1),
+    PURE(Uint32LessThanOrEqual, 2, 0, 1), PURE(Int64Add, 2, 0, 1),
+    PURE(Int64Sub, 2, 0, 1), PURE(Int64Mul, 2, 0, 1), PURE(Int64Div, 2, 0, 1),
+    PURE(Uint64Div, 2, 0, 1), PURE(Int64Mod, 2, 0, 1), PURE(Uint64Mod, 2, 0, 1),
+    PURE(Int64LessThan, 2, 0, 1), PURE(Int64LessThanOrEqual, 2, 0, 1),
+    PURE(Uint64LessThan, 2, 0, 1), PURE(ChangeFloat32ToFloat64, 1, 0, 1),
+    PURE(ChangeFloat64ToInt32, 1, 0, 1), PURE(ChangeFloat64ToUint32, 1, 0, 1),
+    PURE(ChangeInt32ToInt64, 1, 0, 1), PURE(ChangeUint32ToFloat64, 1, 0, 1),
+    PURE(ChangeUint32ToUint64, 1, 0, 1),
+    PURE(TruncateFloat64ToFloat32, 1, 0, 1),
+    PURE(TruncateFloat64ToInt32, 1, 0, 1), PURE(TruncateInt64ToInt32, 1, 0, 1),
+    PURE(Float64Add, 2, 0, 1), PURE(Float64Sub, 2, 0, 1),
+    PURE(Float64Mul, 2, 0, 1), PURE(Float64Div, 2, 0, 1),
+    PURE(Float64Mod, 2, 0, 1), PURE(Float64Sqrt, 1, 0, 1),
+    PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1),
+    PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1),
+    PURE(Float64Floor, 1, 0, 1), PURE(Float64Ceil, 1, 0, 1),
+    PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1)
+#undef PURE
+};
+
+
+typedef MachineOperatorTestWithParam<PureOperator> MachinePureOperatorTest;
+
+}  // namespace
+
+
+TEST_P(MachinePureOperatorTest, InstancesAreGloballyShared) {
+  const PureOperator& pop = GetParam();
+  MachineOperatorBuilder machine1(zone(), type());
+  MachineOperatorBuilder machine2(zone(), type());
+  EXPECT_EQ((machine1.*pop.constructor)(), (machine2.*pop.constructor)());
+}
+
+
+TEST_P(MachinePureOperatorTest, NumberOfInputsAndOutputs) {
+  MachineOperatorBuilder machine(zone(), type());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (machine.*pop.constructor)();
+
+  EXPECT_EQ(pop.value_input_count, op->ValueInputCount());
+  EXPECT_EQ(0, op->EffectInputCount());
+  EXPECT_EQ(pop.control_input_count, op->ControlInputCount());
+  EXPECT_EQ(pop.value_input_count + pop.control_input_count,
+            OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(pop.value_output_count, op->ValueOutputCount());
+  EXPECT_EQ(0, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(MachinePureOperatorTest, MarkedAsPure) {
+  MachineOperatorBuilder machine(zone(), type());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (machine.*pop.constructor)();
+  EXPECT_TRUE(op->HasProperty(Operator::kPure));
+}
+
+
+TEST_P(MachinePureOperatorTest, OpcodeIsCorrect) {
+  MachineOperatorBuilder machine(zone(), type());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (machine.*pop.constructor)();
+  EXPECT_EQ(pop.opcode, op->opcode());
+}
+
+
+INSTANTIATE_TEST_CASE_P(
+    MachineOperatorTest, MachinePureOperatorTest,
+    ::testing::Combine(::testing::ValuesIn(kMachineReps),
+                       ::testing::ValuesIn(kPureOperators)));
+
+#endif  // GTEST_HAS_COMBINE
+
+
+// -----------------------------------------------------------------------------
+// Pseudo operators.
+
+
+namespace {
+
+typedef TestWithZone MachineOperatorTest;
+
+}  // namespace
+
+
+TEST_F(MachineOperatorTest, PseudoOperatorsWhenWordSizeIs32Bit) {
+  MachineOperatorBuilder machine(zone(), kRepWord32);
+  EXPECT_EQ(machine.Word32And(), machine.WordAnd());
+  EXPECT_EQ(machine.Word32Or(), machine.WordOr());
+  EXPECT_EQ(machine.Word32Xor(), machine.WordXor());
+  EXPECT_EQ(machine.Word32Shl(), machine.WordShl());
+  EXPECT_EQ(machine.Word32Shr(), machine.WordShr());
+  EXPECT_EQ(machine.Word32Sar(), machine.WordSar());
+  EXPECT_EQ(machine.Word32Ror(), machine.WordRor());
+  EXPECT_EQ(machine.Word32Equal(), machine.WordEqual());
+  EXPECT_EQ(machine.Int32Add(), machine.IntAdd());
+  EXPECT_EQ(machine.Int32Sub(), machine.IntSub());
+  EXPECT_EQ(machine.Int32Mul(), machine.IntMul());
+  EXPECT_EQ(machine.Int32Div(), machine.IntDiv());
+  EXPECT_EQ(machine.Uint32Div(), machine.UintDiv());
+  EXPECT_EQ(machine.Int32Mod(), machine.IntMod());
+  EXPECT_EQ(machine.Uint32Mod(), machine.UintMod());
+  EXPECT_EQ(machine.Int32LessThan(), machine.IntLessThan());
+  EXPECT_EQ(machine.Int32LessThanOrEqual(), machine.IntLessThanOrEqual());
+}
+
+
+TEST_F(MachineOperatorTest, PseudoOperatorsWhenWordSizeIs64Bit) {
+  MachineOperatorBuilder machine(zone(), kRepWord64);
+  EXPECT_EQ(machine.Word64And(), machine.WordAnd());
+  EXPECT_EQ(machine.Word64Or(), machine.WordOr());
+  EXPECT_EQ(machine.Word64Xor(), machine.WordXor());
+  EXPECT_EQ(machine.Word64Shl(), machine.WordShl());
+  EXPECT_EQ(machine.Word64Shr(), machine.WordShr());
+  EXPECT_EQ(machine.Word64Sar(), machine.WordSar());
+  EXPECT_EQ(machine.Word64Ror(), machine.WordRor());
+  EXPECT_EQ(machine.Word64Equal(), machine.WordEqual());
+  EXPECT_EQ(machine.Int64Add(), machine.IntAdd());
+  EXPECT_EQ(machine.Int64Sub(), machine.IntSub());
+  EXPECT_EQ(machine.Int64Mul(), machine.IntMul());
+  EXPECT_EQ(machine.Int64Div(), machine.IntDiv());
+  EXPECT_EQ(machine.Uint64Div(), machine.UintDiv());
+  EXPECT_EQ(machine.Int64Mod(), machine.IntMod());
+  EXPECT_EQ(machine.Uint64Mod(), machine.UintMod());
+  EXPECT_EQ(machine.Int64LessThan(), machine.IntLessThan());
+  EXPECT_EQ(machine.Int64LessThanOrEqual(), machine.IntLessThanOrEqual());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/mips/OWNERS b/test/unittests/compiler/mips/OWNERS
new file mode 100644
index 0000000..5508ba6
--- /dev/null
+++ b/test/unittests/compiler/mips/OWNERS
@@ -0,0 +1,5 @@
+paul.lind@imgtec.com
+gergely.kis@imgtec.com
+akos.palfi@imgtec.com
+balazs.kilvady@imgtec.com
+dusan.milosavljevic@imgtec.com
diff --git a/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc b/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc
new file mode 100644
index 0000000..0b3a0f5
--- /dev/null
+++ b/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc
@@ -0,0 +1,805 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+template <typename T>
+struct MachInst {
+  T constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  MachineType machine_type;
+};
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
+  return os << mi.constructor_name;
+}
+
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
+
+// To avoid duplicated code IntCmp helper structure
+// is created. It contains MachInst2 with two nodes and expected_size
+// because different cmp instructions have different size.
+struct IntCmp {
+  MachInst2 mi;
+  uint32_t expected_size;
+};
+
+struct FPCmp {
+  MachInst2 mi;
+  FlagsCondition cond;
+};
+
+const FPCmp kFPCmpInstructions[] = {
+    {{&RawMachineAssembler::Float64Equal, "Float64Equal", kMipsCmpD,
+      kMachFloat64},
+     kUnorderedEqual},
+    {{&RawMachineAssembler::Float64LessThan, "Float64LessThan", kMipsCmpD,
+      kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
+      kMipsCmpD, kMachFloat64},
+     kUnorderedLessThanOrEqual},
+    {{&RawMachineAssembler::Float64GreaterThan, "Float64GreaterThan", kMipsCmpD,
+      kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64GreaterThanOrEqual,
+      "Float64GreaterThanOrEqual", kMipsCmpD, kMachFloat64},
+     kUnorderedLessThanOrEqual}};
+
+struct Conversion {
+  // The machine_type field in MachInst1 represents the destination type.
+  MachInst1 mi;
+  MachineType src_machine_type;
+};
+
+
+// ----------------------------------------------------------------------------
+// Logical instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kLogicalInstructions[] = {
+    {&RawMachineAssembler::WordAnd, "WordAnd", kMipsAnd, kMachInt16},
+    {&RawMachineAssembler::WordOr, "WordOr", kMipsOr, kMachInt16},
+    {&RawMachineAssembler::WordXor, "WordXor", kMipsXor, kMachInt16},
+    {&RawMachineAssembler::Word32And, "Word32And", kMipsAnd, kMachInt32},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kMipsOr, kMachInt32},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kMipsXor, kMachInt32}};
+
+
+// ----------------------------------------------------------------------------
+// Shift instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kShiftInstructions[] = {
+    {&RawMachineAssembler::WordShl, "WordShl", kMipsShl, kMachInt16},
+    {&RawMachineAssembler::WordShr, "WordShr", kMipsShr, kMachInt16},
+    {&RawMachineAssembler::WordSar, "WordSar", kMipsSar, kMachInt16},
+    {&RawMachineAssembler::WordRor, "WordRor", kMipsRor, kMachInt16},
+    {&RawMachineAssembler::Word32Shl, "Word32Shl", kMipsShl, kMachInt32},
+    {&RawMachineAssembler::Word32Shr, "Word32Shr", kMipsShr, kMachInt32},
+    {&RawMachineAssembler::Word32Sar, "Word32Sar", kMipsSar, kMachInt32},
+    {&RawMachineAssembler::Word32Ror, "Word32Ror", kMipsRor, kMachInt32}};
+
+
+// ----------------------------------------------------------------------------
+// MUL/DIV instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kMulDivInstructions[] = {
+    {&RawMachineAssembler::Int32Mul, "Int32Mul", kMipsMul, kMachInt32},
+    {&RawMachineAssembler::Int32Div, "Int32Div", kMipsDiv, kMachInt32},
+    {&RawMachineAssembler::Uint32Div, "Uint32Div", kMipsDivU, kMachUint32},
+    {&RawMachineAssembler::Float64Mul, "Float64Mul", kMipsMulD, kMachFloat64},
+    {&RawMachineAssembler::Float64Div, "Float64Div", kMipsDivD, kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// MOD instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kModInstructions[] = {
+    {&RawMachineAssembler::Int32Mod, "Int32Mod", kMipsMod, kMachInt32},
+    {&RawMachineAssembler::Uint32Mod, "Int32UMod", kMipsModU, kMachInt32},
+    {&RawMachineAssembler::Float64Mod, "Float64Mod", kMipsModD, kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic FPU instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kFPArithInstructions[] = {
+    {&RawMachineAssembler::Float64Add, "Float64Add", kMipsAddD, kMachFloat64},
+    {&RawMachineAssembler::Float64Sub, "Float64Sub", kMipsSubD, kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// IntArithTest instructions, two nodes.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kAddSubInstructions[] = {
+    {&RawMachineAssembler::Int32Add, "Int32Add", kMipsAdd, kMachInt32},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub", kMipsSub, kMachInt32},
+    {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
+     kMipsAddOvf, kMachInt32},
+    {&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
+     kMipsSubOvf, kMachInt32}};
+
+
+// ----------------------------------------------------------------------------
+// IntArithTest instructions, one node.
+// ----------------------------------------------------------------------------
+
+
+const MachInst1 kAddSubOneInstructions[] = {
+    {&RawMachineAssembler::Int32Neg, "Int32Neg", kMipsSub, kMachInt32},
+    // TODO(dusmil): check this ...
+    // {&RawMachineAssembler::WordEqual  , "WordEqual"  , kMipsTst, kMachInt32}
+};
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic compare instructions.
+// ----------------------------------------------------------------------------
+
+
+const IntCmp kCmpInstructions[] = {
+    {{&RawMachineAssembler::WordEqual, "WordEqual", kMipsCmp, kMachInt16}, 1U},
+    {{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMipsCmp, kMachInt16},
+     1U},
+    {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMipsCmp, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMipsCmp,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMipsCmp,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
+      kMipsCmp, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMipsCmp,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
+      kMipsCmp, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMipsCmp,
+      kMachUint32},
+     1U},
+    {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
+      kMipsCmp, kMachUint32},
+     1U}};
+
+
+// ----------------------------------------------------------------------------
+// Conversion instructions.
+// ----------------------------------------------------------------------------
+
+const Conversion kConversionInstructions[] = {
+    // Conversion instructions are related to machine_operator.h:
+    // FPU conversions:
+    // Convert representation of integers between float64 and int32/uint32.
+    // The precise rounding mode and handling of out of range inputs are *not*
+    // defined for these operators, since they are intended only for use with
+    // integers.
+    // mips instruction: cvt_d_w
+    {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
+      kMipsCvtDW, kMachFloat64},
+     kMachInt32},
+
+    // mips instruction: cvt_d_uw
+    {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
+      kMipsCvtDUw, kMachFloat64},
+     kMachInt32},
+
+    // mips instruction: trunc_w_d
+    {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
+      kMipsTruncWD, kMachFloat64},
+     kMachInt32},
+
+    // mips instruction: trunc_uw_d
+    {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
+      kMipsTruncUwD, kMachFloat64},
+     kMachInt32}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
+
+
+TEST_P(InstructionSelectorFPCmpTest, Parameter) {
+  const FPCmp cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
+                        ::testing::ValuesIn(kFPCmpInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic compare instructions integers.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<IntCmp> InstructionSelectorCmpTest;
+
+
+TEST_P(InstructionSelectorCmpTest, Parameter) {
+  const IntCmp cmp = GetParam();
+  const MachineType type = cmp.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(cmp.expected_size, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorCmpTest,
+                        ::testing::ValuesIn(kCmpInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Shift instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorShiftTest;
+
+
+TEST_P(InstructionSelectorShiftTest, Immediate) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
+    StreamBuilder m(this, type, type);
+    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
+                        ::testing::ValuesIn(kShiftInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Logical instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorLogicalTest;
+
+
+TEST_P(InstructionSelectorLogicalTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
+                        ::testing::ValuesIn(kLogicalInstructions));
+
+
+// ----------------------------------------------------------------------------
+// MUL/DIV instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorMulDivTest;
+
+
+TEST_P(InstructionSelectorMulDivTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
+                        ::testing::ValuesIn(kMulDivInstructions));
+
+
+// ----------------------------------------------------------------------------
+// MOD instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2> InstructionSelectorModTest;
+
+
+TEST_P(InstructionSelectorModTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorModTest,
+                        ::testing::ValuesIn(kModInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Floating point instructions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorFPArithTest;
+
+
+TEST_P(InstructionSelectorFPArithTest, Parameter) {
+  const MachInst2 fpa = GetParam();
+  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
+  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
+                        ::testing::ValuesIn(kFPArithInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Integer arithmetic.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorIntArithTwoTest;
+
+
+TEST_P(InstructionSelectorIntArithTwoTest, Parameter) {
+  const MachInst2 intpa = GetParam();
+  StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
+                  intpa.machine_type);
+  m.Return((m.*intpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntArithTwoTest,
+                        ::testing::ValuesIn(kAddSubInstructions));
+
+
+// ----------------------------------------------------------------------------
+// One node.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst1>
+    InstructionSelectorIntArithOneTest;
+
+
+TEST_P(InstructionSelectorIntArithOneTest, Parameter) {
+  const MachInst1 intpa = GetParam();
+  StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
+                  intpa.machine_type);
+  m.Return((m.*intpa.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntArithOneTest,
+                        ::testing::ValuesIn(kAddSubOneInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Conversions.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<Conversion>
+    InstructionSelectorConversionTest;
+
+
+TEST_P(InstructionSelectorConversionTest, Parameter) {
+  const Conversion conv = GetParam();
+  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
+  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorConversionTest,
+                        ::testing::ValuesIn(kConversionInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Loads and stores.
+// ----------------------------------------------------------------------------
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+};
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8, kMipsLb, kMipsSb},
+    {kMachUint8, kMipsLbu, kMipsSb},
+    {kMachInt16, kMipsLh, kMipsSh},
+    {kMachUint16, kMipsLhu, kMipsSh},
+    {kMachInt32, kMipsLw, kMipsSw},
+    {kRepFloat32, kMipsLwc1, kMipsSwc1},
+    {kRepFloat64, kMipsLdc1, kMipsSdc1}};
+
+
+struct MemoryAccessImm {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[40];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccessImm& acc) {
+  return os << acc.type;
+}
+
+
+struct MemoryAccessImm1 {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[5];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
+  return os << acc.type;
+}
+
+
+// ----------------------------------------------------------------------------
+// Loads and stores immediate values.
+// ----------------------------------------------------------------------------
+
+
+const MemoryAccessImm kMemoryAccessesImm[] = {
+    {kMachInt8,
+     kMipsLb,
+     kMipsSb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint8,
+     kMipsLbu,
+     kMipsSb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt16,
+     kMipsLh,
+     kMipsSh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint16,
+     kMipsLhu,
+     kMipsSh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt32,
+     kMipsLw,
+     kMipsSw,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachFloat32,
+     kMipsLwc1,
+     kMipsSwc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachFloat64,
+     kMipsLdc1,
+     kMipsSdc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
+
+
+const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
+    {kMachInt8,
+     kMipsLb,
+     kMipsSb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt8,
+     kMipsLbu,
+     kMipsSb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt16,
+     kMipsLh,
+     kMipsSh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt16,
+     kMipsLhu,
+     kMipsSh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt32,
+     kMipsLw,
+     kMipsSw,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachFloat32,
+     kMipsLwc1,
+     kMipsSwc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachFloat64,
+     kMipsLdc1,
+     kMipsSdc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-65000, -55000, 32777, 55000, 65000}}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// ----------------------------------------------------------------------------
+// Load immediate.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccessImm>
+    InstructionSelectorMemoryAccessImmTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessImmTest, LoadWithImmediateIndex) {
+  const MemoryAccessImm memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// Store immediate.
+// ----------------------------------------------------------------------------
+
+
+TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) {
+  const MemoryAccessImm memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessImmTest,
+                        ::testing::ValuesIn(kMemoryAccessesImm));
+
+
+// ----------------------------------------------------------------------------
+// Load/store offsets more than 16 bits.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccessImm1>
+    InstructionSelectorMemoryAccessImmMoreThan16bitTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+       LoadWithImmediateIndex) {
+  const MemoryAccessImm1 memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(2U, s.size());
+    // kMipsAdd is expected opcode.
+    // size more than 16 bits wide.
+    EXPECT_EQ(kMipsAdd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+       StoreWithImmediateIndex) {
+  const MemoryAccessImm1 memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(2U, s.size());
+    // kMipsAdd is expected opcode
+    // size more than 16 bits wide
+    EXPECT_EQ(kMipsAdd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+                        ::testing::ValuesIn(kMemoryAccessImmMoreThan16bit));
+
+
+// ----------------------------------------------------------------------------
+// kMipsTst testing.
+// ----------------------------------------------------------------------------
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMipsCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMipsCmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/mips64/OWNERS b/test/unittests/compiler/mips64/OWNERS
new file mode 100644
index 0000000..5508ba6
--- /dev/null
+++ b/test/unittests/compiler/mips64/OWNERS
@@ -0,0 +1,5 @@
+paul.lind@imgtec.com
+gergely.kis@imgtec.com
+akos.palfi@imgtec.com
+balazs.kilvady@imgtec.com
+dusan.milosavljevic@imgtec.com
diff --git a/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc b/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc
new file mode 100644
index 0000000..a39ae75
--- /dev/null
+++ b/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc
@@ -0,0 +1,807 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+template <typename T>
+struct MachInst {
+  T constructor;
+  const char* constructor_name;
+  ArchOpcode arch_opcode;
+  MachineType machine_type;
+};
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const MachInst<T>& mi) {
+  return os << mi.constructor_name;
+}
+
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*)> MachInst1;
+typedef MachInst<Node* (RawMachineAssembler::*)(Node*, Node*)> MachInst2;
+
+
+// To avoid duplicated code IntCmp helper structure
+// is created. It contains MachInst2 with two nodes and expected_size
+// because different cmp instructions have different size.
+struct IntCmp {
+  MachInst2 mi;
+  uint32_t expected_size;
+};
+
+struct FPCmp {
+  MachInst2 mi;
+  FlagsCondition cond;
+};
+
+const FPCmp kFPCmpInstructions[] = {
+    {{&RawMachineAssembler::Float64Equal, "Float64Equal", kMips64CmpD,
+      kMachFloat64},
+     kUnorderedEqual},
+    {{&RawMachineAssembler::Float64LessThan, "Float64LessThan", kMips64CmpD,
+      kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64LessThanOrEqual, "Float64LessThanOrEqual",
+      kMips64CmpD, kMachFloat64},
+     kUnorderedLessThanOrEqual},
+    {{&RawMachineAssembler::Float64GreaterThan, "Float64GreaterThan",
+      kMips64CmpD, kMachFloat64},
+     kUnorderedLessThan},
+    {{&RawMachineAssembler::Float64GreaterThanOrEqual,
+      "Float64GreaterThanOrEqual", kMips64CmpD, kMachFloat64},
+     kUnorderedLessThanOrEqual}};
+
+struct Conversion {
+  // The machine_type field in MachInst1 represents the destination type.
+  MachInst1 mi;
+  MachineType src_machine_type;
+};
+
+
+// ----------------------------------------------------------------------------
+// Logical instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kLogicalInstructions[] = {
+    {&RawMachineAssembler::Word32And, "Word32And", kMips64And, kMachInt32},
+    {&RawMachineAssembler::Word64And, "Word64And", kMips64And, kMachInt64},
+    {&RawMachineAssembler::Word32Or, "Word32Or", kMips64Or, kMachInt32},
+    {&RawMachineAssembler::Word64Or, "Word64Or", kMips64Or, kMachInt64},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor", kMips64Xor, kMachInt32},
+    {&RawMachineAssembler::Word64Xor, "Word64Xor", kMips64Xor, kMachInt64}};
+
+
+// ----------------------------------------------------------------------------
+// Shift instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kShiftInstructions[] = {
+    {&RawMachineAssembler::Word32Shl, "Word32Shl", kMips64Shl, kMachInt32},
+    {&RawMachineAssembler::Word64Shl, "Word64Shl", kMips64Dshl, kMachInt64},
+    {&RawMachineAssembler::Word32Shr, "Word32Shr", kMips64Shr, kMachInt32},
+    {&RawMachineAssembler::Word64Shr, "Word64Shr", kMips64Dshr, kMachInt64},
+    {&RawMachineAssembler::Word32Sar, "Word32Sar", kMips64Sar, kMachInt32},
+    {&RawMachineAssembler::Word64Sar, "Word64Sar", kMips64Dsar, kMachInt64},
+    {&RawMachineAssembler::Word32Ror, "Word32Ror", kMips64Ror, kMachInt32},
+    {&RawMachineAssembler::Word64Ror, "Word64Ror", kMips64Dror, kMachInt64}};
+
+
+// ----------------------------------------------------------------------------
+// MUL/DIV instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kMulDivInstructions[] = {
+    {&RawMachineAssembler::Int32Mul, "Int32Mul", kMips64Mul, kMachInt32},
+    {&RawMachineAssembler::Int32Div, "Int32Div", kMips64Div, kMachInt32},
+    {&RawMachineAssembler::Uint32Div, "Uint32Div", kMips64DivU, kMachUint32},
+    {&RawMachineAssembler::Int64Mul, "Int64Mul", kMips64Dmul, kMachInt64},
+    {&RawMachineAssembler::Int64Div, "Int64Div", kMips64Ddiv, kMachInt64},
+    {&RawMachineAssembler::Uint64Div, "Uint64Div", kMips64DdivU, kMachUint64},
+    {&RawMachineAssembler::Float64Mul, "Float64Mul", kMips64MulD, kMachFloat64},
+    {&RawMachineAssembler::Float64Div, "Float64Div", kMips64DivD,
+     kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// MOD instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kModInstructions[] = {
+    {&RawMachineAssembler::Int32Mod, "Int32Mod", kMips64Mod, kMachInt32},
+    {&RawMachineAssembler::Uint32Mod, "Uint32Mod", kMips64ModU, kMachInt32},
+    {&RawMachineAssembler::Float64Mod, "Float64Mod", kMips64ModD,
+     kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic FPU instructions.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kFPArithInstructions[] = {
+    {&RawMachineAssembler::Float64Add, "Float64Add", kMips64AddD, kMachFloat64},
+    {&RawMachineAssembler::Float64Sub, "Float64Sub", kMips64SubD,
+     kMachFloat64}};
+
+
+// ----------------------------------------------------------------------------
+// IntArithTest instructions, two nodes.
+// ----------------------------------------------------------------------------
+
+
+const MachInst2 kAddSubInstructions[] = {
+    {&RawMachineAssembler::Int32Add, "Int32Add", kMips64Add, kMachInt32},
+    {&RawMachineAssembler::Int64Add, "Int64Add", kMips64Dadd, kMachInt64},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub", kMips64Sub, kMachInt32},
+    {&RawMachineAssembler::Int64Sub, "Int64Sub", kMips64Dsub, kMachInt64}};
+
+
+// ----------------------------------------------------------------------------
+// IntArithTest instructions, one node.
+// ----------------------------------------------------------------------------
+
+
+const MachInst1 kAddSubOneInstructions[] = {
+    {&RawMachineAssembler::Int32Neg, "Int32Neg", kMips64Sub, kMachInt32},
+    {&RawMachineAssembler::Int64Neg, "Int64Neg", kMips64Dsub, kMachInt64}};
+
+
+// ----------------------------------------------------------------------------
+// Arithmetic compare instructions.
+// ----------------------------------------------------------------------------
+
+
+const IntCmp kCmpInstructions[] = {
+    {{&RawMachineAssembler::WordEqual, "WordEqual", kMips64Cmp, kMachInt64},
+     1U},
+    {{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMips64Cmp,
+      kMachInt64},
+     1U},
+    {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp32,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMips64Cmp32,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp32,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual",
+      kMips64Cmp32, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMips64Cmp32,
+      kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual",
+      kMips64Cmp32, kMachInt32},
+     1U},
+    {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp32,
+      kMachUint32},
+     1U},
+    {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual",
+      kMips64Cmp32, kMachUint32},
+     1U}};
+
+
+// ----------------------------------------------------------------------------
+// Conversion instructions.
+// ----------------------------------------------------------------------------
+
+const Conversion kConversionInstructions[] = {
+    // Conversion instructions are related to machine_operator.h:
+    // FPU conversions:
+    // Convert representation of integers between float64 and int32/uint32.
+    // The precise rounding mode and handling of out of range inputs are *not*
+    // defined for these operators, since they are intended only for use with
+    // integers.
+    // mips instructions:
+    // mtc1, cvt.d.w
+    {{&RawMachineAssembler::ChangeInt32ToFloat64, "ChangeInt32ToFloat64",
+      kMips64CvtDW, kMachFloat64},
+     kMachInt32},
+
+    // mips instructions:
+    // cvt.d.uw
+    {{&RawMachineAssembler::ChangeUint32ToFloat64, "ChangeUint32ToFloat64",
+      kMips64CvtDUw, kMachFloat64},
+     kMachInt32},
+
+    // mips instructions:
+    // mfc1, trunc double to word, for more details look at mips macro
+    // asm and mips asm file
+    {{&RawMachineAssembler::ChangeFloat64ToInt32, "ChangeFloat64ToInt32",
+      kMips64TruncWD, kMachFloat64},
+     kMachInt32},
+
+    // mips instructions:
+    // trunc double to unsigned word, for more details look at mips macro
+    // asm and mips asm file
+    {{&RawMachineAssembler::ChangeFloat64ToUint32, "ChangeFloat64ToUint32",
+      kMips64TruncUwD, kMachFloat64},
+     kMachInt32}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<FPCmp> InstructionSelectorFPCmpTest;
+
+TEST_P(InstructionSelectorFPCmpTest, Parameter) {
+  const FPCmp cmp = GetParam();
+  StreamBuilder m(this, kMachInt32, cmp.mi.machine_type, cmp.mi.machine_type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+  EXPECT_EQ(cmp.cond, s[0]->flags_condition());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPCmpTest,
+                        ::testing::ValuesIn(kFPCmpInstructions));
+
+// ----------------------------------------------------------------------------
+// Arithmetic compare instructions integers
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<IntCmp> InstructionSelectorCmpTest;
+
+
+TEST_P(InstructionSelectorCmpTest, Parameter) {
+  const IntCmp cmp = GetParam();
+  const MachineType type = cmp.mi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*cmp.mi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(cmp.expected_size, s.size());
+  EXPECT_EQ(cmp.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorCmpTest,
+                        ::testing::ValuesIn(kCmpInstructions));
+
+// ----------------------------------------------------------------------------
+// Shift instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorShiftTest;
+
+TEST_P(InstructionSelectorShiftTest, Immediate) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  TRACED_FORRANGE(int32_t, imm, 0, (ElementSizeOf(type) * 8) - 1) {
+    StreamBuilder m(this, type, type);
+    m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+    EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
+                        ::testing::ValuesIn(kShiftInstructions));
+
+// ----------------------------------------------------------------------------
+// Logical instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorLogicalTest;
+
+
+TEST_P(InstructionSelectorLogicalTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest,
+                        ::testing::ValuesIn(kLogicalInstructions));
+
+// ----------------------------------------------------------------------------
+// MUL/DIV instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorMulDivTest;
+
+TEST_P(InstructionSelectorMulDivTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMulDivTest,
+                        ::testing::ValuesIn(kMulDivInstructions));
+
+// ----------------------------------------------------------------------------
+// MOD instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2> InstructionSelectorModTest;
+
+TEST_P(InstructionSelectorModTest, Parameter) {
+  const MachInst2 dpi = GetParam();
+  const MachineType type = dpi.machine_type;
+  StreamBuilder m(this, type, type, type);
+  m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorModTest,
+                        ::testing::ValuesIn(kModInstructions));
+
+// ----------------------------------------------------------------------------
+// Floating point instructions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorFPArithTest;
+
+TEST_P(InstructionSelectorFPArithTest, Parameter) {
+  const MachInst2 fpa = GetParam();
+  StreamBuilder m(this, fpa.machine_type, fpa.machine_type, fpa.machine_type);
+  m.Return((m.*fpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(fpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFPArithTest,
+                        ::testing::ValuesIn(kFPArithInstructions));
+// ----------------------------------------------------------------------------
+// Integer arithmetic
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<MachInst2>
+    InstructionSelectorIntArithTwoTest;
+
+TEST_P(InstructionSelectorIntArithTwoTest, Parameter) {
+  const MachInst2 intpa = GetParam();
+  StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
+                  intpa.machine_type);
+  m.Return((m.*intpa.constructor)(m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntArithTwoTest,
+                        ::testing::ValuesIn(kAddSubInstructions));
+
+
+// ----------------------------------------------------------------------------
+// One node.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MachInst1>
+    InstructionSelectorIntArithOneTest;
+
+TEST_P(InstructionSelectorIntArithOneTest, Parameter) {
+  const MachInst1 intpa = GetParam();
+  StreamBuilder m(this, intpa.machine_type, intpa.machine_type,
+                  intpa.machine_type);
+  m.Return((m.*intpa.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(intpa.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorIntArithOneTest,
+                        ::testing::ValuesIn(kAddSubOneInstructions));
+// ----------------------------------------------------------------------------
+// Conversions.
+// ----------------------------------------------------------------------------
+typedef InstructionSelectorTestWithParam<Conversion>
+    InstructionSelectorConversionTest;
+
+TEST_P(InstructionSelectorConversionTest, Parameter) {
+  const Conversion conv = GetParam();
+  StreamBuilder m(this, conv.mi.machine_type, conv.src_machine_type);
+  m.Return((m.*conv.mi.constructor)(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(conv.mi.arch_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorConversionTest,
+                        ::testing::ValuesIn(kConversionInstructions));
+
+
+// ----------------------------------------------------------------------------
+// Loads and stores.
+// ----------------------------------------------------------------------------
+
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+};
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8, kMips64Lb, kMips64Sb},
+    {kMachUint8, kMips64Lbu, kMips64Sb},
+    {kMachInt16, kMips64Lh, kMips64Sh},
+    {kMachUint16, kMips64Lhu, kMips64Sh},
+    {kMachInt32, kMips64Lw, kMips64Sw},
+    {kRepFloat32, kMips64Lwc1, kMips64Swc1},
+    {kRepFloat64, kMips64Ldc1, kMips64Sdc1},
+    {kMachInt64, kMips64Ld, kMips64Sd}};
+
+
+struct MemoryAccessImm {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[40];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccessImm& acc) {
+  return os << acc.type;
+}
+
+
+struct MemoryAccessImm1 {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+  bool (InstructionSelectorTest::Stream::*val_predicate)(
+      const InstructionOperand*) const;
+  const int32_t immediates[5];
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccessImm1& acc) {
+  return os << acc.type;
+}
+
+
+// ----------------------------------------------------------------------------
+// Loads and stores immediate values
+// ----------------------------------------------------------------------------
+
+
+const MemoryAccessImm kMemoryAccessesImm[] = {
+    {kMachInt8,
+     kMips64Lb,
+     kMips64Sb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint8,
+     kMips64Lbu,
+     kMips64Sb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt16,
+     kMips64Lh,
+     kMips64Sh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachUint16,
+     kMips64Lhu,
+     kMips64Sh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt32,
+     kMips64Lw,
+     kMips64Sw,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachFloat32,
+     kMips64Lwc1,
+     kMips64Swc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachFloat64,
+     kMips64Ldc1,
+     kMips64Sdc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
+    {kMachInt64,
+     kMips64Ld,
+     kMips64Sd,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
+      -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
+      115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}};
+
+
+const MemoryAccessImm1 kMemoryAccessImmMoreThan16bit[] = {
+    {kMachInt8,
+     kMips64Lb,
+     kMips64Sb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt8,
+     kMips64Lbu,
+     kMips64Sb,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt16,
+     kMips64Lh,
+     kMips64Sh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt16,
+     kMips64Lhu,
+     kMips64Sh,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt32,
+     kMips64Lw,
+     kMips64Sw,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachFloat32,
+     kMips64Lwc1,
+     kMips64Swc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachFloat64,
+     kMips64Ldc1,
+     kMips64Sdc1,
+     &InstructionSelectorTest::Stream::IsDouble,
+     {-65000, -55000, 32777, 55000, 65000}},
+    {kMachInt64,
+     kMips64Ld,
+     kMips64Sd,
+     &InstructionSelectorTest::Stream::IsInteger,
+     {-65000, -55000, 32777, 55000, 65000}}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+
+// ----------------------------------------------------------------------------
+// Load immediate.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccessImm>
+    InstructionSelectorMemoryAccessImmTest;
+
+TEST_P(InstructionSelectorMemoryAccessImmTest, LoadWithImmediateIndex) {
+  const MemoryAccessImm memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// Store immediate.
+// ----------------------------------------------------------------------------
+
+
+TEST_P(InstructionSelectorMemoryAccessImmTest, StoreWithImmediateIndex) {
+  const MemoryAccessImm memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
+    EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
+    EXPECT_EQ(0U, s[0]->OutputCount());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessImmTest,
+                        ::testing::ValuesIn(kMemoryAccessesImm));
+
+
+// ----------------------------------------------------------------------------
+// Load/store offsets more than 16 bits.
+// ----------------------------------------------------------------------------
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccessImm1>
+    InstructionSelectorMemoryAccessImmMoreThan16bitTest;
+
+TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+       LoadWithImmediateIndex) {
+  const MemoryAccessImm1 memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, memacc.type, kMachPtr);
+    m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
+    Stream s = m.Build();
+    ASSERT_EQ(2U, s.size());
+    // kMips64Dadd is expected opcode
+    // size more than 16 bits wide
+    EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+TEST_P(InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+       StoreWithImmediateIndex) {
+  const MemoryAccessImm1 memacc = GetParam();
+  TRACED_FOREACH(int32_t, index, memacc.immediates) {
+    StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
+    m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
+            m.Parameter(1));
+    m.Return(m.Int32Constant(0));
+    Stream s = m.Build();
+    ASSERT_EQ(2U, s.size());
+    // kMips64Add is expected opcode
+    // size more than 16 bits wide
+    EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    EXPECT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessImmMoreThan16bitTest,
+                        ::testing::ValuesIn(kMemoryAccessImmMoreThan16bit));
+
+
+// ----------------------------------------------------------------------------
+// kMips64Cmp with zero testing.
+// ----------------------------------------------------------------------------
+
+
+TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMips64Cmp32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMips64Cmp32, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64EqualWithZero) {
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Equal(m.Parameter(0), m.Int64Constant(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+  {
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    m.Return(m.Word64Equal(m.Int32Constant(0), m.Parameter(0)));
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode());
+    EXPECT_EQ(kMode_None, s[0]->addressing_mode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(kFlags_set, s[0]->flags_mode());
+    EXPECT_EQ(kEqual, s[0]->flags_condition());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/move-optimizer-unittest.cc b/test/unittests/compiler/move-optimizer-unittest.cc
new file mode 100644
index 0000000..5b956f0
--- /dev/null
+++ b/test/unittests/compiler/move-optimizer-unittest.cc
@@ -0,0 +1,133 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/move-optimizer.h"
+#include "test/unittests/compiler/instruction-sequence-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class MoveOptimizerTest : public InstructionSequenceTest {
+ public:
+  GapInstruction* LastGap() {
+    auto instruction = sequence()->instructions().back();
+    if (!instruction->IsGapMoves()) {
+      instruction = *(sequence()->instructions().rbegin() + 1);
+    }
+    return GapInstruction::cast(instruction);
+  }
+
+  void AddMove(GapInstruction* gap, TestOperand from, TestOperand to,
+               GapInstruction::InnerPosition pos = GapInstruction::START) {
+    auto parallel_move = gap->GetOrCreateParallelMove(pos, zone());
+    parallel_move->AddMove(ConvertMoveArg(from), ConvertMoveArg(to), zone());
+  }
+
+  int NonRedundantSize(ParallelMove* move) {
+    int i = 0;
+    auto ops = move->move_operands();
+    for (auto op = ops->begin(); op != ops->end(); ++op) {
+      if (op->IsRedundant()) continue;
+      i++;
+    }
+    return i;
+  }
+
+  bool Contains(ParallelMove* move, TestOperand from_op, TestOperand to_op) {
+    auto from = ConvertMoveArg(from_op);
+    auto to = ConvertMoveArg(to_op);
+    auto ops = move->move_operands();
+    for (auto op = ops->begin(); op != ops->end(); ++op) {
+      if (op->IsRedundant()) continue;
+      if (op->source()->Equals(from) && op->destination()->Equals(to)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // TODO(dcarney): add a verifier.
+  void Optimize() {
+    WireBlocks();
+    if (FLAG_trace_turbo) {
+      OFStream os(stdout);
+      PrintableInstructionSequence printable = {config(), sequence()};
+      os << "----- Instruction sequence before move optimization -----\n"
+         << printable;
+    }
+    MoveOptimizer move_optimizer(zone(), sequence());
+    move_optimizer.Run();
+    if (FLAG_trace_turbo) {
+      OFStream os(stdout);
+      PrintableInstructionSequence printable = {config(), sequence()};
+      os << "----- Instruction sequence after move optimization -----\n"
+         << printable;
+    }
+  }
+
+ private:
+  InstructionOperand* ConvertMoveArg(TestOperand op) {
+    CHECK_EQ(kNoValue, op.vreg_.value_);
+    CHECK_NE(kNoValue, op.value_);
+    switch (op.type_) {
+      case kConstant:
+        return ConstantOperand::Create(op.value_, zone());
+      case kFixedSlot:
+        return StackSlotOperand::Create(op.value_, zone());
+      case kFixedRegister:
+        CHECK(0 <= op.value_ && op.value_ < num_general_registers());
+        return RegisterOperand::Create(op.value_, zone());
+      default:
+        break;
+    }
+    CHECK(false);
+    return nullptr;
+  }
+};
+
+
+TEST_F(MoveOptimizerTest, RemovesRedundant) {
+  StartBlock();
+  AddMove(LastGap(), Reg(0), Reg(1));
+  EmitNop();
+  AddMove(LastGap(), Reg(1), Reg(0));
+  EmitNop();
+  EndBlock(Last());
+
+  Optimize();
+
+  auto gap = LastGap();
+  auto move = gap->parallel_moves()[0];
+  CHECK_EQ(1, NonRedundantSize(move));
+  CHECK(Contains(move, Reg(0), Reg(1)));
+}
+
+
+TEST_F(MoveOptimizerTest, SplitsConstants) {
+  StartBlock();
+  EndBlock(Last());
+
+  auto gap = LastGap();
+  AddMove(gap, Const(1), Slot(0));
+  AddMove(gap, Const(1), Slot(1));
+  AddMove(gap, Const(1), Reg(0));
+  AddMove(gap, Const(1), Slot(2));
+
+  Optimize();
+
+  auto move = gap->parallel_moves()[0];
+  CHECK_EQ(1, NonRedundantSize(move));
+  CHECK(Contains(move, Const(1), Reg(0)));
+
+  move = gap->parallel_moves()[1];
+  CHECK_EQ(3, NonRedundantSize(move));
+  CHECK(Contains(move, Reg(0), Slot(0)));
+  CHECK(Contains(move, Reg(0), Slot(1)));
+  CHECK(Contains(move, Reg(0), Slot(2)));
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/node-matchers-unittest.cc b/test/unittests/compiler/node-matchers-unittest.cc
new file mode 100644
index 0000000..85db9db
--- /dev/null
+++ b/test/unittests/compiler/node-matchers-unittest.cc
@@ -0,0 +1,733 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/opcodes.h"
+
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class NodeMatcherTest : public GraphTest {
+ public:
+  NodeMatcherTest() : machine_(zone()) {}
+  ~NodeMatcherTest() OVERRIDE {}
+
+  MachineOperatorBuilder* machine() { return &machine_; }
+
+ private:
+  MachineOperatorBuilder machine_;
+};
+
+namespace {
+
+template <class Matcher>
+void CheckBaseWithIndexAndDisplacement(Matcher* matcher, Node* index, int scale,
+                                       Node* base, Node* displacement) {
+  EXPECT_TRUE(matcher->matches());
+  EXPECT_EQ(index, matcher->index());
+  EXPECT_EQ(scale, matcher->scale());
+  EXPECT_EQ(base, matcher->base());
+  EXPECT_EQ(displacement, matcher->displacement());
+}
+};
+
+
+TEST_F(NodeMatcherTest, ScaledWithOffset32Matcher) {
+  graph()->SetStart(graph()->NewNode(common()->Start(0)));
+
+  const Operator* d0_op = common()->Int32Constant(0);
+  Node* d0 = graph()->NewNode(d0_op);
+  USE(d0);
+  const Operator* d1_op = common()->Int32Constant(1);
+  Node* d1 = graph()->NewNode(d1_op);
+  USE(d1);
+  const Operator* d2_op = common()->Int32Constant(2);
+  Node* d2 = graph()->NewNode(d2_op);
+  USE(d2);
+  const Operator* d3_op = common()->Int32Constant(3);
+  Node* d3 = graph()->NewNode(d3_op);
+  USE(d3);
+  const Operator* d4_op = common()->Int32Constant(4);
+  Node* d4 = graph()->NewNode(d4_op);
+  USE(d4);
+  const Operator* d5_op = common()->Int32Constant(5);
+  Node* d5 = graph()->NewNode(d5_op);
+  USE(d5);
+  const Operator* d7_op = common()->Int32Constant(7);
+  Node* d7 = graph()->NewNode(d7_op);
+  USE(d4);
+  const Operator* d8_op = common()->Int32Constant(8);
+  Node* d8 = graph()->NewNode(d8_op);
+  USE(d8);
+  const Operator* d9_op = common()->Int32Constant(9);
+  Node* d9 = graph()->NewNode(d9_op);
+  USE(d9);
+  const Operator* d15_op = common()->Int32Constant(15);
+  Node* d15 = graph()->NewNode(d15_op);
+  USE(d15);
+
+  const Operator* b0_op = common()->Parameter(0);
+  Node* b0 = graph()->NewNode(b0_op, graph()->start());
+  USE(b0);
+  const Operator* b1_op = common()->Parameter(1);
+  Node* b1 = graph()->NewNode(b1_op, graph()->start());
+  USE(b0);
+
+  const Operator* p1_op = common()->Parameter(3);
+  Node* p1 = graph()->NewNode(p1_op, graph()->start());
+  USE(p1);
+
+  const Operator* a_op = machine()->Int32Add();
+  USE(a_op);
+
+  const Operator* m_op = machine()->Int32Mul();
+  Node* m1 = graph()->NewNode(m_op, p1, d1);
+  Node* m2 = graph()->NewNode(m_op, p1, d2);
+  Node* m3 = graph()->NewNode(m_op, p1, d3);
+  Node* m4 = graph()->NewNode(m_op, p1, d4);
+  Node* m5 = graph()->NewNode(m_op, p1, d5);
+  Node* m7 = graph()->NewNode(m_op, p1, d7);
+  Node* m8 = graph()->NewNode(m_op, p1, d8);
+  Node* m9 = graph()->NewNode(m_op, p1, d9);
+  USE(m1);
+  USE(m2);
+  USE(m3);
+  USE(m4);
+  USE(m5);
+  USE(m7);
+  USE(m8);
+  USE(m9);
+
+  const Operator* s_op = machine()->Word32Shl();
+  Node* s0 = graph()->NewNode(s_op, p1, d0);
+  Node* s1 = graph()->NewNode(s_op, p1, d1);
+  Node* s2 = graph()->NewNode(s_op, p1, d2);
+  Node* s3 = graph()->NewNode(s_op, p1, d3);
+  Node* s4 = graph()->NewNode(s_op, p1, d4);
+  USE(s0);
+  USE(s1);
+  USE(s2);
+  USE(s3);
+  USE(s4);
+
+  // 1 INPUT
+
+  // Only relevant test dases is Checking for non-match.
+  BaseWithIndexAndDisplacement32Matcher match0(d15);
+  EXPECT_FALSE(match0.matches());
+
+  // 2 INPUT
+
+  // (B0 + B1) -> [B0, 0, B1, NULL]
+  BaseWithIndexAndDisplacement32Matcher match1(graph()->NewNode(a_op, b0, b1));
+  CheckBaseWithIndexAndDisplacement(&match1, b1, 0, b0, NULL);
+
+  // (B0 + D15) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement32Matcher match2(graph()->NewNode(a_op, b0, d15));
+  CheckBaseWithIndexAndDisplacement(&match2, NULL, 0, b0, d15);
+
+  // (D15 + B0) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement32Matcher match3(graph()->NewNode(a_op, d15, b0));
+  CheckBaseWithIndexAndDisplacement(&match3, NULL, 0, b0, d15);
+
+  // (B0 + M1) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match4(graph()->NewNode(a_op, b0, m1));
+  CheckBaseWithIndexAndDisplacement(&match4, p1, 0, b0, NULL);
+
+  // (M1 + B0) -> [p1, 0, B0, NULL]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match5(graph()->NewNode(a_op, m1, b0));
+  CheckBaseWithIndexAndDisplacement(&match5, p1, 0, b0, NULL);
+
+  // (D15 + M1) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match6(graph()->NewNode(a_op, d15, m1));
+  CheckBaseWithIndexAndDisplacement(&match6, p1, 0, NULL, d15);
+
+  // (M1 + D15) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match7(graph()->NewNode(a_op, m1, d15));
+  CheckBaseWithIndexAndDisplacement(&match7, p1, 0, NULL, d15);
+
+  // (B0 + S0) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match8(graph()->NewNode(a_op, b0, s0));
+  CheckBaseWithIndexAndDisplacement(&match8, p1, 0, b0, NULL);
+
+  // (S0 + B0) -> [p1, 0, B0, NULL]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match9(graph()->NewNode(a_op, s0, b0));
+  CheckBaseWithIndexAndDisplacement(&match9, p1, 0, b0, NULL);
+
+  // (D15 + S0) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match10(
+      graph()->NewNode(a_op, d15, s0));
+  CheckBaseWithIndexAndDisplacement(&match10, p1, 0, NULL, d15);
+
+  // (S0 + D15) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match11(
+      graph()->NewNode(a_op, s0, d15));
+  CheckBaseWithIndexAndDisplacement(&match11, p1, 0, NULL, d15);
+
+  // (B0 + M2) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match12(graph()->NewNode(a_op, b0, m2));
+  CheckBaseWithIndexAndDisplacement(&match12, p1, 1, b0, NULL);
+
+  // (M2 + B0) -> [p1, 1, B0, NULL]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match13(graph()->NewNode(a_op, m2, b0));
+  CheckBaseWithIndexAndDisplacement(&match13, p1, 1, b0, NULL);
+
+  // (D15 + M2) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match14(
+      graph()->NewNode(a_op, d15, m2));
+  CheckBaseWithIndexAndDisplacement(&match14, p1, 1, NULL, d15);
+
+  // (M2 + D15) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match15(
+      graph()->NewNode(a_op, m2, d15));
+  CheckBaseWithIndexAndDisplacement(&match15, p1, 1, NULL, d15);
+
+  // (B0 + S1) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match16(graph()->NewNode(a_op, b0, s1));
+  CheckBaseWithIndexAndDisplacement(&match16, p1, 1, b0, NULL);
+
+  // (S1 + B0) -> [p1, 1, B0, NULL]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match17(graph()->NewNode(a_op, s1, b0));
+  CheckBaseWithIndexAndDisplacement(&match17, p1, 1, b0, NULL);
+
+  // (D15 + S1) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match18(
+      graph()->NewNode(a_op, d15, s1));
+  CheckBaseWithIndexAndDisplacement(&match18, p1, 1, NULL, d15);
+
+  // (S1 + D15) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match19(
+      graph()->NewNode(a_op, s1, d15));
+  CheckBaseWithIndexAndDisplacement(&match19, p1, 1, NULL, d15);
+
+  // (B0 + M4) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match20(graph()->NewNode(a_op, b0, m4));
+  CheckBaseWithIndexAndDisplacement(&match20, p1, 2, b0, NULL);
+
+  // (M4 + B0) -> [p1, 2, B0, NULL]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match21(graph()->NewNode(a_op, m4, b0));
+  CheckBaseWithIndexAndDisplacement(&match21, p1, 2, b0, NULL);
+
+  // (D15 + M4) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match22(
+      graph()->NewNode(a_op, d15, m4));
+  CheckBaseWithIndexAndDisplacement(&match22, p1, 2, NULL, d15);
+
+  // (M4 + D15) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match23(
+      graph()->NewNode(a_op, m4, d15));
+  CheckBaseWithIndexAndDisplacement(&match23, p1, 2, NULL, d15);
+
+  // (B0 + S2) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match24(graph()->NewNode(a_op, b0, s2));
+  CheckBaseWithIndexAndDisplacement(&match24, p1, 2, b0, NULL);
+
+  // (S2 + B0) -> [p1, 2, B0, NULL]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match25(graph()->NewNode(a_op, s2, b0));
+  CheckBaseWithIndexAndDisplacement(&match25, p1, 2, b0, NULL);
+
+  // (D15 + S2) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match26(
+      graph()->NewNode(a_op, d15, s2));
+  CheckBaseWithIndexAndDisplacement(&match26, p1, 2, NULL, d15);
+
+  // (S2 + D15) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match27(
+      graph()->NewNode(a_op, s2, d15));
+  CheckBaseWithIndexAndDisplacement(&match27, p1, 2, NULL, d15);
+
+  // (B0 + M8) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match28(graph()->NewNode(a_op, b0, m8));
+  CheckBaseWithIndexAndDisplacement(&match28, p1, 3, b0, NULL);
+
+  // (M8 + B0) -> [p1, 2, B0, NULL]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match29(graph()->NewNode(a_op, m8, b0));
+  CheckBaseWithIndexAndDisplacement(&match29, p1, 3, b0, NULL);
+
+  // (D15 + M8) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match30(
+      graph()->NewNode(a_op, d15, m8));
+  CheckBaseWithIndexAndDisplacement(&match30, p1, 3, NULL, d15);
+
+  // (M8 + D15) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match31(
+      graph()->NewNode(a_op, m8, d15));
+  CheckBaseWithIndexAndDisplacement(&match31, p1, 3, NULL, d15);
+
+  // (B0 + S3) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match32(graph()->NewNode(a_op, b0, s3));
+  CheckBaseWithIndexAndDisplacement(&match32, p1, 3, b0, NULL);
+
+  // (S3 + B0) -> [p1, 2, B0, NULL]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match33(graph()->NewNode(a_op, s3, b0));
+  CheckBaseWithIndexAndDisplacement(&match33, p1, 3, b0, NULL);
+
+  // (D15 + S3) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match34(
+      graph()->NewNode(a_op, d15, s3));
+  CheckBaseWithIndexAndDisplacement(&match34, p1, 3, NULL, d15);
+
+  // (S3 + D15) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match35(
+      graph()->NewNode(a_op, s3, d15));
+  CheckBaseWithIndexAndDisplacement(&match35, p1, 3, NULL, d15);
+
+  // 2 INPUT - NEGATIVE CASES
+
+  // (M3 + B1) -> [B0, 0, M3, NULL]
+  BaseWithIndexAndDisplacement32Matcher match36(graph()->NewNode(a_op, b1, m3));
+  CheckBaseWithIndexAndDisplacement(&match36, m3, 0, b1, NULL);
+
+  // (S4 + B1) -> [B0, 0, S4, NULL]
+  BaseWithIndexAndDisplacement32Matcher match37(graph()->NewNode(a_op, b1, s4));
+  CheckBaseWithIndexAndDisplacement(&match37, s4, 0, b1, NULL);
+
+  // 3 INPUT
+
+  // (D15 + S3) + B0 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match38(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, d15, s3), b0));
+  CheckBaseWithIndexAndDisplacement(&match38, p1, 3, b0, d15);
+
+  // (B0 + D15) + S3 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match39(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, b0, d15), s3));
+  CheckBaseWithIndexAndDisplacement(&match39, p1, 3, b0, d15);
+
+  // (S3 + B0) + D15 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match40(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, s3, b0), d15));
+  CheckBaseWithIndexAndDisplacement(&match40, p1, 3, b0, d15);
+
+  // D15 + (S3 + B0) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match41(
+      graph()->NewNode(a_op, d15, graph()->NewNode(a_op, s3, b0)));
+  CheckBaseWithIndexAndDisplacement(&match41, p1, 3, b0, d15);
+
+  // B0 + (D15 + S3) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match42(
+      graph()->NewNode(a_op, b0, graph()->NewNode(a_op, d15, s3)));
+  CheckBaseWithIndexAndDisplacement(&match42, p1, 3, b0, d15);
+
+  // S3 + (B0 + D15) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match43(
+      graph()->NewNode(a_op, s3, graph()->NewNode(a_op, b0, d15)));
+  CheckBaseWithIndexAndDisplacement(&match43, p1, 3, b0, d15);
+
+  // Check that scales that require using the base address work dorrectly.
+}
+
+
+TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) {
+  graph()->SetStart(graph()->NewNode(common()->Start(0)));
+
+  const Operator* d0_op = common()->Int64Constant(0);
+  Node* d0 = graph()->NewNode(d0_op);
+  USE(d0);
+  const Operator* d1_op = common()->Int64Constant(1);
+  Node* d1 = graph()->NewNode(d1_op);
+  USE(d1);
+  const Operator* d2_op = common()->Int64Constant(2);
+  Node* d2 = graph()->NewNode(d2_op);
+  USE(d2);
+  const Operator* d3_op = common()->Int64Constant(3);
+  Node* d3 = graph()->NewNode(d3_op);
+  USE(d3);
+  const Operator* d4_op = common()->Int64Constant(4);
+  Node* d4 = graph()->NewNode(d4_op);
+  USE(d4);
+  const Operator* d5_op = common()->Int64Constant(5);
+  Node* d5 = graph()->NewNode(d5_op);
+  USE(d5);
+  const Operator* d7_op = common()->Int64Constant(7);
+  Node* d7 = graph()->NewNode(d7_op);
+  USE(d7);
+  const Operator* d8_op = common()->Int64Constant(8);
+  Node* d8 = graph()->NewNode(d8_op);
+  USE(d8);
+  const Operator* d9_op = common()->Int64Constant(9);
+  Node* d9 = graph()->NewNode(d9_op);
+  USE(d8);
+  const Operator* d15_op = common()->Int64Constant(15);
+  Node* d15 = graph()->NewNode(d15_op);
+  USE(d15);
+  const Operator* d15_32_op = common()->Int32Constant(15);
+  Node* d15_32 = graph()->NewNode(d15_32_op);
+  USE(d15_32);
+
+  const Operator* b0_op = common()->Parameter(0);
+  Node* b0 = graph()->NewNode(b0_op, graph()->start());
+  USE(b0);
+  const Operator* b1_op = common()->Parameter(1);
+  Node* b1 = graph()->NewNode(b1_op, graph()->start());
+  USE(b0);
+
+  const Operator* p1_op = common()->Parameter(3);
+  Node* p1 = graph()->NewNode(p1_op, graph()->start());
+  USE(p1);
+
+  const Operator* a_op = machine()->Int64Add();
+  USE(a_op);
+
+  const Operator* m_op = machine()->Int64Mul();
+  Node* m1 = graph()->NewNode(m_op, p1, d1);
+  Node* m2 = graph()->NewNode(m_op, p1, d2);
+  Node* m3 = graph()->NewNode(m_op, p1, d3);
+  Node* m4 = graph()->NewNode(m_op, p1, d4);
+  Node* m5 = graph()->NewNode(m_op, p1, d5);
+  Node* m7 = graph()->NewNode(m_op, p1, d7);
+  Node* m8 = graph()->NewNode(m_op, p1, d8);
+  Node* m9 = graph()->NewNode(m_op, p1, d9);
+  USE(m1);
+  USE(m2);
+  USE(m3);
+  USE(m4);
+  USE(m5);
+  USE(m7);
+  USE(m8);
+  USE(m9);
+
+  const Operator* s_op = machine()->Word64Shl();
+  Node* s0 = graph()->NewNode(s_op, p1, d0);
+  Node* s1 = graph()->NewNode(s_op, p1, d1);
+  Node* s2 = graph()->NewNode(s_op, p1, d2);
+  Node* s3 = graph()->NewNode(s_op, p1, d3);
+  Node* s4 = graph()->NewNode(s_op, p1, d4);
+  USE(s0);
+  USE(s1);
+  USE(s2);
+  USE(s3);
+  USE(s4);
+
+  // 1 INPUT
+
+  // Only relevant test dases is Checking for non-match.
+  BaseWithIndexAndDisplacement64Matcher match0(d15);
+  EXPECT_FALSE(match0.matches());
+
+  // 2 INPUT
+
+  // (B0 + B1) -> [B0, 0, B1, NULL]
+  BaseWithIndexAndDisplacement64Matcher match1(graph()->NewNode(a_op, b0, b1));
+  CheckBaseWithIndexAndDisplacement(&match1, b1, 0, b0, NULL);
+
+  // (B0 + D15) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement64Matcher match2(graph()->NewNode(a_op, b0, d15));
+  CheckBaseWithIndexAndDisplacement(&match2, NULL, 0, b0, d15);
+
+  BaseWithIndexAndDisplacement64Matcher match2_32(
+      graph()->NewNode(a_op, b0, d15_32));
+  CheckBaseWithIndexAndDisplacement(&match2_32, NULL, 0, b0, d15_32);
+
+  // (D15 + B0) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement64Matcher match3(graph()->NewNode(a_op, d15, b0));
+  CheckBaseWithIndexAndDisplacement(&match3, NULL, 0, b0, d15);
+
+  // (B0 + M1) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match4(graph()->NewNode(a_op, b0, m1));
+  CheckBaseWithIndexAndDisplacement(&match4, p1, 0, b0, NULL);
+
+  // (M1 + B0) -> [p1, 0, B0, NULL]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match5(graph()->NewNode(a_op, m1, b0));
+  CheckBaseWithIndexAndDisplacement(&match5, p1, 0, b0, NULL);
+
+  // (D15 + M1) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match6(graph()->NewNode(a_op, d15, m1));
+  CheckBaseWithIndexAndDisplacement(&match6, p1, 0, NULL, d15);
+
+  // (M1 + D15) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match7(graph()->NewNode(a_op, m1, d15));
+  CheckBaseWithIndexAndDisplacement(&match7, p1, 0, NULL, d15);
+
+  // (B0 + S0) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match8(graph()->NewNode(a_op, b0, s0));
+  CheckBaseWithIndexAndDisplacement(&match8, p1, 0, b0, NULL);
+
+  // (S0 + B0) -> [p1, 0, B0, NULL]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match9(graph()->NewNode(a_op, s0, b0));
+  CheckBaseWithIndexAndDisplacement(&match9, p1, 0, b0, NULL);
+
+  // (D15 + S0) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match10(
+      graph()->NewNode(a_op, d15, s0));
+  CheckBaseWithIndexAndDisplacement(&match10, p1, 0, NULL, d15);
+
+  // (S0 + D15) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match11(
+      graph()->NewNode(a_op, s0, d15));
+  CheckBaseWithIndexAndDisplacement(&match11, p1, 0, NULL, d15);
+
+  // (B0 + M2) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match12(graph()->NewNode(a_op, b0, m2));
+  CheckBaseWithIndexAndDisplacement(&match12, p1, 1, b0, NULL);
+
+  // (M2 + B0) -> [p1, 1, B0, NULL]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match13(graph()->NewNode(a_op, m2, b0));
+  CheckBaseWithIndexAndDisplacement(&match13, p1, 1, b0, NULL);
+
+  // (D15 + M2) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match14(
+      graph()->NewNode(a_op, d15, m2));
+  CheckBaseWithIndexAndDisplacement(&match14, p1, 1, NULL, d15);
+
+  // (M2 + D15) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match15(
+      graph()->NewNode(a_op, m2, d15));
+  CheckBaseWithIndexAndDisplacement(&match15, p1, 1, NULL, d15);
+
+  // (B0 + S1) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match16(graph()->NewNode(a_op, b0, s1));
+  CheckBaseWithIndexAndDisplacement(&match16, p1, 1, b0, NULL);
+
+  // (S1 + B0) -> [p1, 1, B0, NULL]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match17(graph()->NewNode(a_op, s1, b0));
+  CheckBaseWithIndexAndDisplacement(&match17, p1, 1, b0, NULL);
+
+  // (D15 + S1) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match18(
+      graph()->NewNode(a_op, d15, s1));
+  CheckBaseWithIndexAndDisplacement(&match18, p1, 1, NULL, d15);
+
+  // (S1 + D15) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match19(
+      graph()->NewNode(a_op, s1, d15));
+  CheckBaseWithIndexAndDisplacement(&match19, p1, 1, NULL, d15);
+
+  // (B0 + M4) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match20(graph()->NewNode(a_op, b0, m4));
+  CheckBaseWithIndexAndDisplacement(&match20, p1, 2, b0, NULL);
+
+  // (M4 + B0) -> [p1, 2, B0, NULL]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match21(graph()->NewNode(a_op, m4, b0));
+  CheckBaseWithIndexAndDisplacement(&match21, p1, 2, b0, NULL);
+
+  // (D15 + M4) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match22(
+      graph()->NewNode(a_op, d15, m4));
+  CheckBaseWithIndexAndDisplacement(&match22, p1, 2, NULL, d15);
+
+  // (M4 + D15) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match23(
+      graph()->NewNode(a_op, m4, d15));
+  CheckBaseWithIndexAndDisplacement(&match23, p1, 2, NULL, d15);
+
+  // (B0 + S2) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match24(graph()->NewNode(a_op, b0, s2));
+  CheckBaseWithIndexAndDisplacement(&match24, p1, 2, b0, NULL);
+
+  // (S2 + B0) -> [p1, 2, B0, NULL]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match25(graph()->NewNode(a_op, s2, b0));
+  CheckBaseWithIndexAndDisplacement(&match25, p1, 2, b0, NULL);
+
+  // (D15 + S2) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match26(
+      graph()->NewNode(a_op, d15, s2));
+  CheckBaseWithIndexAndDisplacement(&match26, p1, 2, NULL, d15);
+
+  // (S2 + D15) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match27(
+      graph()->NewNode(a_op, s2, d15));
+  CheckBaseWithIndexAndDisplacement(&match27, p1, 2, NULL, d15);
+
+  // (B0 + M8) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match28(graph()->NewNode(a_op, b0, m8));
+  CheckBaseWithIndexAndDisplacement(&match28, p1, 3, b0, NULL);
+
+  // (M8 + B0) -> [p1, 2, B0, NULL]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match29(graph()->NewNode(a_op, m8, b0));
+  CheckBaseWithIndexAndDisplacement(&match29, p1, 3, b0, NULL);
+
+  // (D15 + M8) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match30(
+      graph()->NewNode(a_op, d15, m8));
+  CheckBaseWithIndexAndDisplacement(&match30, p1, 3, NULL, d15);
+
+  // (M8 + D15) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match31(
+      graph()->NewNode(a_op, m8, d15));
+  CheckBaseWithIndexAndDisplacement(&match31, p1, 3, NULL, d15);
+
+  // (B0 + S3) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match64(graph()->NewNode(a_op, b0, s3));
+  CheckBaseWithIndexAndDisplacement(&match64, p1, 3, b0, NULL);
+
+  // (S3 + B0) -> [p1, 2, B0, NULL]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match33(graph()->NewNode(a_op, s3, b0));
+  CheckBaseWithIndexAndDisplacement(&match33, p1, 3, b0, NULL);
+
+  // (D15 + S3) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match34(
+      graph()->NewNode(a_op, d15, s3));
+  CheckBaseWithIndexAndDisplacement(&match34, p1, 3, NULL, d15);
+
+  // (S3 + D15) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match35(
+      graph()->NewNode(a_op, s3, d15));
+  CheckBaseWithIndexAndDisplacement(&match35, p1, 3, NULL, d15);
+
+  // 2 INPUT - NEGATIVE CASES
+
+  // (M3 + B1) -> [B0, 0, M3, NULL]
+  BaseWithIndexAndDisplacement64Matcher match36(graph()->NewNode(a_op, b1, m3));
+  CheckBaseWithIndexAndDisplacement(&match36, m3, 0, b1, NULL);
+
+  // (S4 + B1) -> [B0, 0, S4, NULL]
+  BaseWithIndexAndDisplacement64Matcher match37(graph()->NewNode(a_op, b1, s4));
+  CheckBaseWithIndexAndDisplacement(&match37, s4, 0, b1, NULL);
+
+  // 3 INPUT
+
+  // (D15 + S3) + B0 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match38(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, d15, s3), b0));
+  CheckBaseWithIndexAndDisplacement(&match38, p1, 3, b0, d15);
+
+  // (B0 + D15) + S3 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match39(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, b0, d15), s3));
+  CheckBaseWithIndexAndDisplacement(&match39, p1, 3, b0, d15);
+
+  // (S3 + B0) + D15 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match40(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, s3, b0), d15));
+  CheckBaseWithIndexAndDisplacement(&match40, p1, 3, b0, d15);
+
+  // D15 + (S3 + B0) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match41(
+      graph()->NewNode(a_op, d15, graph()->NewNode(a_op, s3, b0)));
+  CheckBaseWithIndexAndDisplacement(&match41, p1, 3, b0, d15);
+
+  // B0 + (D15 + S3) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match42(
+      graph()->NewNode(a_op, b0, graph()->NewNode(a_op, d15, s3)));
+  CheckBaseWithIndexAndDisplacement(&match42, p1, 3, b0, d15);
+
+  // S3 + (B0 + D15) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match43(
+      graph()->NewNode(a_op, s3, graph()->NewNode(a_op, b0, d15)));
+  CheckBaseWithIndexAndDisplacement(&match43, p1, 3, b0, d15);
+
+  // 2 INPUT with non-power of 2 scale
+
+  // (M3 + D15) -> [p1, 1, p1, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match44(
+      graph()->NewNode(a_op, m3, d15));
+  CheckBaseWithIndexAndDisplacement(&match44, p1, 1, p1, d15);
+
+  // (M5 + D15) -> [p1, 2, p1, D15]
+  m5 = graph()->NewNode(m_op, p1, d5);
+  BaseWithIndexAndDisplacement64Matcher match45(
+      graph()->NewNode(a_op, m5, d15));
+  CheckBaseWithIndexAndDisplacement(&match45, p1, 2, p1, d15);
+
+  // (M9 + D15) -> [p1, 3, p1, D15]
+  m9 = graph()->NewNode(m_op, p1, d9);
+  BaseWithIndexAndDisplacement64Matcher match46(
+      graph()->NewNode(a_op, m9, d15));
+  CheckBaseWithIndexAndDisplacement(&match46, p1, 3, p1, d15);
+
+  // 3 INPUT negative cases: non-power of 2 scale but with a base
+
+  // ((M3 + B0) + D15) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  Node* temp = graph()->NewNode(a_op, m3, b0);
+  BaseWithIndexAndDisplacement64Matcher match47(
+      graph()->NewNode(a_op, temp, d15));
+  CheckBaseWithIndexAndDisplacement(&match47, m3, 0, b0, d15);
+
+  // (M3 + (B0 + D15)) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, d15, b0);
+  BaseWithIndexAndDisplacement64Matcher match48(
+      graph()->NewNode(a_op, m3, temp));
+  CheckBaseWithIndexAndDisplacement(&match48, m3, 0, b0, d15);
+
+  // ((B0 + M3) + D15) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, b0, m3);
+  BaseWithIndexAndDisplacement64Matcher match49(
+      graph()->NewNode(a_op, temp, d15));
+  CheckBaseWithIndexAndDisplacement(&match49, m3, 0, b0, d15);
+
+  // (M3 + (D15 + B0)) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, b0, d15);
+  BaseWithIndexAndDisplacement64Matcher match50(
+      graph()->NewNode(a_op, m3, temp));
+  CheckBaseWithIndexAndDisplacement(&match50, m3, 0, b0, d15);
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/node-test-utils.cc b/test/unittests/compiler/node-test-utils.cc
new file mode 100644
index 0000000..74afda9
--- /dev/null
+++ b/test/unittests/compiler/node-test-utils.cc
@@ -0,0 +1,1315 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/node-test-utils.h"
+
+#include "src/assembler.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
+
+using testing::_;
+using testing::MakeMatcher;
+using testing::MatcherInterface;
+using testing::MatchResultListener;
+using testing::StringMatchResultListener;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+template <typename T>
+bool PrintMatchAndExplain(const T& value, const char* value_name,
+                          const Matcher<T>& value_matcher,
+                          MatchResultListener* listener) {
+  StringMatchResultListener value_listener;
+  if (!value_matcher.MatchAndExplain(value, &value_listener)) {
+    *listener << "whose " << value_name << " " << value << " doesn't match";
+    if (value_listener.str() != "") {
+      *listener << ", " << value_listener.str();
+    }
+    return false;
+  }
+  return true;
+}
+
+
+class NodeMatcher : public MatcherInterface<Node*> {
+ public:
+  explicit NodeMatcher(IrOpcode::Value opcode) : opcode_(opcode) {}
+
+  void DescribeTo(std::ostream* os) const OVERRIDE {
+    *os << "is a " << IrOpcode::Mnemonic(opcode_) << " node";
+  }
+
+  bool MatchAndExplain(Node* node,
+                       MatchResultListener* listener) const OVERRIDE {
+    if (node == NULL) {
+      *listener << "which is NULL";
+      return false;
+    }
+    if (node->opcode() != opcode_) {
+      *listener << "whose opcode is " << IrOpcode::Mnemonic(node->opcode())
+                << " but should have been " << IrOpcode::Mnemonic(opcode_);
+      return false;
+    }
+    return true;
+  }
+
+ private:
+  const IrOpcode::Value opcode_;
+};
+
+
+class IsBranchMatcher FINAL : public NodeMatcher {
+ public:
+  IsBranchMatcher(const Matcher<Node*>& value_matcher,
+                  const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kBranch),
+        value_matcher_(value_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value (";
+    value_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsMergeMatcher FINAL : public NodeMatcher {
+ public:
+  IsMergeMatcher(const Matcher<Node*>& control0_matcher,
+                 const Matcher<Node*>& control1_matcher)
+      : NodeMatcher(IrOpcode::kMerge),
+        control0_matcher_(control0_matcher),
+        control1_matcher_(control1_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose control0 (";
+    control0_matcher_.DescribeTo(os);
+    *os << ") and control1 (";
+    control1_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node, 0),
+                                 "control0", control0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node, 1),
+                                 "control1", control1_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> control0_matcher_;
+  const Matcher<Node*> control1_matcher_;
+};
+
+
+class IsControl1Matcher FINAL : public NodeMatcher {
+ public:
+  IsControl1Matcher(IrOpcode::Value opcode,
+                    const Matcher<Node*>& control_matcher)
+      : NodeMatcher(opcode), control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsFinishMatcher FINAL : public NodeMatcher {
+ public:
+  IsFinishMatcher(const Matcher<Node*>& value_matcher,
+                  const Matcher<Node*>& effect_matcher)
+      : NodeMatcher(IrOpcode::kFinish),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value (";
+    value_matcher_.DescribeTo(os);
+    *os << ") and effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+};
+
+
+template <typename T>
+class IsConstantMatcher FINAL : public NodeMatcher {
+ public:
+  IsConstantMatcher(IrOpcode::Value opcode, const Matcher<T>& value_matcher)
+      : NodeMatcher(opcode), value_matcher_(value_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value (";
+    value_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<T>(node), "value", value_matcher_,
+                                 listener));
+  }
+
+ private:
+  const Matcher<T> value_matcher_;
+};
+
+
+class IsSelectMatcher FINAL : public NodeMatcher {
+ public:
+  IsSelectMatcher(const Matcher<MachineType>& type_matcher,
+                  const Matcher<Node*>& value0_matcher,
+                  const Matcher<Node*>& value1_matcher,
+                  const Matcher<Node*>& value2_matcher)
+      : NodeMatcher(IrOpcode::kSelect),
+        type_matcher_(type_matcher),
+        value0_matcher_(value0_matcher),
+        value1_matcher_(value1_matcher),
+        value2_matcher_(value2_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose type (";
+    type_matcher_.DescribeTo(os);
+    *os << "), value0 (";
+    value0_matcher_.DescribeTo(os);
+    *os << "), value1 (";
+    value1_matcher_.DescribeTo(os);
+    *os << ") and value2 (";
+    value2_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<MachineType>(node), "type",
+                                 type_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value0", value0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value1", value1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value2", value2_matcher_, listener));
+  }
+
+ private:
+  const Matcher<MachineType> type_matcher_;
+  const Matcher<Node*> value0_matcher_;
+  const Matcher<Node*> value1_matcher_;
+  const Matcher<Node*> value2_matcher_;
+};
+
+
+class IsPhiMatcher FINAL : public NodeMatcher {
+ public:
+  IsPhiMatcher(const Matcher<MachineType>& type_matcher,
+               const Matcher<Node*>& value0_matcher,
+               const Matcher<Node*>& value1_matcher,
+               const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kPhi),
+        type_matcher_(type_matcher),
+        value0_matcher_(value0_matcher),
+        value1_matcher_(value1_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose type (";
+    type_matcher_.DescribeTo(os);
+    *os << "), value0 (";
+    value0_matcher_.DescribeTo(os);
+    *os << "), value1 (";
+    value1_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<MachineType>(node), "type",
+                                 type_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value0", value0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value1", value1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<MachineType> type_matcher_;
+  const Matcher<Node*> value0_matcher_;
+  const Matcher<Node*> value1_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsEffectPhiMatcher FINAL : public NodeMatcher {
+ public:
+  IsEffectPhiMatcher(const Matcher<Node*>& effect0_matcher,
+                     const Matcher<Node*>& effect1_matcher,
+                     const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kEffectPhi),
+        effect0_matcher_(effect0_matcher),
+        effect1_matcher_(effect1_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << "), effect0 (";
+    effect0_matcher_.DescribeTo(os);
+    *os << "), effect1 (";
+    effect1_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node, 0),
+                                 "effect0", effect0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node, 1),
+                                 "effect1", effect1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> effect0_matcher_;
+  const Matcher<Node*> effect1_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsProjectionMatcher FINAL : public NodeMatcher {
+ public:
+  IsProjectionMatcher(const Matcher<size_t>& index_matcher,
+                      const Matcher<Node*>& base_matcher)
+      : NodeMatcher(IrOpcode::kProjection),
+        index_matcher_(index_matcher),
+        base_matcher_(base_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose index (";
+    index_matcher_.DescribeTo(os);
+    *os << ") and base (";
+    base_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<size_t>(node), "index",
+                                 index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener));
+  }
+
+ private:
+  const Matcher<size_t> index_matcher_;
+  const Matcher<Node*> base_matcher_;
+};
+
+
+class IsCall2Matcher FINAL : public NodeMatcher {
+ public:
+  IsCall2Matcher(const Matcher<CallDescriptor*>& descriptor_matcher,
+                 const Matcher<Node*>& value0_matcher,
+                 const Matcher<Node*>& value1_matcher,
+                 const Matcher<Node*>& effect_matcher,
+                 const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kCall),
+        descriptor_matcher_(descriptor_matcher),
+        value0_matcher_(value0_matcher),
+        value1_matcher_(value1_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value0 (";
+    value0_matcher_.DescribeTo(os);
+    *os << ") and value1 (";
+    value1_matcher_.DescribeTo(os);
+    *os << ") and effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<CallDescriptor*>(node),
+                                 "descriptor", descriptor_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value0", value0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value1", value1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<CallDescriptor*> descriptor_matcher_;
+  const Matcher<Node*> value0_matcher_;
+  const Matcher<Node*> value1_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsCall4Matcher FINAL : public NodeMatcher {
+ public:
+  IsCall4Matcher(const Matcher<CallDescriptor*>& descriptor_matcher,
+                 const Matcher<Node*>& value0_matcher,
+                 const Matcher<Node*>& value1_matcher,
+                 const Matcher<Node*>& value2_matcher,
+                 const Matcher<Node*>& value3_matcher,
+                 const Matcher<Node*>& effect_matcher,
+                 const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kCall),
+        descriptor_matcher_(descriptor_matcher),
+        value0_matcher_(value0_matcher),
+        value1_matcher_(value1_matcher),
+        value2_matcher_(value2_matcher),
+        value3_matcher_(value3_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose value0 (";
+    value0_matcher_.DescribeTo(os);
+    *os << ") and value1 (";
+    value1_matcher_.DescribeTo(os);
+    *os << ") and value2 (";
+    value2_matcher_.DescribeTo(os);
+    *os << ") and value3 (";
+    value3_matcher_.DescribeTo(os);
+    *os << ") and effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<CallDescriptor*>(node),
+                                 "descriptor", descriptor_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "value0", value0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value1", value1_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value2", value2_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3),
+                                 "value3", value3_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<CallDescriptor*> descriptor_matcher_;
+  const Matcher<Node*> value0_matcher_;
+  const Matcher<Node*> value1_matcher_;
+  const Matcher<Node*> value2_matcher_;
+  const Matcher<Node*> value3_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsLoadFieldMatcher FINAL : public NodeMatcher {
+ public:
+  IsLoadFieldMatcher(const Matcher<FieldAccess>& access_matcher,
+                     const Matcher<Node*>& base_matcher,
+                     const Matcher<Node*>& effect_matcher,
+                     const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kLoadField),
+        access_matcher_(access_matcher),
+        base_matcher_(base_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<FieldAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<FieldAccess> access_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreFieldMatcher FINAL : public NodeMatcher {
+ public:
+  IsStoreFieldMatcher(const Matcher<FieldAccess>& access_matcher,
+                      const Matcher<Node*>& base_matcher,
+                      const Matcher<Node*>& value_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStoreField),
+        access_matcher_(access_matcher),
+        base_matcher_(base_matcher),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<FieldAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<FieldAccess> access_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsLoadBufferMatcher FINAL : public NodeMatcher {
+ public:
+  IsLoadBufferMatcher(const Matcher<BufferAccess>& access_matcher,
+                      const Matcher<Node*>& buffer_matcher,
+                      const Matcher<Node*>& offset_matcher,
+                      const Matcher<Node*>& length_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kLoadBuffer),
+        access_matcher_(access_matcher),
+        buffer_matcher_(buffer_matcher),
+        offset_matcher_(offset_matcher),
+        length_matcher_(length_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), buffer (";
+    buffer_matcher_.DescribeTo(os);
+    *os << "), offset (";
+    offset_matcher_.DescribeTo(os);
+    *os << "), length (";
+    length_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(BufferAccessOf(node->op()), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "buffer", buffer_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "offset", offset_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "length", length_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<BufferAccess> access_matcher_;
+  const Matcher<Node*> buffer_matcher_;
+  const Matcher<Node*> offset_matcher_;
+  const Matcher<Node*> length_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreBufferMatcher FINAL : public NodeMatcher {
+ public:
+  IsStoreBufferMatcher(const Matcher<BufferAccess>& access_matcher,
+                       const Matcher<Node*>& buffer_matcher,
+                       const Matcher<Node*>& offset_matcher,
+                       const Matcher<Node*>& length_matcher,
+                       const Matcher<Node*>& value_matcher,
+                       const Matcher<Node*>& effect_matcher,
+                       const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStoreBuffer),
+        access_matcher_(access_matcher),
+        buffer_matcher_(buffer_matcher),
+        offset_matcher_(offset_matcher),
+        length_matcher_(length_matcher),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), buffer (";
+    buffer_matcher_.DescribeTo(os);
+    *os << "), offset (";
+    offset_matcher_.DescribeTo(os);
+    *os << "), length (";
+    length_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(BufferAccessOf(node->op()), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "buffer", buffer_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "offset", offset_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "length", length_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<BufferAccess> access_matcher_;
+  const Matcher<Node*> buffer_matcher_;
+  const Matcher<Node*> offset_matcher_;
+  const Matcher<Node*> length_matcher_;
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsLoadElementMatcher FINAL : public NodeMatcher {
+ public:
+  IsLoadElementMatcher(const Matcher<ElementAccess>& access_matcher,
+                       const Matcher<Node*>& base_matcher,
+                       const Matcher<Node*>& index_matcher,
+                       const Matcher<Node*>& effect_matcher,
+                       const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kLoadElement),
+        access_matcher_(access_matcher),
+        base_matcher_(base_matcher),
+        index_matcher_(index_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<ElementAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<ElementAccess> access_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreElementMatcher FINAL : public NodeMatcher {
+ public:
+  IsStoreElementMatcher(const Matcher<ElementAccess>& access_matcher,
+                        const Matcher<Node*>& base_matcher,
+                        const Matcher<Node*>& index_matcher,
+                        const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& effect_matcher,
+                        const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStoreElement),
+        access_matcher_(access_matcher),
+        base_matcher_(base_matcher),
+        index_matcher_(index_matcher),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose access (";
+    access_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<ElementAccess>(node), "access",
+                                 access_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<ElementAccess> access_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsLoadMatcher FINAL : public NodeMatcher {
+ public:
+  IsLoadMatcher(const Matcher<LoadRepresentation>& rep_matcher,
+                const Matcher<Node*>& base_matcher,
+                const Matcher<Node*>& index_matcher,
+                const Matcher<Node*>& effect_matcher,
+                const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kLoad),
+        rep_matcher_(rep_matcher),
+        base_matcher_(base_matcher),
+        index_matcher_(index_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose rep (";
+    rep_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<LoadRepresentation>(node), "rep",
+                                 rep_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<LoadRepresentation> rep_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsToNumberMatcher FINAL : public NodeMatcher {
+ public:
+  IsToNumberMatcher(const Matcher<Node*>& base_matcher,
+                    const Matcher<Node*>& context_matcher,
+                    const Matcher<Node*>& effect_matcher,
+                    const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kJSToNumber),
+        base_matcher_(base_matcher),
+        context_matcher_(context_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), context (";
+    context_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetContextInput(node),
+                                 "context", context_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> context_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsStoreMatcher FINAL : public NodeMatcher {
+ public:
+  IsStoreMatcher(const Matcher<StoreRepresentation>& rep_matcher,
+                 const Matcher<Node*>& base_matcher,
+                 const Matcher<Node*>& index_matcher,
+                 const Matcher<Node*>& value_matcher,
+                 const Matcher<Node*>& effect_matcher,
+                 const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kStore),
+        rep_matcher_(rep_matcher),
+        base_matcher_(base_matcher),
+        index_matcher_(index_matcher),
+        value_matcher_(value_matcher),
+        effect_matcher_(effect_matcher),
+        control_matcher_(control_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose rep (";
+    rep_matcher_.DescribeTo(os);
+    *os << "), base (";
+    base_matcher_.DescribeTo(os);
+    *os << "), index (";
+    index_matcher_.DescribeTo(os);
+    *os << "), value (";
+    value_matcher_.DescribeTo(os);
+    *os << "), effect (";
+    effect_matcher_.DescribeTo(os);
+    *os << ") and control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(OpParameter<StoreRepresentation>(node), "rep",
+                                 rep_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
+                                 base_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+                                 "index", index_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+                                 "value", value_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+                                 effect_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<StoreRepresentation> rep_matcher_;
+  const Matcher<Node*> base_matcher_;
+  const Matcher<Node*> index_matcher_;
+  const Matcher<Node*> value_matcher_;
+  const Matcher<Node*> effect_matcher_;
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsBinopMatcher FINAL : public NodeMatcher {
+ public:
+  IsBinopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher,
+                 const Matcher<Node*>& rhs_matcher)
+      : NodeMatcher(opcode),
+        lhs_matcher_(lhs_matcher),
+        rhs_matcher_(rhs_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose lhs (";
+    lhs_matcher_.DescribeTo(os);
+    *os << ") and rhs (";
+    rhs_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs",
+                                 lhs_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs",
+                                 rhs_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> lhs_matcher_;
+  const Matcher<Node*> rhs_matcher_;
+};
+
+
+class IsUnopMatcher FINAL : public NodeMatcher {
+ public:
+  IsUnopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& input_matcher)
+      : NodeMatcher(opcode), input_matcher_(input_matcher) {}
+
+  void DescribeTo(std::ostream* os) const FINAL {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose input (";
+    input_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+                                 "input", input_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> input_matcher_;
+};
+}
+
+
+Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsBranchMatcher(value_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
+                       const Matcher<Node*>& control1_matcher) {
+  return MakeMatcher(new IsMergeMatcher(control0_matcher, control1_matcher));
+}
+
+
+Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsControl1Matcher(IrOpcode::kIfTrue, control_matcher));
+}
+
+
+Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(
+      new IsControl1Matcher(IrOpcode::kIfFalse, control_matcher));
+}
+
+
+Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher) {
+  return MakeMatcher(new IsUnopMatcher(IrOpcode::kValueEffect, value_matcher));
+}
+
+
+Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& effect_matcher) {
+  return MakeMatcher(new IsFinishMatcher(value_matcher, effect_matcher));
+}
+
+
+Matcher<Node*> IsExternalConstant(
+    const Matcher<ExternalReference>& value_matcher) {
+  return MakeMatcher(new IsConstantMatcher<ExternalReference>(
+      IrOpcode::kExternalConstant, value_matcher));
+}
+
+
+Matcher<Node*> IsHeapConstant(
+    const Matcher<Unique<HeapObject> >& value_matcher) {
+  return MakeMatcher(new IsConstantMatcher<Unique<HeapObject> >(
+      IrOpcode::kHeapConstant, value_matcher));
+}
+
+
+Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<int32_t>(IrOpcode::kInt32Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<int64_t>(IrOpcode::kInt64Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsFloat32Constant(const Matcher<float>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<float>(IrOpcode::kFloat32Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<double>(IrOpcode::kFloat64Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher) {
+  return MakeMatcher(
+      new IsConstantMatcher<double>(IrOpcode::kNumberConstant, value_matcher));
+}
+
+
+Matcher<Node*> IsSelect(const Matcher<MachineType>& type_matcher,
+                        const Matcher<Node*>& value0_matcher,
+                        const Matcher<Node*>& value1_matcher,
+                        const Matcher<Node*>& value2_matcher) {
+  return MakeMatcher(new IsSelectMatcher(type_matcher, value0_matcher,
+                                         value1_matcher, value2_matcher));
+}
+
+
+Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
+                     const Matcher<Node*>& value0_matcher,
+                     const Matcher<Node*>& value1_matcher,
+                     const Matcher<Node*>& merge_matcher) {
+  return MakeMatcher(new IsPhiMatcher(type_matcher, value0_matcher,
+                                      value1_matcher, merge_matcher));
+}
+
+
+Matcher<Node*> IsEffectPhi(const Matcher<Node*>& effect0_matcher,
+                           const Matcher<Node*>& effect1_matcher,
+                           const Matcher<Node*>& merge_matcher) {
+  return MakeMatcher(
+      new IsEffectPhiMatcher(effect0_matcher, effect1_matcher, merge_matcher));
+}
+
+
+Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher,
+                            const Matcher<Node*>& base_matcher) {
+  return MakeMatcher(new IsProjectionMatcher(index_matcher, base_matcher));
+}
+
+
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+                      const Matcher<Node*>& value0_matcher,
+                      const Matcher<Node*>& value1_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsCall2Matcher(descriptor_matcher, value0_matcher,
+                                        value1_matcher, effect_matcher,
+                                        control_matcher));
+}
+
+
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+                      const Matcher<Node*>& value0_matcher,
+                      const Matcher<Node*>& value1_matcher,
+                      const Matcher<Node*>& value2_matcher,
+                      const Matcher<Node*>& value3_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsCall4Matcher(
+      descriptor_matcher, value0_matcher, value1_matcher, value2_matcher,
+      value3_matcher, effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
+                           const Matcher<Node*>& base_matcher,
+                           const Matcher<Node*>& effect_matcher,
+                           const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadFieldMatcher(access_matcher, base_matcher,
+                                            effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsStoreField(const Matcher<FieldAccess>& access_matcher,
+                            const Matcher<Node*>& base_matcher,
+                            const Matcher<Node*>& value_matcher,
+                            const Matcher<Node*>& effect_matcher,
+                            const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsStoreFieldMatcher(access_matcher, base_matcher,
+                                             value_matcher, effect_matcher,
+                                             control_matcher));
+}
+
+
+Matcher<Node*> IsLoadBuffer(const Matcher<BufferAccess>& access_matcher,
+                            const Matcher<Node*>& buffer_matcher,
+                            const Matcher<Node*>& offset_matcher,
+                            const Matcher<Node*>& length_matcher,
+                            const Matcher<Node*>& effect_matcher,
+                            const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadBufferMatcher(access_matcher, buffer_matcher,
+                                             offset_matcher, length_matcher,
+                                             effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsStoreBuffer(const Matcher<BufferAccess>& access_matcher,
+                             const Matcher<Node*>& buffer_matcher,
+                             const Matcher<Node*>& offset_matcher,
+                             const Matcher<Node*>& length_matcher,
+                             const Matcher<Node*>& value_matcher,
+                             const Matcher<Node*>& effect_matcher,
+                             const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsStoreBufferMatcher(
+      access_matcher, buffer_matcher, offset_matcher, length_matcher,
+      value_matcher, effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
+                             const Matcher<Node*>& base_matcher,
+                             const Matcher<Node*>& index_matcher,
+                             const Matcher<Node*>& effect_matcher,
+                             const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadElementMatcher(access_matcher, base_matcher,
+                                              index_matcher, effect_matcher,
+                                              control_matcher));
+}
+
+
+Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher,
+                              const Matcher<Node*>& base_matcher,
+                              const Matcher<Node*>& index_matcher,
+                              const Matcher<Node*>& value_matcher,
+                              const Matcher<Node*>& effect_matcher,
+                              const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsStoreElementMatcher(
+      access_matcher, base_matcher, index_matcher, value_matcher,
+      effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
+                      const Matcher<Node*>& base_matcher,
+                      const Matcher<Node*>& index_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsLoadMatcher(rep_matcher, base_matcher, index_matcher,
+                                       effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
+                          const Matcher<Node*>& context_matcher,
+                          const Matcher<Node*>& effect_matcher,
+                          const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsToNumberMatcher(base_matcher, context_matcher,
+                                           effect_matcher, control_matcher));
+}
+
+
+Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
+                       const Matcher<Node*>& base_matcher,
+                       const Matcher<Node*>& index_matcher,
+                       const Matcher<Node*>& value_matcher,
+                       const Matcher<Node*>& effect_matcher,
+                       const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsStoreMatcher(rep_matcher, base_matcher,
+                                        index_matcher, value_matcher,
+                                        effect_matcher, control_matcher));
+}
+
+
+#define IS_BINOP_MATCHER(Name)                                            \
+  Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher,              \
+                          const Matcher<Node*>& rhs_matcher) {            \
+    return MakeMatcher(                                                   \
+        new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \
+  }
+IS_BINOP_MATCHER(NumberEqual)
+IS_BINOP_MATCHER(NumberLessThan)
+IS_BINOP_MATCHER(NumberSubtract)
+IS_BINOP_MATCHER(NumberMultiply)
+IS_BINOP_MATCHER(Word32And)
+IS_BINOP_MATCHER(Word32Sar)
+IS_BINOP_MATCHER(Word32Shl)
+IS_BINOP_MATCHER(Word32Shr)
+IS_BINOP_MATCHER(Word32Ror)
+IS_BINOP_MATCHER(Word32Equal)
+IS_BINOP_MATCHER(Word64And)
+IS_BINOP_MATCHER(Word64Sar)
+IS_BINOP_MATCHER(Word64Shl)
+IS_BINOP_MATCHER(Word64Equal)
+IS_BINOP_MATCHER(Int32AddWithOverflow)
+IS_BINOP_MATCHER(Int32Add)
+IS_BINOP_MATCHER(Int32Sub)
+IS_BINOP_MATCHER(Int32Mul)
+IS_BINOP_MATCHER(Int32MulHigh)
+IS_BINOP_MATCHER(Int32LessThan)
+IS_BINOP_MATCHER(Uint32LessThan)
+IS_BINOP_MATCHER(Uint32LessThanOrEqual)
+IS_BINOP_MATCHER(Float64Sub)
+#undef IS_BINOP_MATCHER
+
+
+#define IS_UNOP_MATCHER(Name)                                                \
+  Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) {             \
+    return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
+  }
+IS_UNOP_MATCHER(AnyToBoolean)
+IS_UNOP_MATCHER(BooleanNot)
+IS_UNOP_MATCHER(ChangeFloat64ToInt32)
+IS_UNOP_MATCHER(ChangeFloat64ToUint32)
+IS_UNOP_MATCHER(ChangeInt32ToFloat64)
+IS_UNOP_MATCHER(ChangeInt32ToInt64)
+IS_UNOP_MATCHER(ChangeUint32ToFloat64)
+IS_UNOP_MATCHER(ChangeUint32ToUint64)
+IS_UNOP_MATCHER(TruncateFloat64ToFloat32)
+IS_UNOP_MATCHER(TruncateFloat64ToInt32)
+IS_UNOP_MATCHER(TruncateInt64ToInt32)
+IS_UNOP_MATCHER(Float64Sqrt)
+IS_UNOP_MATCHER(Float64Floor)
+IS_UNOP_MATCHER(Float64Ceil)
+IS_UNOP_MATCHER(Float64RoundTruncate)
+IS_UNOP_MATCHER(Float64RoundTiesAway)
+IS_UNOP_MATCHER(NumberToInt32)
+IS_UNOP_MATCHER(NumberToUint32)
+#undef IS_UNOP_MATCHER
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/node-test-utils.h b/test/unittests/compiler/node-test-utils.h
new file mode 100644
index 0000000..02b6e43
--- /dev/null
+++ b/test/unittests/compiler/node-test-utils.h
@@ -0,0 +1,196 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_
+#define V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_
+
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/machine-type.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class ExternalReference;
+class HeapObject;
+template <class T>
+class Unique;
+
+namespace compiler {
+
+// Forward declarations.
+class BufferAccess;
+class CallDescriptor;
+struct ElementAccess;
+struct FieldAccess;
+class Node;
+
+
+using ::testing::Matcher;
+
+
+Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
+                       const Matcher<Node*>& control1_matcher);
+Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
+                        const Matcher<Node*>& effect_matcher);
+Matcher<Node*> IsExternalConstant(
+    const Matcher<ExternalReference>& value_matcher);
+Matcher<Node*> IsHeapConstant(
+    const Matcher<Unique<HeapObject> >& value_matcher);
+Matcher<Node*> IsFloat32Constant(const Matcher<float>& value_matcher);
+Matcher<Node*> IsFloat64Constant(const Matcher<double>& value_matcher);
+Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher);
+Matcher<Node*> IsInt64Constant(const Matcher<int64_t>& value_matcher);
+Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher);
+Matcher<Node*> IsSelect(const Matcher<MachineType>& type_matcher,
+                        const Matcher<Node*>& value0_matcher,
+                        const Matcher<Node*>& value1_matcher,
+                        const Matcher<Node*>& value2_matcher);
+Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
+                     const Matcher<Node*>& value0_matcher,
+                     const Matcher<Node*>& value1_matcher,
+                     const Matcher<Node*>& merge_matcher);
+Matcher<Node*> IsEffectPhi(const Matcher<Node*>& effect0_matcher,
+                           const Matcher<Node*>& effect1_matcher,
+                           const Matcher<Node*>& merge_matcher);
+Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher,
+                            const Matcher<Node*>& base_matcher);
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+                      const Matcher<Node*>& value0_matcher,
+                      const Matcher<Node*>& value1_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+                      const Matcher<Node*>& value0_matcher,
+                      const Matcher<Node*>& value1_matcher,
+                      const Matcher<Node*>& value2_matcher,
+                      const Matcher<Node*>& value3_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher);
+
+Matcher<Node*> IsAnyToBoolean(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher);
+Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsNumberLessThan(const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsNumberSubtract(const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsNumberMultiply(const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
+                           const Matcher<Node*>& base_matcher,
+                           const Matcher<Node*>& effect_matcher,
+                           const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsStoreField(const Matcher<FieldAccess>& access_matcher,
+                            const Matcher<Node*>& base_matcher,
+                            const Matcher<Node*>& value_matcher,
+                            const Matcher<Node*>& effect_matcher,
+                            const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsLoadBuffer(const Matcher<BufferAccess>& access_matcher,
+                            const Matcher<Node*>& buffer_matcher,
+                            const Matcher<Node*>& offset_matcher,
+                            const Matcher<Node*>& length_matcher,
+                            const Matcher<Node*>& effect_matcher,
+                            const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsStoreBuffer(const Matcher<BufferAccess>& access_matcher,
+                             const Matcher<Node*>& buffer_matcher,
+                             const Matcher<Node*>& offset_matcher,
+                             const Matcher<Node*>& length_matcher,
+                             const Matcher<Node*>& value_matcher,
+                             const Matcher<Node*>& effect_matcher,
+                             const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsLoadElement(const Matcher<ElementAccess>& access_matcher,
+                             const Matcher<Node*>& base_matcher,
+                             const Matcher<Node*>& index_matcher,
+                             const Matcher<Node*>& control_matcher,
+                             const Matcher<Node*>& effect_matcher);
+Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher,
+                              const Matcher<Node*>& base_matcher,
+                              const Matcher<Node*>& index_matcher,
+                              const Matcher<Node*>& value_matcher,
+                              const Matcher<Node*>& effect_matcher,
+                              const Matcher<Node*>& control_matcher);
+
+Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher,
+                      const Matcher<Node*>& base_matcher,
+                      const Matcher<Node*>& index_matcher,
+                      const Matcher<Node*>& effect_matcher,
+                      const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
+                       const Matcher<Node*>& base_matcher,
+                       const Matcher<Node*>& index_matcher,
+                       const Matcher<Node*>& value_matcher,
+                       const Matcher<Node*>& effect_matcher,
+                       const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsWord32And(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Sar(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Shl(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Shr(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Ror(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord64Shl(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord64Sar(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord64Equal(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32AddWithOverflow(const Matcher<Node*>& lhs_matcher,
+                                      const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32Add(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32Sub(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32Mul(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32MulHigh(const Matcher<Node*>& lhs_matcher,
+                              const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32LessThan(const Matcher<Node*>& lhs_matcher,
+                               const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsUint32LessThan(const Matcher<Node*>& lhs_matcher,
+                                const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsUint32LessThanOrEqual(const Matcher<Node*>& lhs_matcher,
+                                       const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeFloat64ToUint32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeInt32ToInt64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeUint32ToFloat64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeUint32ToUint64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsTruncateFloat64ToFloat32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsTruncateFloat64ToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64Sub(const Matcher<Node*>& lhs_matcher,
+                            const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsFloat64Sqrt(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64Floor(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64Ceil(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64RoundTruncate(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsFloat64RoundTiesAway(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher,
+                          const Matcher<Node*>& context_matcher,
+                          const Matcher<Node*>& effect_matcher,
+                          const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsNumberToInt32(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher);
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_COMPILER_NODE_TEST_UTILS_H_
diff --git a/test/unittests/compiler/register-allocator-unittest.cc b/test/unittests/compiler/register-allocator-unittest.cc
new file mode 100644
index 0000000..12dedbd
--- /dev/null
+++ b/test/unittests/compiler/register-allocator-unittest.cc
@@ -0,0 +1,437 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/pipeline.h"
+#include "test/unittests/compiler/instruction-sequence-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class RegisterAllocatorTest : public InstructionSequenceTest {
+ public:
+  void Allocate() {
+    WireBlocks();
+    Pipeline::AllocateRegistersForTesting(config(), sequence(), true);
+  }
+};
+
+
+TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
+  // return p0 + p1;
+  StartBlock();
+  auto a_reg = Parameter();
+  auto b_reg = Parameter();
+  auto c_reg = EmitOI(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0));
+  Return(c_reg);
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SimpleLoop) {
+  // i = K;
+  // while(true) { i++ }
+  StartBlock();
+  auto i_reg = DefineConstant();
+  EndBlock();
+
+  {
+    StartLoop(1);
+
+    StartBlock();
+    auto phi = Phi(i_reg);
+    auto ipp = EmitOI(Same(), Reg(phi), Use(DefineConstant()));
+    Extend(phi, ipp);
+    EndBlock(Jump(0));
+
+    EndLoop();
+  }
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SimpleBranch) {
+  // return i ? K1 : K2
+  StartBlock();
+  auto i = DefineConstant();
+  EndBlock(Branch(Reg(i), 1, 2));
+
+  StartBlock();
+  Return(DefineConstant());
+  EndBlock(Last());
+
+  StartBlock();
+  Return(DefineConstant());
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SimpleDiamond) {
+  // return p0 ? p0 : p0
+  StartBlock();
+  auto param = Parameter();
+  EndBlock(Branch(Reg(param), 1, 2));
+
+  StartBlock();
+  EndBlock(Jump(2));
+
+  StartBlock();
+  EndBlock(Jump(1));
+
+  StartBlock();
+  Return(param);
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SimpleDiamondPhi) {
+  // return i ? K1 : K2
+  StartBlock();
+  EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+  StartBlock();
+  auto t_val = DefineConstant();
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto f_val = DefineConstant();
+  EndBlock(Jump(1));
+
+  StartBlock();
+  Return(Reg(Phi(t_val, f_val)));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, DiamondManyPhis) {
+  const int kPhis = kDefaultNRegs * 2;
+
+  StartBlock();
+  EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+  StartBlock();
+  VReg t_vals[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    t_vals[i] = DefineConstant();
+  }
+  EndBlock(Jump(2));
+
+  StartBlock();
+  VReg f_vals[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    f_vals[i] = DefineConstant();
+  }
+  EndBlock(Jump(1));
+
+  StartBlock();
+  TestOperand merged[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    merged[i] = Use(Phi(t_vals[i], f_vals[i]));
+  }
+  Return(EmitCall(Slot(-1), kPhis, merged));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) {
+  const int kPhis = kDefaultNRegs * 2;
+
+  // First diamond.
+  StartBlock();
+  VReg vals[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    vals[i] = Parameter(Slot(-1 - i));
+  }
+  EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+  StartBlock();
+  EndBlock(Jump(2));
+
+  StartBlock();
+  EndBlock(Jump(1));
+
+  // Second diamond.
+  StartBlock();
+  EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+  StartBlock();
+  EndBlock(Jump(2));
+
+  StartBlock();
+  EndBlock(Jump(1));
+
+  StartBlock();
+  TestOperand merged[kPhis];
+  for (int i = 0; i < kPhis; ++i) {
+    merged[i] = Use(Phi(vals[i], vals[i]));
+  }
+  Return(EmitCall(Reg(0), kPhis, merged));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
+  const size_t kNumRegs = 3;
+  const size_t kParams = kNumRegs + 1;
+  // Override number of registers.
+  SetNumRegs(kNumRegs, kNumRegs);
+
+  StartBlock();
+  auto constant = DefineConstant();
+  VReg parameters[kParams];
+  for (size_t i = 0; i < arraysize(parameters); ++i) {
+    parameters[i] = DefineConstant();
+  }
+  EndBlock();
+
+  PhiInstruction* phis[kParams];
+  {
+    StartLoop(2);
+
+    // Loop header.
+    StartBlock();
+
+    for (size_t i = 0; i < arraysize(parameters); ++i) {
+      phis[i] = Phi(parameters[i]);
+    }
+
+    // Perform some computations.
+    // something like phi[i] += const
+    for (size_t i = 0; i < arraysize(parameters); ++i) {
+      auto result = EmitOI(Same(), Reg(phis[i]), Use(constant));
+      Extend(phis[i], result);
+    }
+
+    EndBlock(Branch(Reg(DefineConstant()), 1, 2));
+
+    // Jump back to loop header.
+    StartBlock();
+    EndBlock(Jump(-1));
+
+    EndLoop();
+  }
+
+  StartBlock();
+  Return(DefineConstant());
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SpillPhi) {
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto left = Define(Reg(0));
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto right = Define(Reg(0));
+  EndBlock();
+
+  StartBlock();
+  auto phi = Phi(left, right);
+  EmitCall(Slot(-1));
+  Return(Reg(phi));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, MoveLotsOfConstants) {
+  StartBlock();
+  VReg constants[kDefaultNRegs];
+  for (size_t i = 0; i < arraysize(constants); ++i) {
+    constants[i] = DefineConstant();
+  }
+  TestOperand call_ops[kDefaultNRegs * 2];
+  for (int i = 0; i < kDefaultNRegs; ++i) {
+    call_ops[i] = Reg(constants[i], i);
+  }
+  for (int i = 0; i < kDefaultNRegs; ++i) {
+    call_ops[i + kDefaultNRegs] = Slot(constants[i], i);
+  }
+  EmitCall(Slot(-1), arraysize(call_ops), call_ops);
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, SplitBeforeInstruction) {
+  const int kNumRegs = 6;
+  SetNumRegs(kNumRegs, kNumRegs);
+
+  StartBlock();
+
+  // Stack parameters/spilled values.
+  auto p_0 = Define(Slot(-1));
+  auto p_1 = Define(Slot(-2));
+
+  // Fill registers.
+  VReg values[kNumRegs];
+  for (size_t i = 0; i < arraysize(values); ++i) {
+    values[i] = Define(Reg(static_cast<int>(i)));
+  }
+
+  // values[0] will be split in the second half of this instruction.
+  // Models Intel mod instructions.
+  EmitOI(Reg(0), Reg(p_0, 1), UniqueReg(p_1));
+  EmitI(Reg(values[0], 0));
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, NestedDiamondPhiMerge) {
+  // Outer diamond.
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 5));
+
+  // Diamond 1
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto ll = Define(Reg());
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto lr = Define(Reg());
+  EndBlock();
+
+  StartBlock();
+  auto l_phi = Phi(ll, lr);
+  EndBlock(Jump(5));
+
+  // Diamond 2
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto rl = Define(Reg());
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto rr = Define(Reg());
+  EndBlock();
+
+  StartBlock();
+  auto r_phi = Phi(rl, rr);
+  EndBlock();
+
+  // Outer diamond merge.
+  StartBlock();
+  auto phi = Phi(l_phi, r_phi);
+  Return(Reg(phi));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, NestedDiamondPhiMergeDifferent) {
+  // Outer diamond.
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 5));
+
+  // Diamond 1
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto ll = Define(Reg(0));
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto lr = Define(Reg(1));
+  EndBlock();
+
+  StartBlock();
+  auto l_phi = Phi(ll, lr);
+  EndBlock(Jump(5));
+
+  // Diamond 2
+  StartBlock();
+  EndBlock(Branch(Imm(), 1, 2));
+
+  StartBlock();
+  auto rl = Define(Reg(2));
+  EndBlock(Jump(2));
+
+  StartBlock();
+  auto rr = Define(Reg(3));
+  EndBlock();
+
+  StartBlock();
+  auto r_phi = Phi(rl, rr);
+  EndBlock();
+
+  // Outer diamond merge.
+  StartBlock();
+  auto phi = Phi(l_phi, r_phi);
+  Return(Reg(phi));
+  EndBlock();
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, RegressionSplitBeforeAndMove) {
+  StartBlock();
+
+  // Fill registers.
+  VReg values[kDefaultNRegs];
+  for (size_t i = 0; i < arraysize(values); ++i) {
+    if (i == 0 || i == 1) continue;  // Leave a hole for c_1 to take.
+    values[i] = Define(Reg(static_cast<int>(i)));
+  }
+
+  auto c_0 = DefineConstant();
+  auto c_1 = DefineConstant();
+
+  EmitOI(Reg(1), Reg(c_0, 0), UniqueReg(c_1));
+
+  // Use previous values to force c_1 to split before the previous instruction.
+  for (size_t i = 0; i < arraysize(values); ++i) {
+    if (i == 0 || i == 1) continue;
+    EmitI(Reg(values[i], static_cast<int>(i)));
+  }
+
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, RegressionSpillTwice) {
+  StartBlock();
+  auto p_0 = Parameter(Reg(1));
+  EmitCall(Slot(-2), Unique(p_0), Reg(p_0, 1));
+  EndBlock(Last());
+
+  Allocate();
+}
+
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/select-lowering-unittest.cc b/test/unittests/compiler/select-lowering-unittest.cc
new file mode 100644
index 0000000..51efc83
--- /dev/null
+++ b/test/unittests/compiler/select-lowering-unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/select-lowering.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::AllOf;
+using testing::Capture;
+using testing::CaptureEq;
+using testing::Not;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class SelectLoweringTest : public GraphTest {
+ public:
+  SelectLoweringTest() : GraphTest(5), lowering_(graph(), common()) {}
+
+ protected:
+  Reduction Reduce(Node* node) { return lowering_.Reduce(node); }
+
+ private:
+  SelectLowering lowering_;
+};
+
+
+TEST_F(SelectLoweringTest, SelectWithSameConditions) {
+  Node* const p0 = Parameter(0);
+  Node* const p1 = Parameter(1);
+  Node* const p2 = Parameter(2);
+  Node* const p3 = Parameter(3);
+  Node* const p4 = Parameter(4);
+  Node* const s0 = graph()->NewNode(common()->Select(kMachInt32), p0, p1, p2);
+
+  Capture<Node*> branch;
+  Capture<Node*> merge;
+  {
+    Reduction const r = Reduce(s0);
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsPhi(
+            kMachInt32, p1, p2,
+            AllOf(CaptureEq(&merge),
+                  IsMerge(IsIfTrue(CaptureEq(&branch)),
+                          IsIfFalse(AllOf(CaptureEq(&branch),
+                                          IsBranch(p0, graph()->start())))))));
+  }
+  {
+    Reduction const r =
+        Reduce(graph()->NewNode(common()->Select(kMachInt32), p0, p3, p4));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsPhi(kMachInt32, p3, p4, CaptureEq(&merge)));
+  }
+  {
+    // We must not reuse the diamond if it is reachable from either else/then
+    // values of the Select, because the resulting graph can not be scheduled.
+    Reduction const r =
+        Reduce(graph()->NewNode(common()->Select(kMachInt32), p0, s0, p0));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsPhi(kMachInt32, s0, p0, Not(CaptureEq(&merge))));
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/simplified-operator-reducer-unittest.cc b/test/unittests/compiler/simplified-operator-reducer-unittest.cc
new file mode 100644
index 0000000..e5f46c0
--- /dev/null
+++ b/test/unittests/compiler/simplified-operator-reducer-unittest.cc
@@ -0,0 +1,520 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/compiler/simplified-operator-reducer.h"
+#include "src/conversions.h"
+#include "src/types.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::BitEq;
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class SimplifiedOperatorReducerTest : public TypedGraphTest {
+ public:
+  explicit SimplifiedOperatorReducerTest(int num_parameters = 1)
+      : TypedGraphTest(num_parameters), simplified_(zone()) {}
+  ~SimplifiedOperatorReducerTest() OVERRIDE {}
+
+ protected:
+  Reduction Reduce(Node* node) {
+    MachineOperatorBuilder machine(zone());
+    JSOperatorBuilder javascript(zone());
+    JSGraph jsgraph(graph(), common(), &javascript, &machine);
+    SimplifiedOperatorReducer reducer(&jsgraph);
+    return reducer.Reduce(node);
+  }
+
+  SimplifiedOperatorBuilder* simplified() { return &simplified_; }
+
+ private:
+  SimplifiedOperatorBuilder simplified_;
+};
+
+
+template <typename T>
+class SimplifiedOperatorReducerTestWithParam
+    : public SimplifiedOperatorReducerTest,
+      public ::testing::WithParamInterface<T> {
+ public:
+  explicit SimplifiedOperatorReducerTestWithParam(int num_parameters = 1)
+      : SimplifiedOperatorReducerTest(num_parameters) {}
+  ~SimplifiedOperatorReducerTestWithParam() OVERRIDE {}
+};
+
+
+namespace {
+
+static const double kFloat64Values[] = {
+    -V8_INFINITY,  -6.52696e+290, -1.05768e+290, -5.34203e+268, -1.01997e+268,
+    -8.22758e+266, -1.58402e+261, -5.15246e+241, -5.92107e+226, -1.21477e+226,
+    -1.67913e+188, -1.6257e+184,  -2.60043e+170, -2.52941e+168, -3.06033e+116,
+    -4.56201e+52,  -3.56788e+50,  -9.9066e+38,   -3.07261e+31,  -2.1271e+09,
+    -1.91489e+09,  -1.73053e+09,  -9.30675e+08,  -26030,        -20453,
+    -15790,        -11699,        -111,          -97,           -78,
+    -63,           -58,           -1.53858e-06,  -2.98914e-12,  -1.14741e-39,
+    -8.20347e-57,  -1.48932e-59,  -3.17692e-66,  -8.93103e-81,  -3.91337e-83,
+    -6.0489e-92,   -8.83291e-113, -4.28266e-117, -1.92058e-178, -2.0567e-192,
+    -1.68167e-194, -1.51841e-214, -3.98738e-234, -7.31851e-242, -2.21875e-253,
+    -1.11612e-293, -0.0,          0.0,           2.22507e-308,  1.06526e-307,
+    4.16643e-227,  6.76624e-223,  2.0432e-197,   3.16254e-184,  1.37315e-173,
+    2.88603e-172,  1.54155e-99,   4.42923e-81,   1.40539e-73,   5.4462e-73,
+    1.24064e-58,   3.11167e-58,   2.75826e-39,   0.143815,      58,
+    67,            601,           7941,          11644,         13697,
+    25680,         29882,         1.32165e+08,   1.62439e+08,   4.16837e+08,
+    9.59097e+08,   1.32491e+09,   1.8728e+09,    1.0672e+17,    2.69606e+46,
+    1.98285e+79,   1.0098e+82,    7.93064e+88,   3.67444e+121,  9.36506e+123,
+    7.27954e+162,  3.05316e+168,  1.16171e+175,  1.64771e+189,  1.1622e+202,
+    2.00748e+239,  2.51778e+244,  3.90282e+306,  1.79769e+308,  V8_INFINITY};
+
+
+static const int32_t kInt32Values[] = {
+    -2147483647 - 1, -2104508227, -2103151830, -1435284490, -1378926425,
+    -1318814539,     -1289388009, -1287537572, -1279026536, -1241605942,
+    -1226046939,     -941837148,  -779818051,  -413830641,  -245798087,
+    -184657557,      -127145950,  -105483328,  -32325,      -26653,
+    -23858,          -23834,      -22363,      -19858,      -19044,
+    -18744,          -15528,      -5309,       -3372,       -2093,
+    -104,            -98,         -97,         -93,         -84,
+    -80,             -78,         -76,         -72,         -58,
+    -57,             -56,         -55,         -45,         -40,
+    -34,             -32,         -25,         -24,         -5,
+    -2,              0,           3,           10,          24,
+    34,              42,          46,          47,          48,
+    52,              56,          64,          65,          71,
+    76,              79,          81,          82,          97,
+    102,             103,         104,         106,         107,
+    109,             116,         122,         3653,        4485,
+    12405,           16504,       26262,       28704,       29755,
+    30554,           16476817,    605431957,   832401070,   873617242,
+    914205764,       1062628108,  1087581664,  1488498068,  1534668023,
+    1661587028,      1696896187,  1866841746,  2032089723,  2147483647};
+
+
+static const uint32_t kUint32Values[] = {
+    0x0,        0x5,        0x8,        0xc,        0xd,        0x26,
+    0x28,       0x29,       0x30,       0x34,       0x3e,       0x42,
+    0x50,       0x5b,       0x63,       0x71,       0x77,       0x7c,
+    0x83,       0x88,       0x96,       0x9c,       0xa3,       0xfa,
+    0x7a7,      0x165d,     0x234d,     0x3acb,     0x43a5,     0x4573,
+    0x5b4f,     0x5f14,     0x6996,     0x6c6e,     0x7289,     0x7b9a,
+    0x7bc9,     0x86bb,     0xa839,     0xaa41,     0xb03b,     0xc942,
+    0xce68,     0xcf4c,     0xd3ad,     0xdea3,     0xe90c,     0xed86,
+    0xfba5,     0x172dcc6,  0x114d8fc1, 0x182d6c9d, 0x1b1e3fad, 0x1db033bf,
+    0x1e1de755, 0x1f625c80, 0x28f6cf00, 0x2acb6a94, 0x2c20240e, 0x2f0fe54e,
+    0x31863a7c, 0x33325474, 0x3532fae3, 0x3bab82ea, 0x4c4b83a2, 0x4cd93d1e,
+    0x4f7331d4, 0x5491b09b, 0x57cc6ff9, 0x60d3b4dc, 0x653f5904, 0x690ae256,
+    0x69fe3276, 0x6bebf0ba, 0x6e2c69a3, 0x73b84ff7, 0x7b3a1924, 0x7ed032d9,
+    0x84dd734b, 0x8552ea53, 0x8680754f, 0x8e9660eb, 0x94fe2b9c, 0x972d30cf,
+    0x9b98c482, 0xb158667e, 0xb432932c, 0xb5b70989, 0xb669971a, 0xb7c359d1,
+    0xbeb15c0d, 0xc171c53d, 0xc743dd38, 0xc8e2af50, 0xc98e2df0, 0xd9d1cdf9,
+    0xdcc91049, 0xe46f396d, 0xee991950, 0xef64e521, 0xf7aeefc9, 0xffffffff};
+
+}  // namespace
+
+
+// -----------------------------------------------------------------------------
+// Unary operators
+
+
+namespace {
+
+struct UnaryOperator {
+  const Operator* (SimplifiedOperatorBuilder::*constructor)();
+  const char* constructor_name;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) {
+  return os << unop.constructor_name;
+}
+
+
+static const UnaryOperator kUnaryOperators[] = {
+    {&SimplifiedOperatorBuilder::AnyToBoolean, "AnyToBoolean"},
+    {&SimplifiedOperatorBuilder::BooleanNot, "BooleanNot"},
+    {&SimplifiedOperatorBuilder::ChangeBitToBool, "ChangeBitToBool"},
+    {&SimplifiedOperatorBuilder::ChangeBoolToBit, "ChangeBoolToBit"},
+    {&SimplifiedOperatorBuilder::ChangeFloat64ToTagged,
+     "ChangeFloat64ToTagged"},
+    {&SimplifiedOperatorBuilder::ChangeInt32ToTagged, "ChangeInt32ToTagged"},
+    {&SimplifiedOperatorBuilder::ChangeTaggedToFloat64,
+     "ChangeTaggedToFloat64"},
+    {&SimplifiedOperatorBuilder::ChangeTaggedToInt32, "ChangeTaggedToInt32"},
+    {&SimplifiedOperatorBuilder::ChangeTaggedToUint32, "ChangeTaggedToUint32"},
+    {&SimplifiedOperatorBuilder::ChangeUint32ToTagged, "ChangeUint32ToTagged"}};
+
+}  // namespace
+
+
+typedef SimplifiedOperatorReducerTestWithParam<UnaryOperator>
+    SimplifiedUnaryOperatorTest;
+
+
+TEST_P(SimplifiedUnaryOperatorTest, Parameter) {
+  const UnaryOperator& unop = GetParam();
+  Reduction reduction = Reduce(graph()->NewNode(
+      (simplified()->*unop.constructor)(), Parameter(Type::Any())));
+  EXPECT_FALSE(reduction.Changed());
+}
+
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorReducerTest,
+                        SimplifiedUnaryOperatorTest,
+                        ::testing::ValuesIn(kUnaryOperators));
+
+
+// -----------------------------------------------------------------------------
+// AnyToBoolean
+
+
+TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithBoolean) {
+  Node* p = Parameter(Type::Boolean());
+  Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_EQ(p, r.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithOrderedNumber) {
+  Node* p = Parameter(Type::OrderedNumber());
+  Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsBooleanNot(IsNumberEqual(p, IsNumberConstant(0))));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithString) {
+  Node* p = Parameter(Type::String());
+  Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(r.replacement(),
+              IsBooleanNot(
+                  IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), p,
+                                            graph()->start(), graph()->start()),
+                                IsNumberConstant(0))));
+}
+
+
+// -----------------------------------------------------------------------------
+// BooleanNot
+
+
+TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithBooleanNot) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(
+      graph()->NewNode(simplified()->BooleanNot(),
+                       graph()->NewNode(simplified()->BooleanNot(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithFalseConstant) {
+  Reduction reduction0 =
+      Reduce(graph()->NewNode(simplified()->BooleanNot(), FalseConstant()));
+  ASSERT_TRUE(reduction0.Changed());
+  EXPECT_THAT(reduction0.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, BooleanNotWithTrueConstant) {
+  Reduction reduction1 =
+      Reduce(graph()->NewNode(simplified()->BooleanNot(), TrueConstant()));
+  ASSERT_TRUE(reduction1.Changed());
+  EXPECT_THAT(reduction1.replacement(), IsFalseConstant());
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeBoolToBit
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithChangeBoolToBit) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeBitToBool(),
+      graph()->NewNode(simplified()->ChangeBoolToBit(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithZeroConstant) {
+  Reduction reduction = Reduce(
+      graph()->NewNode(simplified()->ChangeBitToBool(), Int32Constant(0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBitToBoolWithOneConstant) {
+  Reduction reduction = Reduce(
+      graph()->NewNode(simplified()->ChangeBitToBool(), Int32Constant(1)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsTrueConstant());
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeBoolToBit
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithFalseConstant) {
+  Reduction reduction = Reduce(
+      graph()->NewNode(simplified()->ChangeBoolToBit(), FalseConstant()));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithTrueConstant) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeBoolToBit(), TrueConstant()));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(1));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeBoolToBitWithChangeBitToBool) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeBoolToBit(),
+      graph()->NewNode(simplified()->ChangeBitToBool(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeFloat64ToTagged
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeFloat64ToTaggedWithConstant) {
+  TRACED_FOREACH(double, n, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeFloat64ToTagged(), Float64Constant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(n)));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeInt32ToTagged
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeInt32ToTaggedWithConstant) {
+  TRACED_FOREACH(int32_t, n, kInt32Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeInt32ToTagged(), Int32Constant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(FastI2D(n))));
+  }
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeTaggedToFloat64
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToFloat64WithChangeFloat64ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToFloat64(),
+      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToFloat64WithChangeInt32ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToFloat64(),
+      graph()->NewNode(simplified()->ChangeInt32ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsChangeInt32ToFloat64(param0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToFloat64WithChangeUint32ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToFloat64(),
+      graph()->NewNode(simplified()->ChangeUint32ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsChangeUint32ToFloat64(param0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithConstant) {
+  TRACED_FOREACH(double, n, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeTaggedToFloat64(), NumberConstant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(n)));
+  }
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant1) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
+                              NumberConstant(-base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(),
+              IsFloat64Constant(BitEq(-base::OS::nan_value())));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant2) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
+                              NumberConstant(base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(),
+              IsFloat64Constant(BitEq(base::OS::nan_value())));
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeTaggedToInt32
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToInt32WithChangeFloat64ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToInt32(),
+      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToInt32(param0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToInt32WithChangeInt32ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToInt32(),
+      graph()->NewNode(simplified()->ChangeInt32ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithConstant) {
+  TRACED_FOREACH(double, n, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeTaggedToInt32(), NumberConstant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsInt32Constant(DoubleToInt32(n)));
+  }
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithNaNConstant1) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(),
+                              NumberConstant(-base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToInt32WithNaNConstant2) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(),
+                              NumberConstant(base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeTaggedToUint32
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToUint32WithChangeFloat64ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToUint32(),
+      graph()->NewNode(simplified()->ChangeFloat64ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsChangeFloat64ToUint32(param0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest,
+       ChangeTaggedToUint32WithChangeUint32ToTagged) {
+  Node* param0 = Parameter(0);
+  Reduction reduction = Reduce(graph()->NewNode(
+      simplified()->ChangeTaggedToUint32(),
+      graph()->NewNode(simplified()->ChangeUint32ToTagged(), param0)));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_EQ(param0, reduction.replacement());
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithConstant) {
+  TRACED_FOREACH(double, n, kFloat64Values) {
+    Reduction reduction = Reduce(graph()->NewNode(
+        simplified()->ChangeTaggedToUint32(), NumberConstant(n)));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(),
+                IsInt32Constant(bit_cast<int32_t>(DoubleToUint32(n))));
+  }
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithNaNConstant1) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(),
+                              NumberConstant(-base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToUint32WithNaNConstant2) {
+  Reduction reduction =
+      Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(),
+                              NumberConstant(base::OS::nan_value())));
+  ASSERT_TRUE(reduction.Changed());
+  EXPECT_THAT(reduction.replacement(), IsInt32Constant(0));
+}
+
+
+// -----------------------------------------------------------------------------
+// ChangeUint32ToTagged
+
+
+TEST_F(SimplifiedOperatorReducerTest, ChangeUint32ToTagged) {
+  TRACED_FOREACH(uint32_t, n, kUint32Values) {
+    Reduction reduction =
+        Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(),
+                                Int32Constant(bit_cast<int32_t>(n))));
+    ASSERT_TRUE(reduction.Changed());
+    EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(FastUI2D(n))));
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/simplified-operator-unittest.cc b/test/unittests/compiler/simplified-operator-unittest.cc
new file mode 100644
index 0000000..bc537fd
--- /dev/null
+++ b/test/unittests/compiler/simplified-operator-unittest.cc
@@ -0,0 +1,288 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/operator-properties.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/types-inl.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// -----------------------------------------------------------------------------
+// Pure operators.
+
+
+namespace {
+
+struct PureOperator {
+  const Operator* (SimplifiedOperatorBuilder::*constructor)();
+  IrOpcode::Value opcode;
+  Operator::Properties properties;
+  int value_input_count;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
+  return os << IrOpcode::Mnemonic(pop.opcode);
+}
+
+
+const PureOperator kPureOperators[] = {
+#define PURE(Name, properties, input_count)              \
+  {                                                      \
+    &SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \
+        Operator::kPure | properties, input_count        \
+  }
+    PURE(AnyToBoolean, Operator::kNoProperties, 1),
+    PURE(BooleanNot, Operator::kNoProperties, 1),
+    PURE(BooleanToNumber, Operator::kNoProperties, 1),
+    PURE(NumberEqual, Operator::kCommutative, 2),
+    PURE(NumberLessThan, Operator::kNoProperties, 2),
+    PURE(NumberLessThanOrEqual, Operator::kNoProperties, 2),
+    PURE(NumberAdd, Operator::kCommutative, 2),
+    PURE(NumberSubtract, Operator::kNoProperties, 2),
+    PURE(NumberMultiply, Operator::kCommutative, 2),
+    PURE(NumberDivide, Operator::kNoProperties, 2),
+    PURE(NumberModulus, Operator::kNoProperties, 2),
+    PURE(NumberToInt32, Operator::kNoProperties, 1),
+    PURE(NumberToUint32, Operator::kNoProperties, 1),
+    PURE(StringEqual, Operator::kCommutative, 2),
+    PURE(StringLessThan, Operator::kNoProperties, 2),
+    PURE(StringLessThanOrEqual, Operator::kNoProperties, 2),
+    PURE(StringAdd, Operator::kNoProperties, 2),
+    PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1),
+    PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1),
+    PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1),
+    PURE(ChangeInt32ToTagged, Operator::kNoProperties, 1),
+    PURE(ChangeUint32ToTagged, Operator::kNoProperties, 1),
+    PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1),
+    PURE(ChangeBoolToBit, Operator::kNoProperties, 1),
+    PURE(ChangeBitToBool, Operator::kNoProperties, 1),
+    PURE(ObjectIsSmi, Operator::kNoProperties, 1),
+    PURE(ObjectIsNonNegativeSmi, Operator::kNoProperties, 1)
+#undef PURE
+};
+
+}  // namespace
+
+
+class SimplifiedPureOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<PureOperator> {};
+
+
+TEST_P(SimplifiedPureOperatorTest, InstancesAreGloballyShared) {
+  const PureOperator& pop = GetParam();
+  SimplifiedOperatorBuilder simplified1(zone());
+  SimplifiedOperatorBuilder simplified2(zone());
+  EXPECT_EQ((simplified1.*pop.constructor)(), (simplified2.*pop.constructor)());
+}
+
+
+TEST_P(SimplifiedPureOperatorTest, NumberOfInputsAndOutputs) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (simplified.*pop.constructor)();
+
+  EXPECT_EQ(pop.value_input_count, op->ValueInputCount());
+  EXPECT_EQ(0, op->EffectInputCount());
+  EXPECT_EQ(0, op->ControlInputCount());
+  EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, op->ValueOutputCount());
+  EXPECT_EQ(0, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(SimplifiedPureOperatorTest, OpcodeIsCorrect) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (simplified.*pop.constructor)();
+  EXPECT_EQ(pop.opcode, op->opcode());
+}
+
+
+TEST_P(SimplifiedPureOperatorTest, Properties) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const PureOperator& pop = GetParam();
+  const Operator* op = (simplified.*pop.constructor)();
+  EXPECT_EQ(pop.properties, op->properties() & pop.properties);
+}
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
+                        ::testing::ValuesIn(kPureOperators));
+
+
+// -----------------------------------------------------------------------------
+// Buffer access operators.
+
+
+namespace {
+
+const ExternalArrayType kExternalArrayTypes[] = {
+    kExternalUint8Array,   kExternalInt8Array,   kExternalUint16Array,
+    kExternalInt16Array,   kExternalUint32Array, kExternalInt32Array,
+    kExternalFloat32Array, kExternalFloat64Array};
+
+}  // namespace
+
+
+class SimplifiedBufferAccessOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<ExternalArrayType> {};
+
+
+TEST_P(SimplifiedBufferAccessOperatorTest, InstancesAreGloballyShared) {
+  BufferAccess const access(GetParam());
+  SimplifiedOperatorBuilder simplified1(zone());
+  SimplifiedOperatorBuilder simplified2(zone());
+  EXPECT_EQ(simplified1.LoadBuffer(access), simplified2.LoadBuffer(access));
+  EXPECT_EQ(simplified1.StoreBuffer(access), simplified2.StoreBuffer(access));
+}
+
+
+TEST_P(SimplifiedBufferAccessOperatorTest, LoadBuffer) {
+  SimplifiedOperatorBuilder simplified(zone());
+  BufferAccess const access(GetParam());
+  const Operator* op = simplified.LoadBuffer(access);
+
+  EXPECT_EQ(IrOpcode::kLoadBuffer, op->opcode());
+  EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
+  EXPECT_EQ(access, BufferAccessOf(op));
+
+  EXPECT_EQ(3, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(SimplifiedBufferAccessOperatorTest, StoreBuffer) {
+  SimplifiedOperatorBuilder simplified(zone());
+  BufferAccess const access(GetParam());
+  const Operator* op = simplified.StoreBuffer(access);
+
+  EXPECT_EQ(IrOpcode::kStoreBuffer, op->opcode());
+  EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
+  EXPECT_EQ(access, BufferAccessOf(op));
+
+  EXPECT_EQ(4, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
+                        SimplifiedBufferAccessOperatorTest,
+                        ::testing::ValuesIn(kExternalArrayTypes));
+
+
+// -----------------------------------------------------------------------------
+// Element access operators.
+
+
+namespace {
+
+const ElementAccess kElementAccesses[] = {
+    {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged},
+    {kUntaggedBase, 0, Type::Any(), kMachInt8},
+    {kUntaggedBase, 0, Type::Any(), kMachInt16},
+    {kUntaggedBase, 0, Type::Any(), kMachInt32},
+    {kUntaggedBase, 0, Type::Any(), kMachUint8},
+    {kUntaggedBase, 0, Type::Any(), kMachUint16},
+    {kUntaggedBase, 0, Type::Any(), kMachUint32},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt8},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt16},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt32},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
+    {kUntaggedBase, 0, Type::Number(), kRepFloat32},
+    {kUntaggedBase, 0, Type::Number(), kRepFloat64},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt8},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint8},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt16},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint16},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
+     kRepFloat32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
+     kRepFloat64}};
+
+}  // namespace
+
+
+class SimplifiedElementAccessOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<ElementAccess> {};
+
+
+TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const ElementAccess& access = GetParam();
+  const Operator* op = simplified.LoadElement(access);
+
+  EXPECT_EQ(IrOpcode::kLoadElement, op->opcode());
+  EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
+  EXPECT_EQ(access, ElementAccessOf(op));
+
+  EXPECT_EQ(2, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const ElementAccess& access = GetParam();
+  const Operator* op = simplified.StoreElement(access);
+
+  EXPECT_EQ(IrOpcode::kStoreElement, op->opcode());
+  EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
+  EXPECT_EQ(access, ElementAccessOf(op));
+
+  EXPECT_EQ(3, op->ValueInputCount());
+  EXPECT_EQ(1, op->EffectInputCount());
+  EXPECT_EQ(1, op->ControlInputCount());
+  EXPECT_EQ(5, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, op->ValueOutputCount());
+  EXPECT_EQ(1, op->EffectOutputCount());
+  EXPECT_EQ(0, op->ControlOutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
+                        SimplifiedElementAccessOperatorTest,
+                        ::testing::ValuesIn(kElementAccesses));
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/value-numbering-reducer-unittest.cc b/test/unittests/compiler/value-numbering-reducer-unittest.cc
new file mode 100644
index 0000000..b6be0bf
--- /dev/null
+++ b/test/unittests/compiler/value-numbering-reducer-unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "src/compiler/graph.h"
+#include "src/compiler/value-numbering-reducer.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+struct TestOperator : public Operator {
+  TestOperator(Operator::Opcode opcode, Operator::Properties properties,
+               size_t value_in, size_t value_out)
+      : Operator(opcode, properties, "TestOp", value_in, 0, 0, value_out, 0,
+                 0) {}
+};
+
+
+static const TestOperator kOp0(0, Operator::kEliminatable, 0, 1);
+static const TestOperator kOp1(1, Operator::kEliminatable, 1, 1);
+
+
+class ValueNumberingReducerTest : public TestWithZone {
+ public:
+  ValueNumberingReducerTest() : graph_(zone()), reducer_(zone()) {}
+
+ protected:
+  Reduction Reduce(Node* node) { return reducer_.Reduce(node); }
+
+  Graph* graph() { return &graph_; }
+
+ private:
+  Graph graph_;
+  ValueNumberingReducer reducer_;
+};
+
+
+TEST_F(ValueNumberingReducerTest, AllInputsAreChecked) {
+  Node* na = graph()->NewNode(&kOp0);
+  Node* nb = graph()->NewNode(&kOp0);
+  Node* n1 = graph()->NewNode(&kOp0, na);
+  Node* n2 = graph()->NewNode(&kOp0, nb);
+  EXPECT_FALSE(Reduce(n1).Changed());
+  EXPECT_FALSE(Reduce(n2).Changed());
+}
+
+
+TEST_F(ValueNumberingReducerTest, DeadNodesAreNeverReturned) {
+  Node* n0 = graph()->NewNode(&kOp0);
+  Node* n1 = graph()->NewNode(&kOp1, n0);
+  EXPECT_FALSE(Reduce(n1).Changed());
+  n1->Kill();
+  EXPECT_FALSE(Reduce(graph()->NewNode(&kOp1, n0)).Changed());
+}
+
+
+TEST_F(ValueNumberingReducerTest, OnlyEliminatableNodesAreReduced) {
+  TestOperator op(0, Operator::kNoProperties, 0, 1);
+  Node* n0 = graph()->NewNode(&op);
+  Node* n1 = graph()->NewNode(&op);
+  EXPECT_FALSE(Reduce(n0).Changed());
+  EXPECT_FALSE(Reduce(n1).Changed());
+}
+
+
+TEST_F(ValueNumberingReducerTest, OperatorEqualityNotIdentity) {
+  static const size_t kMaxInputCount = 16;
+  Node* inputs[kMaxInputCount];
+  for (size_t i = 0; i < arraysize(inputs); ++i) {
+    Operator::Opcode opcode = static_cast<Operator::Opcode>(
+        std::numeric_limits<Operator::Opcode>::max() - i);
+    inputs[i] = graph()->NewNode(
+        new (zone()) TestOperator(opcode, Operator::kEliminatable, 0, 1));
+  }
+  TRACED_FORRANGE(size_t, input_count, 0, arraysize(inputs)) {
+    const TestOperator op1(static_cast<Operator::Opcode>(input_count),
+                           Operator::kEliminatable, input_count, 1);
+    Node* n1 = graph()->NewNode(&op1, static_cast<int>(input_count), inputs);
+    Reduction r1 = Reduce(n1);
+    EXPECT_FALSE(r1.Changed());
+
+    const TestOperator op2(static_cast<Operator::Opcode>(input_count),
+                           Operator::kEliminatable, input_count, 1);
+    Node* n2 = graph()->NewNode(&op2, static_cast<int>(input_count), inputs);
+    Reduction r2 = Reduce(n2);
+    EXPECT_TRUE(r2.Changed());
+    EXPECT_EQ(n1, r2.replacement());
+  }
+}
+
+
+TEST_F(ValueNumberingReducerTest, SubsequentReductionsYieldTheSameNode) {
+  static const size_t kMaxInputCount = 16;
+  Node* inputs[kMaxInputCount];
+  for (size_t i = 0; i < arraysize(inputs); ++i) {
+    Operator::Opcode opcode = static_cast<Operator::Opcode>(
+        std::numeric_limits<Operator::Opcode>::max() - i);
+    inputs[i] = graph()->NewNode(
+        new (zone()) TestOperator(opcode, Operator::kEliminatable, 0, 1));
+  }
+  TRACED_FORRANGE(size_t, input_count, 0, arraysize(inputs)) {
+    const TestOperator op1(1, Operator::kEliminatable, input_count, 1);
+    Node* n = graph()->NewNode(&op1, static_cast<int>(input_count), inputs);
+    Reduction r = Reduce(n);
+    EXPECT_FALSE(r.Changed());
+
+    r = Reduce(graph()->NewNode(&op1, static_cast<int>(input_count), inputs));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(n, r.replacement());
+
+    r = Reduce(graph()->NewNode(&op1, static_cast<int>(input_count), inputs));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(n, r.replacement());
+  }
+}
+
+
+TEST_F(ValueNumberingReducerTest, WontReplaceNodeWithItself) {
+  Node* n = graph()->NewNode(&kOp0);
+  EXPECT_FALSE(Reduce(n).Changed());
+  EXPECT_FALSE(Reduce(n).Changed());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
new file mode 100644
index 0000000..9ef0fa5
--- /dev/null
+++ b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
@@ -0,0 +1,1068 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/compiler/instruction-selector-unittest.h"
+
+#include "src/compiler/node-matchers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeFloat32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat32, kMachFloat64);
+  m.Return(m.ChangeFloat32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSECvtss2sd, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) {
+  StreamBuilder m(this, kMachInt64, kMachInt32);
+  m.Return(m.ChangeInt32ToInt64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachUint32);
+  m.Return(m.ChangeUint32ToFloat64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSEUint32ToFloat64, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) {
+  StreamBuilder m(this, kMachUint64, kMachUint32);
+  m.Return(m.ChangeUint32ToUint64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat32);
+  m.Return(m.TruncateFloat64ToFloat32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kSSECvtsd2ss, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  m.Return(m.TruncateInt64ToInt32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
+}
+
+
+// -----------------------------------------------------------------------------
+// Loads and stores
+
+namespace {
+
+struct MemoryAccess {
+  MachineType type;
+  ArchOpcode load_opcode;
+  ArchOpcode store_opcode;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
+  return os << memacc.type;
+}
+
+
+static const MemoryAccess kMemoryAccesses[] = {
+    {kMachInt8, kX64Movsxbl, kX64Movb},
+    {kMachUint8, kX64Movzxbl, kX64Movb},
+    {kMachInt16, kX64Movsxwl, kX64Movw},
+    {kMachUint16, kX64Movzxwl, kX64Movw},
+    {kMachInt32, kX64Movl, kX64Movl},
+    {kMachUint32, kX64Movl, kX64Movl},
+    {kMachInt64, kX64Movq, kX64Movq},
+    {kMachUint64, kX64Movq, kX64Movq},
+    {kMachFloat32, kX64Movss, kX64Movss},
+    {kMachFloat64, kX64Movsd, kX64Movsd}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<MemoryAccess>
+    InstructionSelectorMemoryAccessTest;
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
+  m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
+  const MemoryAccess memacc = GetParam();
+  StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
+  m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
+  m.Return(m.Int32Constant(0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode());
+  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(0U, s[0]->OutputCount());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorMemoryAccessTest,
+                        ::testing::ValuesIn(kMemoryAccesses));
+
+// -----------------------------------------------------------------------------
+// ChangeUint32ToUint64.
+
+
+namespace {
+
+typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*);
+
+
+struct BinaryOperation {
+  Constructor constructor;
+  const char* constructor_name;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const BinaryOperation& bop) {
+  return os << bop.constructor_name;
+}
+
+
+const BinaryOperation kWord32BinaryOperations[] = {
+    {&RawMachineAssembler::Word32And, "Word32And"},
+    {&RawMachineAssembler::Word32Or, "Word32Or"},
+    {&RawMachineAssembler::Word32Xor, "Word32Xor"},
+    {&RawMachineAssembler::Word32Shl, "Word32Shl"},
+    {&RawMachineAssembler::Word32Shr, "Word32Shr"},
+    {&RawMachineAssembler::Word32Sar, "Word32Sar"},
+    {&RawMachineAssembler::Word32Ror, "Word32Ror"},
+    {&RawMachineAssembler::Word32Equal, "Word32Equal"},
+    {&RawMachineAssembler::Int32Add, "Int32Add"},
+    {&RawMachineAssembler::Int32Sub, "Int32Sub"},
+    {&RawMachineAssembler::Int32Mul, "Int32Mul"},
+    {&RawMachineAssembler::Int32MulHigh, "Int32MulHigh"},
+    {&RawMachineAssembler::Int32Div, "Int32Div"},
+    {&RawMachineAssembler::Int32LessThan, "Int32LessThan"},
+    {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual"},
+    {&RawMachineAssembler::Int32Mod, "Int32Mod"},
+    {&RawMachineAssembler::Uint32Div, "Uint32Div"},
+    {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan"},
+    {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual"},
+    {&RawMachineAssembler::Uint32Mod, "Uint32Mod"}};
+
+}  // namespace
+
+
+typedef InstructionSelectorTestWithParam<BinaryOperation>
+    InstructionSelectorChangeUint32ToUint64Test;
+
+
+TEST_P(InstructionSelectorChangeUint32ToUint64Test, ChangeUint32ToUint64) {
+  const BinaryOperation& bop = GetParam();
+  StreamBuilder m(this, kMachUint64, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  m.Return(m.ChangeUint32ToUint64((m.*bop.constructor)(p0, p1)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+                        InstructionSelectorChangeUint32ToUint64Test,
+                        ::testing::ValuesIn(kWord32BinaryOperations));
+
+
+// -----------------------------------------------------------------------------
+// TruncateInt64ToInt32.
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Sar) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  Node* const p = m.Parameter(0);
+  Node* const t = m.TruncateInt64ToInt32(m.Word64Sar(p, m.Int64Constant(32)));
+  m.Return(t);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Shr, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0)));
+  EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithWord64Shr) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  Node* const p = m.Parameter(0);
+  Node* const t = m.TruncateInt64ToInt32(m.Word64Shr(p, m.Int64Constant(32)));
+  m.Return(t);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Shr, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt32(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_TRUE(s.IsSameAsFirst(s[0]->OutputAt(0)));
+  EXPECT_EQ(s.ToVreg(t), s.ToVreg(s[0]->OutputAt(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Addition.
+
+
+TEST_F(InstructionSelectorTest, Int32AddWithInt32ParametersLea) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const a0 = m.Int32Add(p0, p1);
+  // Additional uses of input to add chooses lea
+  Node* const a1 = m.Int32Div(p0, p1);
+  m.Return(m.Int32Div(a0, a1));
+  Stream s = m.Build();
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaSingle) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(15);
+  // If one of the add's operands is only used once, use an "leal", even though
+  // an "addl" could be used. The "leal" has proven faster--out best guess is
+  // that it gives the register allocation more freedom and it doesn't set
+  // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+  // register allocation, then code generation will select an "addl" later for
+  // the cases that have been measured to be faster.
+  Node* const v0 = m.Int32Add(p0, c0);
+  m.Return(v0);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddConstantAsAdd) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(1);
+  // If there is only a single use of an add's input and the immediate constant
+  // for the add is 1, don't use an inc. It is much slower on modern Intel
+  // architectures.
+  m.Return(m.Int32Add(p0, c0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddConstantAsLeaDouble) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(15);
+  // A second use of an add's input uses lea
+  Node* const a0 = m.Int32Add(p0, c0);
+  m.Return(m.Int32Div(a0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaSingle) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(15);
+  // If one of the add's operands is only used once, use an "leal", even though
+  // an "addl" could be used. The "leal" has proven faster--out best guess is
+  // that it gives the register allocation more freedom and it doesn't set
+  // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+  // register allocation, then code generation will select an "addl" later for
+  // the cases that have been measured to be faster.
+  m.Return(m.Int32Add(c0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddCommutedConstantAsLeaDouble) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(15);
+  // A second use of an add's input uses lea
+  Node* const a0 = m.Int32Add(c0, p0);
+  USE(a0);
+  m.Return(m.Int32Div(a0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddSimpleAsAdd) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  // If one of the add's operands is only used once, use an "leal", even though
+  // an "addl" could be used. The "leal" has proven faster--out best guess is
+  // that it gives the register allocation more freedom and it doesn't set
+  // flags, reducing pressure in the CPU's pipeline. If we're lucky with
+  // register allocation, then code generation will select an "addl" later for
+  // the cases that have been measured to be faster.
+  m.Return(m.Int32Add(p0, p1));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddSimpleAsLea) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  // If all of of the add's operands are used multiple times, use an "leal".
+  Node* const v1 = m.Int32Add(p0, p1);
+  m.Return(m.Int32Add(m.Int32Add(v1, p1), p0));
+  Stream s = m.Build();
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  m.Return(m.Int32Add(s0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2Shl) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddCommutedScaled2Shl) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
+  m.Return(m.Int32Add(s0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled4Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled4Shl) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled8Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled8Shl) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3));
+  m.Return(m.Int32Add(p0, s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle1) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(p0, m.Int32Add(s0, c0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle2) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(s0, m.Int32Add(c0, p0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle3) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(m.Int32Add(s0, c0), p0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle4) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(m.Int32Add(c0, p0), s0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2MulWithConstantShuffle5) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(m.Int32Add(p0, s0), c0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2ShlWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(1));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled4MulWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(4));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled4ShlWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(2));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled8MulWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(8));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled8ShlWithConstant) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const s0 = m.Word32Shl(p1, m.Int32Constant(3));
+  Node* const c0 = m.Int32Constant(15);
+  m.Return(m.Int32Add(c0, m.Int32Add(p0, s0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8I, s[0]->addressing_mode());
+  ASSERT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(s[0]->InputAt(2)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubConstantAsSub) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(-1);
+  // If there is only a single use of on of the sub's non-constant input, use a
+  // "subl" instruction.
+  m.Return(m.Int32Sub(p0, c0));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubConstantAsLea) {
+  StreamBuilder m(this, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c0 = m.Int32Constant(-1);
+  // If there are multiple uses of on of the sub's non-constant input, use a
+  // "leal" instruction.
+  Node* const v0 = m.Int32Sub(p0, c0);
+  m.Return(m.Int32Div(p0, v0));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MRI, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate());
+}
+
+
+TEST_F(InstructionSelectorTest, Int32AddScaled2Other) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const p2 = m.Parameter(2);
+  Node* const s0 = m.Int32Mul(p1, m.Int32Constant(2));
+  Node* const a0 = m.Int32Add(s0, p2);
+  Node* const a1 = m.Int32Add(p0, a0);
+  m.Return(a1);
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[0]->OutputAt(0)));
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(kX64Lea32, s[1]->arch_opcode());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(a0), s.ToVreg(s[1]->InputAt(1)));
+  EXPECT_EQ(s.ToVreg(a1), s.ToVreg(s[1]->OutputAt(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Multiplication.
+
+
+TEST_F(InstructionSelectorTest, Int32MulWithInt32MulWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const m0 = m.Int32Mul(p0, p1);
+  m.Return(m.Int32Mul(m0, p0));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kX64Imul32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[0]->OutputAt(0)));
+  EXPECT_EQ(kX64Imul32, s[1]->arch_opcode());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(m0), s.ToVreg(s[1]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32MulHigh) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
+  ASSERT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32MulHigh) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Uint32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64UmulHigh32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
+  ASSERT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul2BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(2);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul3BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(3);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul4BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(4);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul5BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(5);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul8BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(8);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul9BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(9);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Shl.
+
+
+TEST_F(InstructionSelectorTest, Int32Shl1BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(1);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Shl2BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(2);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(3);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Word64Shl.
+
+
+TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt64, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const n = m.Word64Shl(m.ChangeInt32ToInt64(p0), m.Int64Constant(x));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kX64Shl, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64ShlWithChangeUint32ToUint64) {
+  TRACED_FORRANGE(int64_t, x, 32, 63) {
+    StreamBuilder m(this, kMachInt64, kMachUint32);
+    Node* const p0 = m.Parameter(0);
+    Node* const n = m.Word64Shl(m.ChangeUint32ToUint64(p0), m.Int64Constant(x));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kX64Shl, s[0]->arch_opcode());
+    ASSERT_EQ(2U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(x, s.ToInt32(s[0]->InputAt(1)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output()));
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Float64BinopArithmetic) {
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
+    Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
+    Node* mul = m.Float64Mul(add, m.Parameter(1));
+    Node* sub = m.Float64Sub(mul, add);
+    Node* ret = m.Float64Div(mul, sub);
+    m.Return(ret);
+    Stream s = m.Build(AVX);
+    ASSERT_EQ(4U, s.size());
+    EXPECT_EQ(kAVXFloat64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Mul, s[1]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Sub, s[2]->arch_opcode());
+    EXPECT_EQ(kAVXFloat64Div, s[3]->arch_opcode());
+  }
+  {
+    StreamBuilder m(this, kMachFloat64, kMachFloat64, kMachFloat64);
+    Node* add = m.Float64Add(m.Parameter(0), m.Parameter(1));
+    Node* mul = m.Float64Mul(add, m.Parameter(1));
+    Node* sub = m.Float64Sub(mul, add);
+    Node* ret = m.Float64Div(mul, sub);
+    m.Return(ret);
+    Stream s = m.Build();
+    ASSERT_EQ(4U, s.size());
+    EXPECT_EQ(kSSEFloat64Add, s[0]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Mul, s[1]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Sub, s[2]->arch_opcode());
+    EXPECT_EQ(kSSEFloat64Div, s[3]->arch_opcode());
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/zone-pool-unittest.cc b/test/unittests/compiler/zone-pool-unittest.cc
new file mode 100644
index 0000000..e23557a
--- /dev/null
+++ b/test/unittests/compiler/zone-pool-unittest.cc
@@ -0,0 +1,162 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/utils/random-number-generator.h"
+#include "src/compiler/zone-pool.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class ZonePoolTest : public TestWithIsolate {
+ public:
+  ZonePoolTest() : zone_pool_(isolate()) {}
+
+ protected:
+  ZonePool* zone_pool() { return &zone_pool_; }
+
+  void ExpectForPool(size_t current, size_t max, size_t total) {
+    ASSERT_EQ(current, zone_pool()->GetCurrentAllocatedBytes());
+    ASSERT_EQ(max, zone_pool()->GetMaxAllocatedBytes());
+    ASSERT_EQ(total, zone_pool()->GetTotalAllocatedBytes());
+  }
+
+  void Expect(ZonePool::StatsScope* stats, size_t current, size_t max,
+              size_t total) {
+    ASSERT_EQ(current, stats->GetCurrentAllocatedBytes());
+    ASSERT_EQ(max, stats->GetMaxAllocatedBytes());
+    ASSERT_EQ(total, stats->GetTotalAllocatedBytes());
+  }
+
+  size_t Allocate(Zone* zone) {
+    size_t bytes = rng.NextInt(25) + 7;
+    int size_before = zone->allocation_size();
+    zone->New(static_cast<int>(bytes));
+    return static_cast<size_t>(zone->allocation_size() - size_before);
+  }
+
+ private:
+  ZonePool zone_pool_;
+  base::RandomNumberGenerator rng;
+};
+
+
+TEST_F(ZonePoolTest, Empty) {
+  ExpectForPool(0, 0, 0);
+  {
+    ZonePool::StatsScope stats(zone_pool());
+    Expect(&stats, 0, 0, 0);
+  }
+  ExpectForPool(0, 0, 0);
+  {
+    ZonePool::Scope scope(zone_pool());
+    scope.zone();
+  }
+  ExpectForPool(0, 0, 0);
+}
+
+
+TEST_F(ZonePoolTest, MultipleZonesWithDeletion) {
+  static const size_t kArraySize = 10;
+
+  ZonePool::Scope* scopes[kArraySize];
+
+  // Initialize.
+  size_t before_stats = 0;
+  for (size_t i = 0; i < kArraySize; ++i) {
+    scopes[i] = new ZonePool::Scope(zone_pool());
+    before_stats += Allocate(scopes[i]->zone());  // Add some stuff.
+  }
+
+  ExpectForPool(before_stats, before_stats, before_stats);
+
+  ZonePool::StatsScope stats(zone_pool());
+
+  size_t before_deletion = 0;
+  for (size_t i = 0; i < kArraySize; ++i) {
+    before_deletion += Allocate(scopes[i]->zone());  // Add some stuff.
+  }
+
+  Expect(&stats, before_deletion, before_deletion, before_deletion);
+  ExpectForPool(before_stats + before_deletion, before_stats + before_deletion,
+                before_stats + before_deletion);
+
+  // Delete the scopes and create new ones.
+  for (size_t i = 0; i < kArraySize; ++i) {
+    delete scopes[i];
+    scopes[i] = new ZonePool::Scope(zone_pool());
+  }
+
+  Expect(&stats, 0, before_deletion, before_deletion);
+  ExpectForPool(0, before_stats + before_deletion,
+                before_stats + before_deletion);
+
+  size_t after_deletion = 0;
+  for (size_t i = 0; i < kArraySize; ++i) {
+    after_deletion += Allocate(scopes[i]->zone());  // Add some stuff.
+  }
+
+  Expect(&stats, after_deletion, std::max(after_deletion, before_deletion),
+         before_deletion + after_deletion);
+  ExpectForPool(after_deletion,
+                std::max(after_deletion, before_stats + before_deletion),
+                before_stats + before_deletion + after_deletion);
+
+  // Cleanup.
+  for (size_t i = 0; i < kArraySize; ++i) {
+    delete scopes[i];
+  }
+
+  Expect(&stats, 0, std::max(after_deletion, before_deletion),
+         before_deletion + after_deletion);
+  ExpectForPool(0, std::max(after_deletion, before_stats + before_deletion),
+                before_stats + before_deletion + after_deletion);
+}
+
+
+TEST_F(ZonePoolTest, SimpleAllocationLoop) {
+  int runs = 20;
+  size_t total_allocated = 0;
+  size_t max_loop_allocation = 0;
+  ZonePool::StatsScope outer_stats(zone_pool());
+  {
+    ZonePool::Scope outer_scope(zone_pool());
+    size_t outer_allocated = 0;
+    for (int i = 0; i < runs; ++i) {
+      {
+        size_t bytes = Allocate(outer_scope.zone());
+        outer_allocated += bytes;
+        total_allocated += bytes;
+      }
+      ZonePool::StatsScope inner_stats(zone_pool());
+      size_t allocated = 0;
+      {
+        ZonePool::Scope inner_scope(zone_pool());
+        for (int j = 0; j < 20; ++j) {
+          size_t bytes = Allocate(inner_scope.zone());
+          allocated += bytes;
+          total_allocated += bytes;
+          max_loop_allocation =
+              std::max(max_loop_allocation, outer_allocated + allocated);
+          Expect(&inner_stats, allocated, allocated, allocated);
+          Expect(&outer_stats, outer_allocated + allocated, max_loop_allocation,
+                 total_allocated);
+          ExpectForPool(outer_allocated + allocated, max_loop_allocation,
+                        total_allocated);
+        }
+      }
+      Expect(&inner_stats, 0, allocated, allocated);
+      Expect(&outer_stats, outer_allocated, max_loop_allocation,
+             total_allocated);
+      ExpectForPool(outer_allocated, max_loop_allocation, total_allocated);
+    }
+  }
+  Expect(&outer_stats, 0, max_loop_allocation, total_allocated);
+  ExpectForPool(0, max_loop_allocation, total_allocated);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/heap/gc-idle-time-handler-unittest.cc b/test/unittests/heap/gc-idle-time-handler-unittest.cc
new file mode 100644
index 0000000..2076e60
--- /dev/null
+++ b/test/unittests/heap/gc-idle-time-handler-unittest.cc
@@ -0,0 +1,444 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "src/heap/gc-idle-time-handler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+class GCIdleTimeHandlerTest : public ::testing::Test {
+ public:
+  GCIdleTimeHandlerTest() {}
+  virtual ~GCIdleTimeHandlerTest() {}
+
+  GCIdleTimeHandler* handler() { return &handler_; }
+
+  GCIdleTimeHandler::HeapState DefaultHeapState() {
+    GCIdleTimeHandler::HeapState result;
+    result.contexts_disposed = 0;
+    result.contexts_disposal_rate = GCIdleTimeHandler::kHighContextDisposalRate;
+    result.size_of_objects = kSizeOfObjects;
+    result.incremental_marking_stopped = false;
+    result.can_start_incremental_marking = true;
+    result.sweeping_in_progress = false;
+    result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed;
+    result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed;
+    result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed;
+    result.used_new_space_size = 0;
+    result.new_space_capacity = kNewSpaceCapacity;
+    result.new_space_allocation_throughput_in_bytes_per_ms =
+        kNewSpaceAllocationThroughput;
+    return result;
+  }
+
+  static const size_t kSizeOfObjects = 100 * MB;
+  static const size_t kMarkCompactSpeed = 200 * KB;
+  static const size_t kMarkingSpeed = 200 * KB;
+  static const size_t kScavengeSpeed = 100 * KB;
+  static const size_t kNewSpaceCapacity = 1 * MB;
+  static const size_t kNewSpaceAllocationThroughput = 10 * KB;
+
+ private:
+  GCIdleTimeHandler handler_;
+};
+
+}  // namespace
+
+
+TEST(GCIdleTimeHandler, EstimateMarkingStepSizeInitial) {
+  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0);
+  EXPECT_EQ(
+      static_cast<size_t>(GCIdleTimeHandler::kInitialConservativeMarkingSpeed *
+                          GCIdleTimeHandler::kConservativeTimeRatio),
+      step_size);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkingStepSizeNonZero) {
+  size_t marking_speed_in_bytes_per_millisecond = 100;
+  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
+      1, marking_speed_in_bytes_per_millisecond);
+  EXPECT_EQ(static_cast<size_t>(marking_speed_in_bytes_per_millisecond *
+                                GCIdleTimeHandler::kConservativeTimeRatio),
+            step_size);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow1) {
+  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
+      10, std::numeric_limits<size_t>::max());
+  EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
+            step_size);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkingStepSizeOverflow2) {
+  size_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
+      std::numeric_limits<size_t>::max(), 10);
+  EXPECT_EQ(static_cast<size_t>(GCIdleTimeHandler::kMaximumMarkingStepSize),
+            step_size);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkCompactTimeInitial) {
+  size_t size = 100 * MB;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, 0);
+  EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeMarkCompactSpeed,
+            time);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkCompactTimeNonZero) {
+  size_t size = 100 * MB;
+  size_t speed = 1 * MB;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
+  EXPECT_EQ(size / speed, time);
+}
+
+
+TEST(GCIdleTimeHandler, EstimateMarkCompactTimeMax) {
+  size_t size = std::numeric_limits<size_t>::max();
+  size_t speed = 1;
+  size_t time = GCIdleTimeHandler::EstimateMarkCompactTime(size, speed);
+  EXPECT_EQ(GCIdleTimeHandler::kMaxMarkCompactTimeInMs, time);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeEmptyNewSpace) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  int idle_time_in_ms = 16;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeFullNewSpace) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.used_new_space_size = kNewSpaceCapacity;
+  int idle_time_in_ms = 16;
+  EXPECT_TRUE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeUnknownScavengeSpeed) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.used_new_space_size = kNewSpaceCapacity;
+  heap_state.scavenge_speed_in_bytes_per_ms = 0;
+  int idle_time_in_ms = 16;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeLowScavengeSpeed) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.used_new_space_size = kNewSpaceCapacity;
+  heap_state.scavenge_speed_in_bytes_per_ms = 1 * KB;
+  int idle_time_in_ms = 16;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DoScavengeHighScavengeSpeed) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.used_new_space_size = kNewSpaceCapacity;
+  heap_state.scavenge_speed_in_bytes_per_ms = kNewSpaceCapacity;
+  int idle_time_in_ms = 16;
+  EXPECT_TRUE(GCIdleTimeHandler::ShouldDoScavenge(
+      idle_time_in_ms, heap_state.new_space_capacity,
+      heap_state.used_new_space_size, heap_state.scavenge_speed_in_bytes_per_ms,
+      heap_state.new_space_allocation_throughput_in_bytes_per_ms));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ShouldDoMarkCompact) {
+  size_t idle_time_in_ms = 16;
+  EXPECT_TRUE(GCIdleTimeHandler::ShouldDoMarkCompact(idle_time_in_ms, 0, 0));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DontDoMarkCompact) {
+  size_t idle_time_in_ms = 1;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoMarkCompact(
+      idle_time_in_ms, kSizeOfObjects, kMarkingSpeed));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ShouldDoFinalIncrementalMarkCompact) {
+  size_t idle_time_in_ms = 16;
+  EXPECT_TRUE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
+      idle_time_in_ms, 0, 0));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, DontDoFinalIncrementalMarkCompact) {
+  size_t idle_time_in_ms = 1;
+  EXPECT_FALSE(GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
+      idle_time_in_ms, kSizeOfObjects, kMarkingSpeed));
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.incremental_marking_stopped = true;
+  double idle_time_ms = 0;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate =
+      GCIdleTimeHandler::kHighContextDisposalRate - 1;
+  heap_state.incremental_marking_stopped = true;
+  double idle_time_ms = 0;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_FULL_GC, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeIdleTime) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate = 1.0;
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>((heap_state.size_of_objects + speed - 1) / speed);
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_FULL_GC, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate = 1.0;
+  heap_state.incremental_marking_stopped = true;
+  double idle_time_ms = 0;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_FULL_GC, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate = 1.0;
+  heap_state.incremental_marking_stopped = true;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed - 1);
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.contexts_disposed = 1;
+  heap_state.contexts_disposal_rate = 1.0;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed - 1);
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
+  double idle_time_ms = 10;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+  EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
+            static_cast<size_t>(action.parameter));
+  EXPECT_LT(0, action.parameter);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.incremental_marking_stopped = true;
+  size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
+  double idle_time_ms = 10;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+  EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
+            static_cast<size_t>(action.parameter));
+  EXPECT_LT(0, action.parameter);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed - 1);
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, StopEventually1) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed + 1);
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_FULL_GC, action.type);
+    handler()->NotifyIdleMarkCompact();
+  }
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, StopEventually2) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  double idle_time_ms = 10;
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+    // In this case we emulate incremental marking steps that finish with a
+    // full gc.
+    handler()->NotifyIdleMarkCompact();
+  }
+  heap_state.can_start_incremental_marking = false;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  heap_state.incremental_marking_stopped = true;
+  heap_state.can_start_incremental_marking = false;
+  size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
+  double idle_time_ms =
+      static_cast<double>(heap_state.size_of_objects / speed + 1);
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    EXPECT_EQ(DO_FULL_GC, action.type);
+    handler()->NotifyIdleMarkCompact();
+  }
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+  // Emulate mutator work.
+  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
+    handler()->NotifyScavenge();
+  }
+  action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_FULL_GC, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  double idle_time_ms = 10;
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    if (action.type == DONE) break;
+    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+    // In this case we try to emulate incremental marking steps the finish with
+    // a full gc.
+    handler()->NotifyIdleMarkCompact();
+  }
+  heap_state.can_start_incremental_marking = false;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DONE, action.type);
+  // Emulate mutator work.
+  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
+    handler()->NotifyScavenge();
+  }
+  heap_state.can_start_incremental_marking = true;
+  action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, Scavenge) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  int idle_time_ms = 10;
+  heap_state.used_new_space_size =
+      heap_state.new_space_capacity -
+      (kNewSpaceAllocationThroughput * idle_time_ms);
+  GCIdleTimeAction action =
+      handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
+  EXPECT_EQ(DO_SCAVENGE, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  int idle_time_ms = 10;
+  heap_state.can_start_incremental_marking = false;
+  heap_state.incremental_marking_stopped = true;
+  heap_state.used_new_space_size =
+      heap_state.new_space_capacity -
+      (kNewSpaceAllocationThroughput * idle_time_ms);
+  GCIdleTimeAction action =
+      handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
+  EXPECT_EQ(DO_SCAVENGE, action.type);
+  heap_state.used_new_space_size = 0;
+  action = handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  double idle_time_ms = 0;
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+
+TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeDoNothingButStartIdleRound) {
+  GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
+  double idle_time_ms = 10;
+  for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
+    GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+    if (action.type == DONE) break;
+    EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
+    // In this case we try to emulate incremental marking steps the finish with
+    // a full gc.
+    handler()->NotifyIdleMarkCompact();
+  }
+  GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
+  // Emulate mutator work.
+  for (int i = 0; i < GCIdleTimeHandler::kIdleScavengeThreshold; i++) {
+    handler()->NotifyScavenge();
+  }
+  action = handler()->Compute(0, heap_state);
+  EXPECT_EQ(DO_NOTHING, action.type);
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/libplatform/default-platform-unittest.cc b/test/unittests/libplatform/default-platform-unittest.cc
new file mode 100644
index 0000000..d2c160e
--- /dev/null
+++ b/test/unittests/libplatform/default-platform-unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/libplatform/default-platform.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::InSequence;
+using testing::StrictMock;
+
+namespace v8 {
+namespace platform {
+
+namespace {
+
+struct MockTask : public Task {
+  virtual ~MockTask() { Die(); }
+  MOCK_METHOD0(Run, void());
+  MOCK_METHOD0(Die, void());
+};
+
+}  // namespace
+
+
+TEST(DefaultPlatformTest, PumpMessageLoop) {
+  InSequence s;
+
+  int dummy;
+  Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
+
+  DefaultPlatform platform;
+  EXPECT_FALSE(platform.PumpMessageLoop(isolate));
+
+  StrictMock<MockTask>* task = new StrictMock<MockTask>;
+  platform.CallOnForegroundThread(isolate, task);
+  EXPECT_CALL(*task, Run());
+  EXPECT_CALL(*task, Die());
+  EXPECT_TRUE(platform.PumpMessageLoop(isolate));
+  EXPECT_FALSE(platform.PumpMessageLoop(isolate));
+}
+
+}  // namespace platform
+}  // namespace v8
diff --git a/test/unittests/libplatform/task-queue-unittest.cc b/test/unittests/libplatform/task-queue-unittest.cc
new file mode 100644
index 0000000..9a18658
--- /dev/null
+++ b/test/unittests/libplatform/task-queue-unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/v8-platform.h"
+#include "src/base/platform/platform.h"
+#include "src/libplatform/task-queue.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::InSequence;
+using testing::IsNull;
+using testing::StrictMock;
+
+namespace v8 {
+namespace platform {
+
+namespace {
+
+struct MockTask : public Task {
+  MOCK_METHOD0(Run, void());
+};
+
+
+class TaskQueueThread FINAL : public base::Thread {
+ public:
+  explicit TaskQueueThread(TaskQueue* queue)
+      : Thread(Options("libplatform TaskQueueThread")), queue_(queue) {}
+
+  virtual void Run() OVERRIDE { EXPECT_THAT(queue_->GetNext(), IsNull()); }
+
+ private:
+  TaskQueue* queue_;
+};
+
+}  // namespace
+
+
+TEST(TaskQueueTest, Basic) {
+  TaskQueue queue;
+  MockTask task;
+  queue.Append(&task);
+  EXPECT_EQ(&task, queue.GetNext());
+  queue.Terminate();
+  EXPECT_THAT(queue.GetNext(), IsNull());
+}
+
+
+TEST(TaskQueueTest, TerminateMultipleReaders) {
+  TaskQueue queue;
+  TaskQueueThread thread1(&queue);
+  TaskQueueThread thread2(&queue);
+  thread1.Start();
+  thread2.Start();
+  queue.Terminate();
+  thread1.Join();
+  thread2.Join();
+}
+
+}  // namespace platform
+}  // namespace v8
diff --git a/test/unittests/libplatform/worker-thread-unittest.cc b/test/unittests/libplatform/worker-thread-unittest.cc
new file mode 100644
index 0000000..175b311
--- /dev/null
+++ b/test/unittests/libplatform/worker-thread-unittest.cc
@@ -0,0 +1,48 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/v8-platform.h"
+#include "src/libplatform/task-queue.h"
+#include "src/libplatform/worker-thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::InSequence;
+using testing::IsNull;
+using testing::StrictMock;
+
+namespace v8 {
+namespace platform {
+
+namespace {
+
+struct MockTask : public Task {
+  virtual ~MockTask() { Die(); }
+  MOCK_METHOD0(Run, void());
+  MOCK_METHOD0(Die, void());
+};
+
+}  // namespace
+
+
+TEST(WorkerThreadTest, Basic) {
+  static const size_t kNumTasks = 10;
+
+  TaskQueue queue;
+  for (size_t i = 0; i < kNumTasks; ++i) {
+    InSequence s;
+    StrictMock<MockTask>* task = new StrictMock<MockTask>;
+    EXPECT_CALL(*task, Run());
+    EXPECT_CALL(*task, Die());
+    queue.Append(task);
+  }
+
+  WorkerThread thread1(&queue);
+  WorkerThread thread2(&queue);
+
+  // TaskQueue DCHECKS that it's empty in its destructor.
+  queue.Terminate();
+}
+
+}  // namespace platform
+}  // namespace v8
diff --git a/test/unittests/run-all-unittests.cc b/test/unittests/run-all-unittests.cc
new file mode 100644
index 0000000..8c361dd
--- /dev/null
+++ b/test/unittests/run-all-unittests.cc
@@ -0,0 +1,45 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/libplatform/libplatform.h"
+#include "include/v8.h"
+#include "src/base/compiler-specific.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace {
+
+class DefaultPlatformEnvironment FINAL : public ::testing::Environment {
+ public:
+  DefaultPlatformEnvironment() : platform_(NULL) {}
+  ~DefaultPlatformEnvironment() {}
+
+  virtual void SetUp() OVERRIDE {
+    EXPECT_EQ(NULL, platform_);
+    platform_ = v8::platform::CreateDefaultPlatform();
+    ASSERT_TRUE(platform_ != NULL);
+    v8::V8::InitializePlatform(platform_);
+    ASSERT_TRUE(v8::V8::Initialize());
+  }
+
+  virtual void TearDown() OVERRIDE {
+    ASSERT_TRUE(platform_ != NULL);
+    v8::V8::Dispose();
+    v8::V8::ShutdownPlatform();
+    delete platform_;
+    platform_ = NULL;
+  }
+
+ private:
+  v8::Platform* platform_;
+};
+
+}  // namespace
+
+
+int main(int argc, char** argv) {
+  testing::InitGoogleMock(&argc, argv);
+  testing::AddGlobalTestEnvironment(new DefaultPlatformEnvironment);
+  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/unittests/test-utils.cc b/test/unittests/test-utils.cc
new file mode 100644
index 0000000..31d724a
--- /dev/null
+++ b/test/unittests/test-utils.cc
@@ -0,0 +1,109 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "test/unittests/test-utils.h"
+
+#include "src/base/platform/time.h"
+#include "src/flags.h"
+#include "src/isolate-inl.h"
+
+namespace v8 {
+
+std::ostream& operator<<(std::ostream& os, ExternalArrayType type) {
+  switch (type) {
+    case kExternalInt8Array:
+      return os << "ExternalInt8Array";
+    case kExternalUint8Array:
+      return os << "ExternalUint8Array";
+    case kExternalInt16Array:
+      return os << "ExternalInt16Array";
+    case kExternalUint16Array:
+      return os << "ExternalUint16Array";
+    case kExternalInt32Array:
+      return os << "ExternalInt32Array";
+    case kExternalUint32Array:
+      return os << "ExternalUint32Array";
+    case kExternalFloat32Array:
+      return os << "ExternalFloat32Array";
+    case kExternalFloat64Array:
+      return os << "ExternalFloat64Array";
+    case kExternalUint8ClampedArray:
+      return os << "ExternalUint8ClampedArray";
+  }
+  UNREACHABLE();
+  return os;
+}
+
+
+// static
+Isolate* TestWithIsolate::isolate_ = NULL;
+
+
+TestWithIsolate::TestWithIsolate()
+    : isolate_scope_(isolate()), handle_scope_(isolate()) {}
+
+
+TestWithIsolate::~TestWithIsolate() {}
+
+
+// static
+void TestWithIsolate::SetUpTestCase() {
+  Test::SetUpTestCase();
+  EXPECT_EQ(NULL, isolate_);
+  isolate_ = v8::Isolate::New();
+  EXPECT_TRUE(isolate_ != NULL);
+}
+
+
+// static
+void TestWithIsolate::TearDownTestCase() {
+  ASSERT_TRUE(isolate_ != NULL);
+  isolate_->Dispose();
+  isolate_ = NULL;
+  Test::TearDownTestCase();
+}
+
+
+TestWithContext::TestWithContext()
+    : context_(Context::New(isolate())), context_scope_(context_) {}
+
+
+TestWithContext::~TestWithContext() {}
+
+
+namespace base {
+namespace {
+
+inline int64_t GetRandomSeedFromFlag(int random_seed) {
+  return random_seed ? random_seed : TimeTicks::Now().ToInternalValue();
+}
+
+}  // namespace
+
+TestWithRandomNumberGenerator::TestWithRandomNumberGenerator()
+    : rng_(GetRandomSeedFromFlag(internal::FLAG_random_seed)) {}
+
+
+TestWithRandomNumberGenerator::~TestWithRandomNumberGenerator() {}
+
+}  // namespace base
+
+
+namespace internal {
+
+TestWithIsolate::~TestWithIsolate() {}
+
+
+Factory* TestWithIsolate::factory() const { return isolate()->factory(); }
+
+
+base::RandomNumberGenerator* TestWithIsolate::random_number_generator() const {
+  return isolate()->random_number_generator();
+}
+
+
+TestWithZone::~TestWithZone() {}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/test-utils.h b/test/unittests/test-utils.h
new file mode 100644
index 0000000..511e357
--- /dev/null
+++ b/test/unittests/test-utils.h
@@ -0,0 +1,109 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UNITTESTS_TEST_UTILS_H_
+#define V8_UNITTESTS_TEST_UTILS_H_
+
+#include "include/v8.h"
+#include "src/base/macros.h"
+#include "src/base/utils/random-number-generator.h"
+#include "src/zone.h"
+#include "testing/gtest-support.h"
+
+namespace v8 {
+
+std::ostream& operator<<(std::ostream&, ExternalArrayType);
+
+
+class TestWithIsolate : public ::testing::Test {
+ public:
+  TestWithIsolate();
+  virtual ~TestWithIsolate();
+
+  Isolate* isolate() const { return isolate_; }
+
+  static void SetUpTestCase();
+  static void TearDownTestCase();
+
+ private:
+  static Isolate* isolate_;
+  Isolate::Scope isolate_scope_;
+  HandleScope handle_scope_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWithIsolate);
+};
+
+
+class TestWithContext : public virtual TestWithIsolate {
+ public:
+  TestWithContext();
+  virtual ~TestWithContext();
+
+  const Local<Context>& context() const { return context_; }
+
+ private:
+  Local<Context> context_;
+  Context::Scope context_scope_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWithContext);
+};
+
+
+namespace base {
+
+class TestWithRandomNumberGenerator : public ::testing::Test {
+ public:
+  TestWithRandomNumberGenerator();
+  virtual ~TestWithRandomNumberGenerator();
+
+  RandomNumberGenerator* rng() { return &rng_; }
+
+ private:
+  RandomNumberGenerator rng_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWithRandomNumberGenerator);
+};
+
+}  // namespace base
+
+
+namespace internal {
+
+// Forward declarations.
+class Factory;
+
+
+class TestWithIsolate : public virtual ::v8::TestWithIsolate {
+ public:
+  TestWithIsolate() {}
+  virtual ~TestWithIsolate();
+
+  Factory* factory() const;
+  Isolate* isolate() const {
+    return reinterpret_cast<Isolate*>(::v8::TestWithIsolate::isolate());
+  }
+  base::RandomNumberGenerator* random_number_generator() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestWithIsolate);
+};
+
+
+class TestWithZone : public TestWithIsolate {
+ public:
+  TestWithZone() : zone_(isolate()) {}
+  virtual ~TestWithZone();
+
+  Zone* zone() { return &zone_; }
+
+ private:
+  Zone zone_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWithZone);
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_UNITTESTS_TEST_UTILS_H_
diff --git a/test/unittests/unittests.gyp b/test/unittests/unittests.gyp
new file mode 100644
index 0000000..2ead44f
--- /dev/null
+++ b/test/unittests/unittests.gyp
@@ -0,0 +1,140 @@
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'v8_code': 1,
+  },
+  'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
+  'targets': [
+    {
+      'target_name': 'unittests',
+      'type': 'executable',
+      'variables': {
+        'optimize': 'max',
+      },
+      'dependencies': [
+        '../../testing/gmock.gyp:gmock',
+        '../../testing/gtest.gyp:gtest',
+        '../../tools/gyp/v8.gyp:v8_libplatform',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'sources': [  ### gcmole(all) ###
+        'base/bits-unittest.cc',
+        'base/cpu-unittest.cc',
+        'base/division-by-constant-unittest.cc',
+        'base/flags-unittest.cc',
+        'base/functional-unittest.cc',
+        'base/iterator-unittest.cc',
+        'base/platform/condition-variable-unittest.cc',
+        'base/platform/mutex-unittest.cc',
+        'base/platform/platform-unittest.cc',
+        'base/platform/semaphore-unittest.cc',
+        'base/platform/time-unittest.cc',
+        'base/sys-info-unittest.cc',
+        'base/utils/random-number-generator-unittest.cc',
+        'char-predicates-unittest.cc',
+        'compiler/change-lowering-unittest.cc',
+        'compiler/common-operator-reducer-unittest.cc',
+        'compiler/common-operator-unittest.cc',
+        'compiler/compiler-test-utils.h',
+        'compiler/control-equivalence-unittest.cc',
+        'compiler/diamond-unittest.cc',
+        'compiler/graph-reducer-unittest.cc',
+        'compiler/graph-unittest.cc',
+        'compiler/graph-unittest.h',
+        'compiler/instruction-selector-unittest.cc',
+        'compiler/instruction-selector-unittest.h',
+        'compiler/instruction-sequence-unittest.cc',
+        'compiler/instruction-sequence-unittest.h',
+        'compiler/js-builtin-reducer-unittest.cc',
+        'compiler/js-operator-unittest.cc',
+        'compiler/js-typed-lowering-unittest.cc',
+        'compiler/load-elimination-unittest.cc',
+        'compiler/machine-operator-reducer-unittest.cc',
+        'compiler/machine-operator-unittest.cc',
+        'compiler/move-optimizer-unittest.cc',
+        'compiler/node-matchers-unittest.cc',
+        'compiler/node-test-utils.cc',
+        'compiler/node-test-utils.h',
+        'compiler/register-allocator-unittest.cc',
+        'compiler/select-lowering-unittest.cc',
+        'compiler/simplified-operator-reducer-unittest.cc',
+        'compiler/simplified-operator-unittest.cc',
+        'compiler/value-numbering-reducer-unittest.cc',
+        'compiler/zone-pool-unittest.cc',
+        'libplatform/default-platform-unittest.cc',
+        'libplatform/task-queue-unittest.cc',
+        'libplatform/worker-thread-unittest.cc',
+        'heap/gc-idle-time-handler-unittest.cc',
+        'run-all-unittests.cc',
+        'test-utils.h',
+        'test-utils.cc',
+      ],
+      'conditions': [
+        ['v8_target_arch=="arm"', {
+          'sources': [  ### gcmole(arch:arm) ###
+            'compiler/arm/instruction-selector-arm-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="arm64"', {
+          'sources': [  ### gcmole(arch:arm64) ###
+            'compiler/arm64/instruction-selector-arm64-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="ia32"', {
+          'sources': [  ### gcmole(arch:ia32) ###
+            'compiler/ia32/instruction-selector-ia32-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="mipsel"', {
+          'sources': [  ### gcmole(arch:mipsel) ###
+            'compiler/mips/instruction-selector-mips-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="mips64el"', {
+          'sources': [  ### gcmole(arch:mips64el) ###
+            'compiler/mips64/instruction-selector-mips64-unittest.cc',
+          ],
+        }],
+        ['v8_target_arch=="x64"', {
+          'sources': [  ### gcmole(arch:x64) ###
+            'compiler/x64/instruction-selector-x64-unittest.cc',
+          ],
+        }],
+        ['component=="shared_library"', {
+          # compiler-unittests can't be built against a shared library, so we
+          # need to depend on the underlying static target in that case.
+          'conditions': [
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==0', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
+            }],
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==1', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_external_snapshot'],
+            }],
+            ['v8_use_snapshot!="true"', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_nosnapshot'],
+            }],
+          ],
+        }, {
+          'dependencies': ['../../tools/gyp/v8.gyp:v8'],
+        }],
+        ['os_posix == 1', {
+          # TODO(svenpanne): This is a temporary work-around to fix the warnings
+          # that show up because we use -std=gnu++0x instead of -std=c++11.
+          'cflags!': [
+            '-pedantic',
+          ],
+          'direct_dependent_settings': {
+            'cflags!': [
+              '-pedantic',
+            ],
+          },
+        }],
+      ],
+    },
+  ],
+}
diff --git a/test/base-unittests/base-unittests.status b/test/unittests/unittests.status
similarity index 100%
rename from test/base-unittests/base-unittests.status
rename to test/unittests/unittests.status
diff --git a/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt b/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
index 030d7f9..0e00f23 100644
--- a/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
+++ b/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
@@ -1,25 +1,6 @@
-# Copyright 2013 the V8 project authors. All rights reserved.
-# Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1.  Redistributions of source code must retain the above copyright
-#     notice, this list of conditions and the following disclaimer.
-# 2.  Redistributions in binary form must reproduce the above copyright
-#     notice, this list of conditions and the following disclaimer in the
-#     documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# Copyright 2014 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 Test to ensure correct behaviour of Object.getOwnPropertyNames
 
@@ -69,8 +50,8 @@
 PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toString']
 PASS getSortedOwnPropertyNames(Array) is ['arguments', 'caller', 'isArray', 'length', 'name', 'observe', 'prototype', 'unobserve']
 PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'filter', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
-PASS getSortedOwnPropertyNames(String) is ['arguments', 'caller', 'fromCharCode', 'length', 'name', 'prototype']
-PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
+PASS getSortedOwnPropertyNames(String) is ['arguments', 'caller', 'fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']
+PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
 PASS getSortedOwnPropertyNames(Boolean) is ['arguments', 'caller', 'length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(Boolean.prototype) is ['constructor', 'toString', 'valueOf']
 PASS getSortedOwnPropertyNames(Number) is ['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'arguments', 'caller', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']
diff --git a/test/webkit/fast/js/Object-getOwnPropertyNames.js b/test/webkit/fast/js/Object-getOwnPropertyNames.js
index caa0111..72bd21b 100644
--- a/test/webkit/fast/js/Object-getOwnPropertyNames.js
+++ b/test/webkit/fast/js/Object-getOwnPropertyNames.js
@@ -77,8 +77,8 @@
     "Function.prototype": "['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toString']",
     "Array": "['arguments', 'caller', 'isArray', 'length', 'name', 'observe', 'prototype', 'unobserve']",
     "Array.prototype": "['concat', 'constructor', 'entries', 'every', 'filter', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']",
-    "String": "['arguments', 'caller', 'fromCharCode', 'length', 'name', 'prototype']",
-    "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
+    "String": "['arguments', 'caller', 'fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']",
+    "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
     "Boolean": "['arguments', 'caller', 'length', 'name', 'prototype']",
     "Boolean.prototype": "['constructor', 'toString', 'valueOf']",
     "Number": "['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'arguments', 'caller', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']",
diff --git a/test/webkit/fast/js/basic-strict-mode-expected.txt b/test/webkit/fast/js/basic-strict-mode-expected.txt
index 45f71bf..0e6228e 100644
--- a/test/webkit/fast/js/basic-strict-mode-expected.txt
+++ b/test/webkit/fast/js/basic-strict-mode-expected.txt
@@ -129,7 +129,7 @@
 PASS (function(){(function (){ 'use strict'; delete someDeclaredGlobal;})}) threw exception SyntaxError: Delete of an unqualified identifier in strict mode..
 PASS 'use strict'; if (0) { someGlobal = 'Shouldn\'t be able to assign this.'; }; true; is true
 PASS 'use strict'; someGlobal = 'Shouldn\'t be able to assign this.';  threw exception ReferenceError: someGlobal is not defined.
-FAIL 'use strict'; (function f(){ f = 'shouldn\'t be able to assign to function expression name'; })() should throw an exception. Was undefined.
+PASS 'use strict'; (function f(){ f = 'shouldn\'t be able to assign to function expression name'; })() threw exception TypeError: Assignment to constant variable..
 PASS 'use strict'; eval('var introducedVariable = "FAIL: variable introduced into containing scope";'); introducedVariable threw exception ReferenceError: introducedVariable is not defined.
 PASS 'use strict'; objectWithReadonlyProperty.prop = 'fail' threw exception TypeError: Cannot assign to read only property 'prop' of #<Object>.
 PASS 'use strict'; delete objectWithReadonlyProperty.prop threw exception TypeError: Cannot delete property 'prop' of #<Object>.
diff --git a/test/webkit/fast/regex/toString-expected.txt b/test/webkit/fast/regex/toString-expected.txt
index a6eefd9..1024072 100644
--- a/test/webkit/fast/regex/toString-expected.txt
+++ b/test/webkit/fast/regex/toString-expected.txt
@@ -26,23 +26,23 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-FAIL RegExp('/').source should be \/. Was /.
+PASS RegExp('/').source is "\\/"
 PASS RegExp('').source is "(?:)"
 PASS RegExp.prototype.source is "(?:)"
-FAIL RegExp('/').toString() should be /\//. Was ///.
+PASS RegExp('/').toString() is "/\\//"
 PASS RegExp('').toString() is "/(?:)/"
 PASS RegExp.prototype.toString() is "/(?:)/"
-FAIL testForwardSlash("^/$", "/"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("^/$", "/"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("^\/$", "/"); should be true. Threw exception SyntaxError: Unexpected end of input
+PASS testForwardSlash("^/$", "/"); is true
+PASS testForwardSlash("^/$", "/"); is true
+PASS testForwardSlash("^\/$", "/"); is true
 PASS testForwardSlash("^\\/$", "\/"); is true
 PASS testForwardSlash("^\\\/$", "\/"); is true
 FAIL testForwardSlash("^\\\\/$", "\\/"); should be true. Threw exception SyntaxError: Unexpected end of input
 FAIL testForwardSlash("^\\\\\/$", "\\/"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("x/x/x", "x\/x\/x"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("x\/x/x", "x\/x\/x"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("x/x\/x", "x\/x\/x"); should be true. Threw exception SyntaxError: Unexpected end of input
-FAIL testForwardSlash("x\/x\/x", "x\/x\/x"); should be true. Threw exception SyntaxError: Unexpected end of input
+PASS testForwardSlash("x/x/x", "x\/x\/x"); is true
+PASS testForwardSlash("x\/x/x", "x\/x\/x"); is true
+PASS testForwardSlash("x/x\/x", "x\/x\/x"); is true
+PASS testForwardSlash("x\/x\/x", "x\/x\/x"); is true
 FAIL testLineTerminator("\n"); should be false. Was true.
 PASS testLineTerminator("\\n"); is false
 FAIL testLineTerminator("\r"); should be false. Was true.
@@ -51,8 +51,8 @@
 PASS testLineTerminator("\\u2028"); is false
 FAIL testLineTerminator("\u2029"); should be false. Was true.
 PASS testLineTerminator("\\u2029"); is false
-PASS RegExp('[/]').source is '[/]'
-FAIL RegExp('\\[/]').source should be \[\/]. Was \[/].
+FAIL RegExp('[/]').source should be [/]. Was [\/].
+PASS RegExp('\\[/]').source is '\\[\\/]'
 PASS var o = new RegExp(); o.toString() === '/'+o.source+'/' && eval(o.toString()+'.exec(String())') is [""]
 PASS successfullyParsed is true
 
diff --git a/test/webkit/testcfg.py b/test/webkit/testcfg.py
index e4e3f8f..aa81964 100644
--- a/test/webkit/testcfg.py
+++ b/test/webkit/testcfg.py
@@ -109,7 +109,11 @@
             string.startswith("tools/nacl-run.py") or
             string.find("BYPASSING ALL ACL CHECKS") > 0 or
             string.find("Native Client module will be loaded") > 0 or
-            string.find("NaClHostDescOpen:") > 0)
+            string.find("NaClHostDescOpen:") > 0 or
+            # FIXME(machenbach): The test driver shouldn't try to use slow
+            # asserts if they weren't compiled. This fails in optdebug=2.
+            string == "Warning: unknown flag --enable-slow-asserts." or
+            string == "Try --help for options")
 
   def IsFailureOutput(self, output, testpath):
     if super(WebkitTestSuite, self).IsFailureOutput(output, testpath):
diff --git a/test/webkit/webkit.status b/test/webkit/webkit.status
index 3bb6574..c33f1b9 100644
--- a/test/webkit/webkit.status
+++ b/test/webkit/webkit.status
@@ -44,13 +44,23 @@
   'dfg-double-vote-fuzz': [SKIP],
   'reentrant-caching': [SKIP],
   'sort-large-array': [SKIP],
+  # Too slow on windows with --nocrankshaft.
+  # TODO(mstarzinger): Too slow with TF.
+  'array-iterate-backwards': [PASS, NO_VARIANTS],
 }],  # 'mode == debug'
 ['simulator', {
+  # Skip tests that timeout with turbofan.
+  'dfg-int-overflow-in-loop': [PASS, NO_VARIANTS],
+  'array-iterate-backwards': [PASS, NO_VARIANTS],
   'function-apply-aliased': [SKIP],
 }],  # 'simulator'
 ['arch == arm64 and simulator_run == True', {
   'dfg-int-overflow-in-loop': [SKIP],
 }],  # 'arch == arm64 and simulator_run == True'
+['dcheck_always_on == True and arch == arm64', {
+  # Doesn't work with gcc 4.6 on arm64 for some reason.
+  'reentrant-caching': [SKIP],
+}],  # 'dcheck_always_on == True and arch == arm64'
 
 
 ##############################################################################
@@ -59,5 +69,10 @@
   'fast/js/excessive-comma-usage': [SKIP]
 }],  # 'gc_stress == True'
 
+['gc_stress == True and mode == debug', {
+  # Skip tests that timeout.
+  'array-iterate-backwards': [SKIP]
+}],  # 'gc_stress == True and mode == debug'
+
 ##############################################################################
 ]