From 4efc428ce0b744d3ec76529547577534223f7210 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Sun, 15 Nov 2015 02:11:41 +0100
Subject: [PATCH] Deploy 0.6.40

---
 README.md    |    4 +-
 bower.json   |    2 +-
 package.json |    2 +-
 y.js         | 6724 ++++++++++++++++++++++++++++++++++++--------------
 4 files changed, 4832 insertions(+), 1900 deletions(-)

diff --git a/README.md b/README.md
index 7aae0f54..d85afb34 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,8 @@ You can create you own shared types easily. Therefore, you can take matters into
 | Name     | Description       |
 |----------|-------------------|
 | map     | Add, update, and remove properties of an object. Included in Yjs|
-|[list](https://github.com/y-js/y-list) | A shared linked list implementation |
-|[selections](https://github.com/y-js/y-selections) | Manages selections on types that use linear structures (e.g. the y-list type). Select a range of elements, and assign meaning to them.|
+|[array](https://github.com/y-js/y-array) | A shared linked list implementation |
+|[selections](https://github.com/y-js/y-selections) | Manages selections on types that use linear structures (e.g. the y-array type). Select a range of elements, and assign meaning to them.|
 |[xml](https://github.com/y-js/y-xml) | An implementation of the DOM. You can create a two way binding to Browser DOM objects|
 |[text](https://github.com/y-js/y-text) | Collaborate on text. Supports two way binding to textareas, input elements, or HTML elements (e.g. *h1*, or *p*)|
 |[richtext](https://github.com/y-js/y-richtext) | Collaborate on rich text. Supports two way binding to several editors|
diff --git a/bower.json b/bower.json
index a5a2dea6..a1265998 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "0.6.35",
+  "version": "0.6.36",
   "homepage": "y-js.org",
   "authors": [
     "Kevin Jahns <kevin.jahns@rwth-aachen.de>"
diff --git a/package.json b/package.json
index 7a971ddf..67bfce73 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "yjs",
-  "version": "0.6.35",
+  "version": "0.6.36",
   "description": "A framework for real-time p2p shared editing on arbitrary complex data types",
   "main": "y.js",
   "scripts": {
diff --git a/y.js b/y.js
index e2db4419..bf116378 100644
--- a/y.js
+++ b/y.js
@@ -1,483 +1,1565 @@
 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-'use strict'
+// shim for using process in browser
+
+var process = module.exports = {};
+var queue = [];
+var draining = false;
+var currentQueue;
+var queueIndex = -1;
+
+function cleanUpNextTick() {
+    draining = false;
+    if (currentQueue.length) {
+        queue = currentQueue.concat(queue);
+    } else {
+        queueIndex = -1;
+    }
+    if (queue.length) {
+        drainQueue();
+    }
+}
+
+function drainQueue() {
+    if (draining) {
+        return;
+    }
+    var timeout = setTimeout(cleanUpNextTick);
+    draining = true;
+
+    var len = queue.length;
+    while(len) {
+        currentQueue = queue;
+        queue = [];
+        while (++queueIndex < len) {
+            if (currentQueue) {
+                currentQueue[queueIndex].run();
+            }
+        }
+        queueIndex = -1;
+        len = queue.length;
+    }
+    currentQueue = null;
+    draining = false;
+    clearTimeout(timeout);
+}
+
+process.nextTick = function (fun) {
+    var args = new Array(arguments.length - 1);
+    if (arguments.length > 1) {
+        for (var i = 1; i < arguments.length; i++) {
+            args[i - 1] = arguments[i];
+        }
+    }
+    queue.push(new Item(fun, args));
+    if (queue.length === 1 && !draining) {
+        setTimeout(drainQueue, 0);
+    }
+};
+
+// v8 likes predictible objects
+function Item(fun, array) {
+    this.fun = fun;
+    this.array = array;
+}
+Item.prototype.run = function () {
+    this.fun.apply(null, this.array);
+};
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+process.version = ''; // empty string to avoid regexp issues
+process.versions = {};
+
+function noop() {}
+
+process.on = noop;
+process.addListener = noop;
+process.once = noop;
+process.off = noop;
+process.removeListener = noop;
+process.removeAllListeners = noop;
+process.emit = noop;
+
+process.binding = function (name) {
+    throw new Error('process.binding is not supported');
+};
+
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+    throw new Error('process.chdir is not supported');
+};
+process.umask = function() { return 0; };
+
+},{}],2:[function(require,module,exports){
+(function (process,global){
+"use strict";
+
+function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
+
+/**
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * https://raw.github.com/facebook/regenerator/master/LICENSE file. An
+ * additional grant of patent rights can be found in the PATENTS file in
+ * the same directory.
+ */
+
+!(function (global) {
+  "use strict";
+
+  var hasOwn = Object.prototype.hasOwnProperty;
+  var undefined; // More compressible than void 0.
+  var $Symbol = typeof Symbol === "function" ? Symbol : {};
+  var iteratorSymbol = $Symbol.iterator || "@@iterator";
+  var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
+
+  var inModule = (typeof module === "undefined" ? "undefined" : _typeof(module)) === "object";
+  var runtime = global.regeneratorRuntime;
+  if (runtime) {
+    if (inModule) {
+      // If regeneratorRuntime is defined globally and we're in a module,
+      // make the exports object identical to regeneratorRuntime.
+      module.exports = runtime;
+    }
+    // Don't bother evaluating the rest of this file if the runtime was
+    // already defined globally.
+    return;
+  }
+
+  // Define the runtime globally (as expected by generated code) as either
+  // module.exports (if we're in a module) or a new, empty object.
+  runtime = global.regeneratorRuntime = inModule ? module.exports : {};
+
+  function wrap(innerFn, outerFn, self, tryLocsList) {
+    // If outerFn provided, then outerFn.prototype instanceof Generator.
+    var generator = Object.create((outerFn || Generator).prototype);
+    var context = new Context(tryLocsList || []);
+
+    // The ._invoke method unifies the implementations of the .next,
+    // .throw, and .return methods.
+    generator._invoke = makeInvokeMethod(innerFn, self, context);
+
+    return generator;
+  }
+  runtime.wrap = wrap;
+
+  // Try/catch helper to minimize deoptimizations. Returns a completion
+  // record like context.tryEntries[i].completion. This interface could
+  // have been (and was previously) designed to take a closure to be
+  // invoked without arguments, but in all the cases we care about we
+  // already have an existing method we want to call, so there's no need
+  // to create a new function object. We can even get away with assuming
+  // the method takes exactly one argument, since that happens to be true
+  // in every case, so we don't have to touch the arguments object. The
+  // only additional allocation required is the completion record, which
+  // has a stable shape and so hopefully should be cheap to allocate.
+  function tryCatch(fn, obj, arg) {
+    try {
+      return { type: "normal", arg: fn.call(obj, arg) };
+    } catch (err) {
+      return { type: "throw", arg: err };
+    }
+  }
+
+  var GenStateSuspendedStart = "suspendedStart";
+  var GenStateSuspendedYield = "suspendedYield";
+  var GenStateExecuting = "executing";
+  var GenStateCompleted = "completed";
+
+  // Returning this object from the innerFn has the same effect as
+  // breaking out of the dispatch switch statement.
+  var ContinueSentinel = {};
+
+  // Dummy constructor functions that we use as the .constructor and
+  // .constructor.prototype properties for functions that return Generator
+  // objects. For full spec compliance, you may wish to configure your
+  // minifier not to mangle the names of these two functions.
+  function Generator() {}
+  function GeneratorFunction() {}
+  function GeneratorFunctionPrototype() {}
+
+  var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype;
+  GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
+  GeneratorFunctionPrototype.constructor = GeneratorFunction;
+  GeneratorFunctionPrototype[toStringTagSymbol] = GeneratorFunction.displayName = "GeneratorFunction";
+
+  // Helper for defining the .next, .throw, and .return methods of the
+  // Iterator interface in terms of a single ._invoke method.
+  function defineIteratorMethods(prototype) {
+    ["next", "throw", "return"].forEach(function (method) {
+      prototype[method] = function (arg) {
+        return this._invoke(method, arg);
+      };
+    });
+  }
+
+  runtime.isGeneratorFunction = function (genFun) {
+    var ctor = typeof genFun === "function" && genFun.constructor;
+    return ctor ? ctor === GeneratorFunction ||
+    // For the native GeneratorFunction constructor, the best we can
+    // do is to check its .name property.
+    (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
+  };
+
+  runtime.mark = function (genFun) {
+    if (Object.setPrototypeOf) {
+      Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
+    } else {
+      genFun.__proto__ = GeneratorFunctionPrototype;
+      if (!(toStringTagSymbol in genFun)) {
+        genFun[toStringTagSymbol] = "GeneratorFunction";
+      }
+    }
+    genFun.prototype = Object.create(Gp);
+    return genFun;
+  };
+
+  // Within the body of any async function, `await x` is transformed to
+  // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
+  // `value instanceof AwaitArgument` to determine if the yielded value is
+  // meant to be awaited. Some may consider the name of this method too
+  // cutesy, but they are curmudgeons.
+  runtime.awrap = function (arg) {
+    return new AwaitArgument(arg);
+  };
+
+  function AwaitArgument(arg) {
+    this.arg = arg;
+  }
+
+  function AsyncIterator(generator) {
+    function invoke(method, arg, resolve, reject) {
+      var record = tryCatch(generator[method], generator, arg);
+      if (record.type === "throw") {
+        reject(record.arg);
+      } else {
+        var result = record.arg;
+        var value = result.value;
+        if (value instanceof AwaitArgument) {
+          return Promise.resolve(value.arg).then(function (value) {
+            invoke("next", value, resolve, reject);
+          }, function (err) {
+            invoke("throw", err, resolve, reject);
+          });
+        }
+
+        return Promise.resolve(value).then(function (unwrapped) {
+          // When a yielded Promise is resolved, its final value becomes
+          // the .value of the Promise<{value,done}> result for the
+          // current iteration. If the Promise is rejected, however, the
+          // result for this iteration will be rejected with the same
+          // reason. Note that rejections of yielded Promises are not
+          // thrown back into the generator function, as is the case
+          // when an awaited Promise is rejected. This difference in
+          // behavior between yield and await is important, because it
+          // allows the consumer to decide what to do with the yielded
+          // rejection (swallow it and continue, manually .throw it back
+          // into the generator, abandon iteration, whatever). With
+          // await, by contrast, there is no opportunity to examine the
+          // rejection reason outside the generator function, so the
+          // only option is to throw it from the await expression, and
+          // let the generator function handle the exception.
+          result.value = unwrapped;
+          resolve(result);
+        }, reject);
+      }
+    }
+
+    if ((typeof process === "undefined" ? "undefined" : _typeof(process)) === "object" && process.domain) {
+      invoke = process.domain.bind(invoke);
+    }
+
+    var previousPromise;
+
+    function enqueue(method, arg) {
+      function callInvokeWithMethodAndArg() {
+        return new Promise(function (resolve, reject) {
+          invoke(method, arg, resolve, reject);
+        });
+      }
+
+      return previousPromise =
+      // If enqueue has been called before, then we want to wait until
+      // all previous Promises have been resolved before calling invoke,
+      // so that results are always delivered in the correct order. If
+      // enqueue has not been called before, then it is important to
+      // call invoke immediately, without waiting on a callback to fire,
+      // so that the async generator function has the opportunity to do
+      // any necessary setup in a predictable way. This predictability
+      // is why the Promise constructor synchronously invokes its
+      // executor callback, and why async functions synchronously
+      // execute code before the first await. Since we implement simple
+      // async functions in terms of async generators, it is especially
+      // important to get this right, even though it requires care.
+      previousPromise ? previousPromise.then(callInvokeWithMethodAndArg,
+      // Avoid propagating failures to Promises returned by later
+      // invocations of the iterator.
+      callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
+    }
+
+    // Define the unified helper method that is used to implement .next,
+    // .throw, and .return (see defineIteratorMethods).
+    this._invoke = enqueue;
+  }
+
+  defineIteratorMethods(AsyncIterator.prototype);
+
+  // Note that simple async functions are implemented on top of
+  // AsyncIterator objects; they just return a Promise for the value of
+  // the final result produced by the iterator.
+  runtime.async = function (innerFn, outerFn, self, tryLocsList) {
+    var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList));
+
+    return runtime.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
+    : iter.next().then(function (result) {
+      return result.done ? result.value : iter.next();
+    });
+  };
+
+  function makeInvokeMethod(innerFn, self, context) {
+    var state = GenStateSuspendedStart;
+
+    return function invoke(method, arg) {
+      if (state === GenStateExecuting) {
+        throw new Error("Generator is already running");
+      }
+
+      if (state === GenStateCompleted) {
+        if (method === "throw") {
+          throw arg;
+        }
+
+        // Be forgiving, per 25.3.3.3.3 of the spec:
+        // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
+        return doneResult();
+      }
+
+      while (true) {
+        var delegate = context.delegate;
+        if (delegate) {
+          if (method === "return" || method === "throw" && delegate.iterator[method] === undefined) {
+            // A return or throw (when the delegate iterator has no throw
+            // method) always terminates the yield* loop.
+            context.delegate = null;
+
+            // If the delegate iterator has a return method, give it a
+            // chance to clean up.
+            var returnMethod = delegate.iterator["return"];
+            if (returnMethod) {
+              var record = tryCatch(returnMethod, delegate.iterator, arg);
+              if (record.type === "throw") {
+                // If the return method threw an exception, let that
+                // exception prevail over the original return or throw.
+                method = "throw";
+                arg = record.arg;
+                continue;
+              }
+            }
+
+            if (method === "return") {
+              // Continue with the outer return, now that the delegate
+              // iterator has been terminated.
+              continue;
+            }
+          }
+
+          var record = tryCatch(delegate.iterator[method], delegate.iterator, arg);
+
+          if (record.type === "throw") {
+            context.delegate = null;
+
+            // Like returning generator.throw(uncaught), but without the
+            // overhead of an extra function call.
+            method = "throw";
+            arg = record.arg;
+            continue;
+          }
+
+          // Delegate generator ran and handled its own exceptions so
+          // regardless of what the method was, we continue as if it is
+          // "next" with an undefined arg.
+          method = "next";
+          arg = undefined;
+
+          var info = record.arg;
+          if (info.done) {
+            context[delegate.resultName] = info.value;
+            context.next = delegate.nextLoc;
+          } else {
+            state = GenStateSuspendedYield;
+            return info;
+          }
+
+          context.delegate = null;
+        }
+
+        if (method === "next") {
+          if (state === GenStateSuspendedYield) {
+            context.sent = arg;
+          } else {
+            context.sent = undefined;
+          }
+        } else if (method === "throw") {
+          if (state === GenStateSuspendedStart) {
+            state = GenStateCompleted;
+            throw arg;
+          }
+
+          if (context.dispatchException(arg)) {
+            // If the dispatched exception was caught by a catch block,
+            // then let that catch block handle the exception normally.
+            method = "next";
+            arg = undefined;
+          }
+        } else if (method === "return") {
+          context.abrupt("return", arg);
+        }
+
+        state = GenStateExecuting;
+
+        var record = tryCatch(innerFn, self, context);
+        if (record.type === "normal") {
+          // If an exception is thrown from innerFn, we leave state ===
+          // GenStateExecuting and loop back for another invocation.
+          state = context.done ? GenStateCompleted : GenStateSuspendedYield;
+
+          var info = {
+            value: record.arg,
+            done: context.done
+          };
+
+          if (record.arg === ContinueSentinel) {
+            if (context.delegate && method === "next") {
+              // Deliberately forget the last sent value so that we don't
+              // accidentally pass it on to the delegate.
+              arg = undefined;
+            }
+          } else {
+            return info;
+          }
+        } else if (record.type === "throw") {
+          state = GenStateCompleted;
+          // Dispatch the exception by looping back around to the
+          // context.dispatchException(arg) call above.
+          method = "throw";
+          arg = record.arg;
+        }
+      }
+    };
+  }
+
+  // Define Generator.prototype.{next,throw,return} in terms of the
+  // unified ._invoke helper method.
+  defineIteratorMethods(Gp);
+
+  Gp[iteratorSymbol] = function () {
+    return this;
+  };
+
+  Gp[toStringTagSymbol] = "Generator";
+
+  Gp.toString = function () {
+    return "[object Generator]";
+  };
+
+  function pushTryEntry(locs) {
+    var entry = { tryLoc: locs[0] };
+
+    if (1 in locs) {
+      entry.catchLoc = locs[1];
+    }
+
+    if (2 in locs) {
+      entry.finallyLoc = locs[2];
+      entry.afterLoc = locs[3];
+    }
+
+    this.tryEntries.push(entry);
+  }
+
+  function resetTryEntry(entry) {
+    var record = entry.completion || {};
+    record.type = "normal";
+    delete record.arg;
+    entry.completion = record;
+  }
+
+  function Context(tryLocsList) {
+    // The root entry object (effectively a try statement without a catch
+    // or a finally block) gives us a place to store values thrown from
+    // locations where there is no enclosing try statement.
+    this.tryEntries = [{ tryLoc: "root" }];
+    tryLocsList.forEach(pushTryEntry, this);
+    this.reset(true);
+  }
+
+  runtime.keys = function (object) {
+    var keys = [];
+    for (var key in object) {
+      keys.push(key);
+    }
+    keys.reverse();
+
+    // Rather than returning an object with a next method, we keep
+    // things simple and return the next function itself.
+    return function next() {
+      while (keys.length) {
+        var key = keys.pop();
+        if (key in object) {
+          next.value = key;
+          next.done = false;
+          return next;
+        }
+      }
+
+      // To avoid creating an additional object, we just hang the .value
+      // and .done properties off the next function object itself. This
+      // also ensures that the minifier will not anonymize the function.
+      next.done = true;
+      return next;
+    };
+  };
+
+  function values(iterable) {
+    if (iterable) {
+      var iteratorMethod = iterable[iteratorSymbol];
+      if (iteratorMethod) {
+        return iteratorMethod.call(iterable);
+      }
+
+      if (typeof iterable.next === "function") {
+        return iterable;
+      }
+
+      if (!isNaN(iterable.length)) {
+        var i = -1,
+            next = function next() {
+          while (++i < iterable.length) {
+            if (hasOwn.call(iterable, i)) {
+              next.value = iterable[i];
+              next.done = false;
+              return next;
+            }
+          }
+
+          next.value = undefined;
+          next.done = true;
+
+          return next;
+        };
+
+        return next.next = next;
+      }
+    }
+
+    // Return an iterator with no values.
+    return { next: doneResult };
+  }
+  runtime.values = values;
+
+  function doneResult() {
+    return { value: undefined, done: true };
+  }
+
+  Context.prototype = {
+    constructor: Context,
+
+    reset: function reset(skipTempReset) {
+      this.prev = 0;
+      this.next = 0;
+      this.sent = undefined;
+      this.done = false;
+      this.delegate = null;
+
+      this.tryEntries.forEach(resetTryEntry);
+
+      if (!skipTempReset) {
+        for (var name in this) {
+          // Not sure about the optimal order of these conditions:
+          if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
+            this[name] = undefined;
+          }
+        }
+      }
+    },
+
+    stop: function stop() {
+      this.done = true;
+
+      var rootEntry = this.tryEntries[0];
+      var rootRecord = rootEntry.completion;
+      if (rootRecord.type === "throw") {
+        throw rootRecord.arg;
+      }
+
+      return this.rval;
+    },
+
+    dispatchException: function dispatchException(exception) {
+      if (this.done) {
+        throw exception;
+      }
+
+      var context = this;
+      function handle(loc, caught) {
+        record.type = "throw";
+        record.arg = exception;
+        context.next = loc;
+        return !!caught;
+      }
+
+      for (var i = this.tryEntries.length - 1; i >= 0; --i) {
+        var entry = this.tryEntries[i];
+        var record = entry.completion;
+
+        if (entry.tryLoc === "root") {
+          // Exception thrown outside of any try block that could handle
+          // it, so set the completion value of the entire function to
+          // throw the exception.
+          return handle("end");
+        }
+
+        if (entry.tryLoc <= this.prev) {
+          var hasCatch = hasOwn.call(entry, "catchLoc");
+          var hasFinally = hasOwn.call(entry, "finallyLoc");
+
+          if (hasCatch && hasFinally) {
+            if (this.prev < entry.catchLoc) {
+              return handle(entry.catchLoc, true);
+            } else if (this.prev < entry.finallyLoc) {
+              return handle(entry.finallyLoc);
+            }
+          } else if (hasCatch) {
+            if (this.prev < entry.catchLoc) {
+              return handle(entry.catchLoc, true);
+            }
+          } else if (hasFinally) {
+            if (this.prev < entry.finallyLoc) {
+              return handle(entry.finallyLoc);
+            }
+          } else {
+            throw new Error("try statement without catch or finally");
+          }
+        }
+      }
+    },
+
+    abrupt: function abrupt(type, arg) {
+      for (var i = this.tryEntries.length - 1; i >= 0; --i) {
+        var entry = this.tryEntries[i];
+        if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
+          var finallyEntry = entry;
+          break;
+        }
+      }
+
+      if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
+        // Ignore the finally entry if control is not jumping to a
+        // location outside the try/catch block.
+        finallyEntry = null;
+      }
+
+      var record = finallyEntry ? finallyEntry.completion : {};
+      record.type = type;
+      record.arg = arg;
+
+      if (finallyEntry) {
+        this.next = finallyEntry.finallyLoc;
+      } else {
+        this.complete(record);
+      }
+
+      return ContinueSentinel;
+    },
+
+    complete: function complete(record, afterLoc) {
+      if (record.type === "throw") {
+        throw record.arg;
+      }
+
+      if (record.type === "break" || record.type === "continue") {
+        this.next = record.arg;
+      } else if (record.type === "return") {
+        this.rval = record.arg;
+        this.next = "end";
+      } else if (record.type === "normal" && afterLoc) {
+        this.next = afterLoc;
+      }
+    },
+
+    finish: function finish(finallyLoc) {
+      for (var i = this.tryEntries.length - 1; i >= 0; --i) {
+        var entry = this.tryEntries[i];
+        if (entry.finallyLoc === finallyLoc) {
+          this.complete(entry.completion, entry.afterLoc);
+          resetTryEntry(entry);
+          return ContinueSentinel;
+        }
+      }
+    },
+
+    "catch": function _catch(tryLoc) {
+      for (var i = this.tryEntries.length - 1; i >= 0; --i) {
+        var entry = this.tryEntries[i];
+        if (entry.tryLoc === tryLoc) {
+          var record = entry.completion;
+          if (record.type === "throw") {
+            var thrown = record.arg;
+            resetTryEntry(entry);
+          }
+          return thrown;
+        }
+      }
+
+      // The context.catch method must only be called with a location
+      // argument that corresponds to a known catch block.
+      throw new Error("illegal catch attempt");
+    },
+
+    delegateYield: function delegateYield(iterable, resultName, nextLoc) {
+      this.delegate = {
+        iterator: values(iterable),
+        resultName: resultName,
+        nextLoc: nextLoc
+      };
+
+      return ContinueSentinel;
+    }
+  };
+})(
+// Among the various tricks for obtaining a reference to the global
+// object, this seems to be the most reliable technique that does not
+// use indirect eval (which violates Content Security Policy).
+(typeof global === "undefined" ? "undefined" : _typeof(global)) === "object" ? global : (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" ? window : (typeof self === "undefined" ? "undefined" : _typeof(self)) === "object" ? self : undefined);
+
+}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"_process":1}],3:[function(require,module,exports){
+'use strict';
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 module.exports = function (Y) {
-  class AbstractConnector {
+  var AbstractConnector = (function () {
     /*
       opts contains the following information:
        role : String Role of this client ("master" or "slave")
        userId : String Uniquely defines the user.
        debug: Boolean Whether to print debug messages (optional)
     */
-    constructor (y, opts) {
-      this.y = y
+
+    function AbstractConnector(y, opts) {
+      _classCallCheck(this, AbstractConnector);
+
+      this.y = y;
       if (opts == null) {
-        opts = {}
+        opts = {};
       }
       if (opts.role == null || opts.role === 'master') {
-        this.role = 'master'
+        this.role = 'master';
       } else if (opts.role === 'slave') {
-        this.role = 'slave'
+        this.role = 'slave';
       } else {
-        throw new Error("Role must be either 'master' or 'slave'!")
+        throw new Error("Role must be either 'master' or 'slave'!");
       }
-      this.role = opts.role
-      this.connections = {}
-      this.isSynced = false
-      this.userEventListeners = []
-      this.whenSyncedListeners = []
-      this.currentSyncTarget = null
-      this.syncingClients = []
-      this.forwardToSyncingClients = opts.forwardToSyncingClients !== false
-      this.debug = opts.debug === true
-      this.broadcastedHB = false
-      this.syncStep2 = Promise.resolve()
+      this.y.db.forwardAppliedOperations = opts.forwardAppliedOperations || false;
+      this.role = opts.role;
+      this.connections = {};
+      this.isSynced = false;
+      this.userEventListeners = [];
+      this.whenSyncedListeners = [];
+      this.currentSyncTarget = null;
+      this.syncingClients = [];
+      this.forwardToSyncingClients = opts.forwardToSyncingClients !== false;
+      this.debug = opts.debug === true;
+      this.broadcastedHB = false;
+      this.syncStep2 = Promise.resolve();
     }
-    reconnect () {
-    }
-    disconnect () {
-      this.connections = {}
-      this.isSynced = false
-      this.currentSyncTarget = null
-      this.broadcastedHB = false
-      this.syncingClients = []
-      this.whenSyncedListeners = []
-      return this.y.db.stopGarbageCollector()
-    }
-    setUserId (userId) {
-      this.userId = userId
-      return this.y.db.setUserId(userId)
-    }
-    onUserEvent (f) {
-      this.userEventListeners.push(f)
-    }
-    userLeft (user) {
-      delete this.connections[user]
-      if (user === this.currentSyncTarget) {
-        this.currentSyncTarget = null
-        this.findNextSyncTarget()
-      }
-      this.syncingClients = this.syncingClients.filter(function (cli) {
-        return cli !== user
-      })
-      for (var f of this.userEventListeners) {
-        f({
-          action: 'userLeft',
-          user: user
-        })
-      }
-    }
-    userJoined (user, role) {
-      if (role == null) {
-        throw new Error('You must specify the role of the joined user!')
-      }
-      if (this.connections[user] != null) {
-        throw new Error('This user already joined!')
-      }
-      this.connections[user] = {
-        isSynced: false,
-        role: role
-      }
-      for (var f of this.userEventListeners) {
-        f({
-          action: 'userJoined',
-          user: user,
-          role: role
-        })
-      }
-      if (this.currentSyncTarget == null) {
-        this.findNextSyncTarget()
-      }
-    }
-    // Execute a function _when_ we are connected.
-    // If not connected, wait until connected
-    whenSynced (f) {
-      if (this.isSynced) {
-        f()
-      } else {
-        this.whenSyncedListeners.push(f)
-      }
-    }
-    /*
 
-     returns false, if there is no sync target
-     true otherwise
-    */
-    findNextSyncTarget () {
-      if (this.currentSyncTarget != null || this.isSynced) {
-        return // "The current sync has not finished!"
+    _createClass(AbstractConnector, [{
+      key: 'reconnect',
+      value: function reconnect() {}
+    }, {
+      key: 'disconnect',
+      value: function disconnect() {
+        this.connections = {};
+        this.isSynced = false;
+        this.currentSyncTarget = null;
+        this.broadcastedHB = false;
+        this.syncingClients = [];
+        this.whenSyncedListeners = [];
+        return this.y.db.stopGarbageCollector();
       }
-
-      var syncUser = null
-      for (var uid in this.connections) {
-        if (!this.connections[uid].isSynced) {
-          syncUser = uid
-          break
+    }, {
+      key: 'setUserId',
+      value: function setUserId(userId) {
+        this.userId = userId;
+        return this.y.db.setUserId(userId);
+      }
+    }, {
+      key: 'onUserEvent',
+      value: function onUserEvent(f) {
+        this.userEventListeners.push(f);
+      }
+    }, {
+      key: 'userLeft',
+      value: function userLeft(user) {
+        delete this.connections[user];
+        if (user === this.currentSyncTarget) {
+          this.currentSyncTarget = null;
+          this.findNextSyncTarget();
         }
-      }
-      if (syncUser != null) {
-        var conn = this
-        this.currentSyncTarget = syncUser
-        this.y.db.requestTransaction(function *() {
-          conn.send(syncUser, {
-            type: 'sync step 1',
-            stateSet: yield* this.getStateSet(),
-            deleteSet: yield* this.getDeleteSet()
-          })
-        })
-      } else {
-        this.isSynced = true
-        // call when synced listeners
-        for (var f of this.whenSyncedListeners) {
-          f()
-        }
-        this.whenSyncedListeners = []
-        this.y.db.requestTransaction(function *() {
-          yield* this.garbageCollectAfterSync()
-        })
-      }
-    }
-    send (uid, message) {
-      if (this.debug) {
-        console.log(`send ${this.userId} -> ${uid}: ${message.type}`, m) // eslint-disable-line
-      }
-    }
-    /*
-      You received a raw message, and you know that it is intended for Yjs. Then call this function.
-    */
-    receiveMessage (sender, m) {
-      if (sender === this.userId) {
-        return
-      }
-      if (this.debug) {
-        console.log(`receive ${sender} -> ${this.userId}: ${m.type}`, JSON.parse(JSON.stringify(m))) // eslint-disable-line
-      }
-      if (m.type === 'sync step 1') {
-        // TODO: make transaction, stream the ops
-        let conn = this
-        this.y.db.requestTransaction(function *() {
-          var currentStateSet = yield* this.getStateSet()
-          yield* this.applyDeleteSet(m.deleteSet)
+        this.syncingClients = this.syncingClients.filter(function (cli) {
+          return cli !== user;
+        });
+        var _iteratorNormalCompletion = true;
+        var _didIteratorError = false;
+        var _iteratorError = undefined;
 
-          var ds = yield* this.getDeleteSet()
-          var ops = yield* this.getOperations(m.stateSet)
-          conn.send(sender, {
-            type: 'sync step 2',
-            os: ops,
-            stateSet: currentStateSet,
-            deleteSet: ds
-          })
-          if (this.forwardToSyncingClients) {
-            conn.syncingClients.push(sender)
-            setTimeout(function () {
-              conn.syncingClients = conn.syncingClients.filter(function (cli) {
-                return cli !== sender
-              })
-              conn.send(sender, {
-                type: 'sync done'
-              })
-            }, conn.syncingClientDuration)
-          } else {
-            conn.send(sender, {
-              type: 'sync done'
-            })
+        try {
+          for (var _iterator = this.userEventListeners[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+            var f = _step.value;
+
+            f({
+              action: 'userLeft',
+              user: user
+            });
           }
-          conn._setSyncedWith(sender)
-        })
-      } else if (m.type === 'sync step 2') {
-        let conn = this
-        var broadcastHB = !this.broadcastedHB
-        this.broadcastedHB = true
-        var db = this.y.db
-        this.syncStep2 = new Promise(function (resolve) {
-          db.requestTransaction(function * () {
-            yield* this.applyDeleteSet(m.deleteSet)
-            this.store.apply(m.os)
-            db.requestTransaction(function * () {
-              var ops = yield* this.getOperations(m.stateSet)
-              if (ops.length > 0) {
-                m = {
-                  type: 'update',
-                  ops: ops
-                }
-                if (!broadcastHB) { // TODO: consider to broadcast here..
-                  conn.send(sender, m)
-                } else {
-                  // broadcast only once!
-                  conn.broadcast(m)
+        } catch (err) {
+          _didIteratorError = true;
+          _iteratorError = err;
+        } finally {
+          try {
+            if (!_iteratorNormalCompletion && _iterator.return) {
+              _iterator.return();
+            }
+          } finally {
+            if (_didIteratorError) {
+              throw _iteratorError;
+            }
+          }
+        }
+      }
+    }, {
+      key: 'userJoined',
+      value: function userJoined(user, role) {
+        if (role == null) {
+          throw new Error('You must specify the role of the joined user!');
+        }
+        if (this.connections[user] != null) {
+          throw new Error('This user already joined!');
+        }
+        this.connections[user] = {
+          isSynced: false,
+          role: role
+        };
+        var _iteratorNormalCompletion2 = true;
+        var _didIteratorError2 = false;
+        var _iteratorError2 = undefined;
+
+        try {
+          for (var _iterator2 = this.userEventListeners[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+            var f = _step2.value;
+
+            f({
+              action: 'userJoined',
+              user: user,
+              role: role
+            });
+          }
+        } catch (err) {
+          _didIteratorError2 = true;
+          _iteratorError2 = err;
+        } finally {
+          try {
+            if (!_iteratorNormalCompletion2 && _iterator2.return) {
+              _iterator2.return();
+            }
+          } finally {
+            if (_didIteratorError2) {
+              throw _iteratorError2;
+            }
+          }
+        }
+
+        if (this.currentSyncTarget == null) {
+          this.findNextSyncTarget();
+        }
+      }
+      // Execute a function _when_ we are connected.
+      // If not connected, wait until connected
+
+    }, {
+      key: 'whenSynced',
+      value: function whenSynced(f) {
+        if (this.isSynced) {
+          f();
+        } else {
+          this.whenSyncedListeners.push(f);
+        }
+      }
+      /*
+        returns false, if there is no sync target
+       true otherwise
+      */
+
+    }, {
+      key: 'findNextSyncTarget',
+      value: function findNextSyncTarget() {
+        if (this.currentSyncTarget != null || this.isSynced) {
+          return; // "The current sync has not finished!"
+        }
+
+        var syncUser = null;
+        for (var uid in this.connections) {
+          if (!this.connections[uid].isSynced) {
+            syncUser = uid;
+            break;
+          }
+        }
+        if (syncUser != null) {
+          var conn = this;
+          this.currentSyncTarget = syncUser;
+          this.y.db.requestTransaction(regeneratorRuntime.mark(function _callee() {
+            return regeneratorRuntime.wrap(function _callee$(_context) {
+              while (1) {
+                switch (_context.prev = _context.next) {
+                  case 0:
+                    _context.t0 = conn;
+                    _context.t1 = syncUser;
+                    return _context.delegateYield(this.getStateSet(), 't2', 3);
+
+                  case 3:
+                    _context.t3 = _context.t2;
+                    return _context.delegateYield(this.getDeleteSet(), 't4', 5);
+
+                  case 5:
+                    _context.t5 = _context.t4;
+                    _context.t6 = {
+                      type: 'sync step 1',
+                      stateSet: _context.t3,
+                      deleteSet: _context.t5
+                    };
+
+                    _context.t0.send.call(_context.t0, _context.t1, _context.t6);
+
+                  case 8:
+                  case 'end':
+                    return _context.stop();
                 }
               }
-              resolve()
-            })
-          })
-        })
-      } else if (m.type === 'sync done') {
-        var self = this
-        this.syncStep2.then(function () {
-          self._setSyncedWith(sender)
-        })
-      } else if (m.type === 'update') {
-        if (this.forwardToSyncingClients) {
-          for (var client of this.syncingClients) {
-            this.send(client, m)
-          }
-        }
-        this.y.db.apply(m.ops)
-      }
-    }
-    _setSyncedWith (user) {
-      var conn = this.connections[user]
-      if (conn != null) {
-        conn.isSynced = true
-      }
-      if (user === this.currentSyncTarget) {
-        this.currentSyncTarget = null
-        this.findNextSyncTarget()
-      }
-    }
-    /*
-      Currently, the HB encodes operations as JSON. For the moment I want to keep it
-      that way. Maybe we support encoding in the HB as XML in the future, but for now I don't want
-      too much overhead. Y is very likely to get changed a lot in the future
+            }, _callee, this);
+          }));
+        } else {
+          this.isSynced = true;
+          // call when synced listeners
+          var _iteratorNormalCompletion3 = true;
+          var _didIteratorError3 = false;
+          var _iteratorError3 = undefined;
 
-      Because we don't want to encode JSON as string (with character escaping, wich makes it pretty much unreadable)
-      we encode the JSON as XML.
+          try {
+            for (var _iterator3 = this.whenSyncedListeners[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+              var f = _step3.value;
 
-      When the HB support encoding as XML, the format should look pretty much like this.
+              f();
+            }
+          } catch (err) {
+            _didIteratorError3 = true;
+            _iteratorError3 = err;
+          } finally {
+            try {
+              if (!_iteratorNormalCompletion3 && _iterator3.return) {
+                _iterator3.return();
+              }
+            } finally {
+              if (_didIteratorError3) {
+                throw _iteratorError3;
+              }
+            }
+          }
 
-      does not support primitive values as array elements
-      expects an ltx (less than xml) object
-    */
-    parseMessageFromXml (m) {
-      function parseArray (node) {
-        for (var n of node.children) {
-          if (n.getAttribute('isArray') === 'true') {
-            return parseArray(n)
-          } else {
-            return parseObject(n)
-          }
-        }
-      }
-      function parseObject (node) {
-        var json = {}
-        for (var attrName in node.attrs) {
-          var value = node.attrs[attrName]
-          var int = parseInt(value, 10)
-          if (isNaN(int) || ('' + int) !== value) {
-            json[attrName] = value
-          } else {
-            json[attrName] = int
-          }
-        }
-        for (var n in node.children) {
-          var name = n.name
-          if (n.getAttribute('isArray') === 'true') {
-            json[name] = parseArray(n)
-          } else {
-            json[name] = parseObject(n)
-          }
-        }
-        return json
-      }
-      parseObject(m)
-    }
-    /*
-      encode message in xml
-      we use string because Strophe only accepts an "xml-string"..
-      So {a:4,b:{c:5}} will look like
-      <y a="4">
-        <b c="5"></b>
-      </y>
-      m - ltx element
-      json - Object
-    */
-    encodeMessageToXml (msg, obj) {
-      // attributes is optional
-      function encodeObject (m, json) {
-        for (var name in json) {
-          var value = json[name]
-          if (name == null) {
-            // nop
-          } else if (value.constructor === Object) {
-            encodeObject(m.c(name), value)
-          } else if (value.constructor === Array) {
-            encodeArray(m.c(name), value)
-          } else {
-            m.setAttribute(name, value)
-          }
-        }
-      }
-      function encodeArray (m, array) {
-        m.setAttribute('isArray', 'true')
-        for (var e of array) {
-          if (e.constructor === Object) {
-            encodeObject(m.c('array-element'), e)
-          } else {
-            encodeArray(m.c('array-element'), e)
-          }
-        }
-      }
-      if (obj.constructor === Object) {
-        encodeObject(msg.c('y', { xmlns: 'http://y.ninja/connector-stanza' }), obj)
-      } else if (obj.constructor === Array) {
-        encodeArray(msg.c('y', { xmlns: 'http://y.ninja/connector-stanza' }), obj)
-      } else {
-        throw new Error("I can't encode this json!")
-      }
-    }
-  }
-  Y.AbstractConnector = AbstractConnector
-}
+          this.whenSyncedListeners = [];
+          this.y.db.requestTransaction(regeneratorRuntime.mark(function _callee2() {
+            return regeneratorRuntime.wrap(function _callee2$(_context2) {
+              while (1) {
+                switch (_context2.prev = _context2.next) {
+                  case 0:
+                    return _context2.delegateYield(this.garbageCollectAfterSync(), 't0', 1);
 
-},{}],2:[function(require,module,exports){
+                  case 1:
+                  case 'end':
+                    return _context2.stop();
+                }
+              }
+            }, _callee2, this);
+          }));
+        }
+      }
+    }, {
+      key: 'send',
+      value: function send(uid, message) {
+        if (this.debug) {
+          console.log('send ' + this.userId + ' -> ' + uid + ': ' + message.type, m); // eslint-disable-line
+        }
+      }
+      /*
+        You received a raw message, and you know that it is intended for Yjs. Then call this function.
+      */
+
+    }, {
+      key: 'receiveMessage',
+      value: function receiveMessage(sender, m) {
+        var _this = this;
+
+        if (sender === this.userId) {
+          return;
+        }
+        if (this.debug) {
+          console.log('receive ' + sender + ' -> ' + this.userId + ': ' + m.type, JSON.parse(JSON.stringify(m))); // eslint-disable-line
+        }
+        if (m.type === 'sync step 1') {
+          (function () {
+            // TODO: make transaction, stream the ops
+            var conn = _this;
+            _this.y.db.requestTransaction(regeneratorRuntime.mark(function _callee3() {
+              var currentStateSet, ds, ops;
+              return regeneratorRuntime.wrap(function _callee3$(_context3) {
+                while (1) {
+                  switch (_context3.prev = _context3.next) {
+                    case 0:
+                      return _context3.delegateYield(this.getStateSet(), 't0', 1);
+
+                    case 1:
+                      currentStateSet = _context3.t0;
+                      return _context3.delegateYield(this.applyDeleteSet(m.deleteSet), 't1', 3);
+
+                    case 3:
+                      return _context3.delegateYield(this.getDeleteSet(), 't2', 4);
+
+                    case 4:
+                      ds = _context3.t2;
+                      return _context3.delegateYield(this.getOperations(m.stateSet), 't3', 6);
+
+                    case 6:
+                      ops = _context3.t3;
+
+                      conn.send(sender, {
+                        type: 'sync step 2',
+                        os: ops,
+                        stateSet: currentStateSet,
+                        deleteSet: ds
+                      });
+                      if (this.forwardToSyncingClients) {
+                        conn.syncingClients.push(sender);
+                        setTimeout(function () {
+                          conn.syncingClients = conn.syncingClients.filter(function (cli) {
+                            return cli !== sender;
+                          });
+                          conn.send(sender, {
+                            type: 'sync done'
+                          });
+                        }, conn.syncingClientDuration);
+                      } else {
+                        conn.send(sender, {
+                          type: 'sync done'
+                        });
+                      }
+                      conn._setSyncedWith(sender);
+
+                    case 10:
+                    case 'end':
+                      return _context3.stop();
+                  }
+                }
+              }, _callee3, this);
+            }));
+          })();
+        } else if (m.type === 'sync step 2') {
+          var broadcastHB;
+          var db;
+
+          (function () {
+            var conn = _this;
+            broadcastHB = !_this.broadcastedHB;
+
+            _this.broadcastedHB = true;
+            db = _this.y.db;
+
+            _this.syncStep2 = new Promise(function (resolve) {
+              db.requestTransaction(regeneratorRuntime.mark(function _callee5() {
+                return regeneratorRuntime.wrap(function _callee5$(_context5) {
+                  while (1) {
+                    switch (_context5.prev = _context5.next) {
+                      case 0:
+                        return _context5.delegateYield(this.applyDeleteSet(m.deleteSet), 't0', 1);
+
+                      case 1:
+                        this.store.apply(m.os);
+                        db.requestTransaction(regeneratorRuntime.mark(function _callee4() {
+                          var ops;
+                          return regeneratorRuntime.wrap(function _callee4$(_context4) {
+                            while (1) {
+                              switch (_context4.prev = _context4.next) {
+                                case 0:
+                                  return _context4.delegateYield(this.getOperations(m.stateSet), 't0', 1);
+
+                                case 1:
+                                  ops = _context4.t0;
+
+                                  if (ops.length > 0) {
+                                    m = {
+                                      type: 'update',
+                                      ops: ops
+                                    };
+                                    if (!broadcastHB) {
+                                      // TODO: consider to broadcast here..
+                                      conn.send(sender, m);
+                                    } else {
+                                      // broadcast only once!
+                                      conn.broadcast(m);
+                                    }
+                                  }
+                                  resolve();
+
+                                case 4:
+                                case 'end':
+                                  return _context4.stop();
+                              }
+                            }
+                          }, _callee4, this);
+                        }));
+
+                      case 3:
+                      case 'end':
+                        return _context5.stop();
+                    }
+                  }
+                }, _callee5, this);
+              }));
+            });
+          })();
+        } else if (m.type === 'sync done') {
+          var self = this;
+          this.syncStep2.then(function () {
+            self._setSyncedWith(sender);
+          });
+        } else if (m.type === 'update') {
+          if (this.forwardToSyncingClients) {
+            var _iteratorNormalCompletion4 = true;
+            var _didIteratorError4 = false;
+            var _iteratorError4 = undefined;
+
+            try {
+              for (var _iterator4 = this.syncingClients[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+                var client = _step4.value;
+
+                this.send(client, m);
+              }
+            } catch (err) {
+              _didIteratorError4 = true;
+              _iteratorError4 = err;
+            } finally {
+              try {
+                if (!_iteratorNormalCompletion4 && _iterator4.return) {
+                  _iterator4.return();
+                }
+              } finally {
+                if (_didIteratorError4) {
+                  throw _iteratorError4;
+                }
+              }
+            }
+          }
+          if (this.y.db.forwardAppliedOperations) {
+            var delops = m.ops.filter(function (o) {
+              return o.struct === 'Delete';
+            });
+            if (delops.length > 0) {
+              this.broadcast({
+                type: 'update',
+                ops: delops
+              });
+            }
+          }
+          this.y.db.apply(m.ops);
+        }
+      }
+    }, {
+      key: '_setSyncedWith',
+      value: function _setSyncedWith(user) {
+        var conn = this.connections[user];
+        if (conn != null) {
+          conn.isSynced = true;
+        }
+        if (user === this.currentSyncTarget) {
+          this.currentSyncTarget = null;
+          this.findNextSyncTarget();
+        }
+      }
+      /*
+        Currently, the HB encodes operations as JSON. For the moment I want to keep it
+        that way. Maybe we support encoding in the HB as XML in the future, but for now I don't want
+        too much overhead. Y is very likely to get changed a lot in the future
+         Because we don't want to encode JSON as string (with character escaping, wich makes it pretty much unreadable)
+        we encode the JSON as XML.
+         When the HB support encoding as XML, the format should look pretty much like this.
+         does not support primitive values as array elements
+        expects an ltx (less than xml) object
+      */
+
+    }, {
+      key: 'parseMessageFromXml',
+      value: function parseMessageFromXml(m) {
+        function parseArray(node) {
+          var _iteratorNormalCompletion5 = true;
+          var _didIteratorError5 = false;
+          var _iteratorError5 = undefined;
+
+          try {
+            for (var _iterator5 = node.children[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+              var n = _step5.value;
+
+              if (n.getAttribute('isArray') === 'true') {
+                return parseArray(n);
+              } else {
+                return parseObject(n);
+              }
+            }
+          } catch (err) {
+            _didIteratorError5 = true;
+            _iteratorError5 = err;
+          } finally {
+            try {
+              if (!_iteratorNormalCompletion5 && _iterator5.return) {
+                _iterator5.return();
+              }
+            } finally {
+              if (_didIteratorError5) {
+                throw _iteratorError5;
+              }
+            }
+          }
+        }
+        function parseObject(node) {
+          var json = {};
+          for (var attrName in node.attrs) {
+            var value = node.attrs[attrName];
+            var int = parseInt(value, 10);
+            if (isNaN(int) || '' + int !== value) {
+              json[attrName] = value;
+            } else {
+              json[attrName] = int;
+            }
+          }
+          for (var n in node.children) {
+            var name = n.name;
+            if (n.getAttribute('isArray') === 'true') {
+              json[name] = parseArray(n);
+            } else {
+              json[name] = parseObject(n);
+            }
+          }
+          return json;
+        }
+        parseObject(m);
+      }
+      /*
+        encode message in xml
+        we use string because Strophe only accepts an "xml-string"..
+        So {a:4,b:{c:5}} will look like
+        <y a="4">
+          <b c="5"></b>
+        </y>
+        m - ltx element
+        json - Object
+      */
+
+    }, {
+      key: 'encodeMessageToXml',
+      value: function encodeMessageToXml(msg, obj) {
+        // attributes is optional
+        function encodeObject(m, json) {
+          for (var name in json) {
+            var value = json[name];
+            if (name == null) {
+              // nop
+            } else if (value.constructor === Object) {
+                encodeObject(m.c(name), value);
+              } else if (value.constructor === Array) {
+                encodeArray(m.c(name), value);
+              } else {
+                m.setAttribute(name, value);
+              }
+          }
+        }
+        function encodeArray(m, array) {
+          m.setAttribute('isArray', 'true');
+          var _iteratorNormalCompletion6 = true;
+          var _didIteratorError6 = false;
+          var _iteratorError6 = undefined;
+
+          try {
+            for (var _iterator6 = array[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+              var e = _step6.value;
+
+              if (e.constructor === Object) {
+                encodeObject(m.c('array-element'), e);
+              } else {
+                encodeArray(m.c('array-element'), e);
+              }
+            }
+          } catch (err) {
+            _didIteratorError6 = true;
+            _iteratorError6 = err;
+          } finally {
+            try {
+              if (!_iteratorNormalCompletion6 && _iterator6.return) {
+                _iterator6.return();
+              }
+            } finally {
+              if (_didIteratorError6) {
+                throw _iteratorError6;
+              }
+            }
+          }
+        }
+        if (obj.constructor === Object) {
+          encodeObject(msg.c('y', { xmlns: 'http://y.ninja/connector-stanza' }), obj);
+        } else if (obj.constructor === Array) {
+          encodeArray(msg.c('y', { xmlns: 'http://y.ninja/connector-stanza' }), obj);
+        } else {
+          throw new Error("I can't encode this json!");
+        }
+      }
+    }]);
+
+    return AbstractConnector;
+  })();
+
+  Y.AbstractConnector = AbstractConnector;
+};
+
+},{}],4:[function(require,module,exports){
 /* global getRandom, wait, async */
-'use strict'
+'use strict';
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
 
 module.exports = function (Y) {
   var globalRoom = {
     users: {},
     buffers: {},
-    removeUser: function (user) {
+    removeUser: function removeUser(user) {
       for (var i in this.users) {
-        this.users[i].userLeft(user)
+        this.users[i].userLeft(user);
       }
-      delete this.users[user]
-      delete this.buffers[user]
+      delete this.users[user];
+      delete this.buffers[user];
     },
-    addUser: function (connector) {
-      this.users[connector.userId] = connector
-      this.buffers[connector.userId] = []
+    addUser: function addUser(connector) {
+      this.users[connector.userId] = connector;
+      this.buffers[connector.userId] = [];
       for (var uname in this.users) {
         if (uname !== connector.userId) {
-          var u = this.users[uname]
-          u.userJoined(connector.userId, 'master')
-          connector.userJoined(u.userId, 'master')
+          var u = this.users[uname];
+          u.userJoined(connector.userId, 'master');
+          connector.userJoined(u.userId, 'master');
         }
       }
     }
-  }
-  Y.utils.globalRoom = globalRoom
+  };
+  Y.utils.globalRoom = globalRoom;
 
-  function flushOne () {
-    var bufs = []
+  function _flushOne() {
+    var bufs = [];
     for (var i in globalRoom.buffers) {
       if (globalRoom.buffers[i].length > 0) {
-        bufs.push(i)
+        bufs.push(i);
       }
     }
     if (bufs.length > 0) {
-      var userId = getRandom(bufs)
-      var m = globalRoom.buffers[userId].shift()
-      var user = globalRoom.users[userId]
-      user.receiveMessage(m[0], m[1])
-      return true
+      var userId = getRandom(bufs);
+      var m = globalRoom.buffers[userId].shift();
+      var user = globalRoom.users[userId];
+      user.receiveMessage(m[0], m[1]);
+      return true;
     } else {
-      return false
+      return false;
     }
   }
 
   // setInterval(flushOne, 10)
 
-  var userIdCounter = 0
+  var userIdCounter = 0;
+
+  var Test = (function (_Y$AbstractConnector) {
+    _inherits(Test, _Y$AbstractConnector);
+
+    function Test(y, options) {
+      _classCallCheck(this, Test);
 
-  class Test extends Y.AbstractConnector {
-    constructor (y, options) {
       if (options === undefined) {
-        throw new Error('Options must not be undefined!')
+        throw new Error('Options must not be undefined!');
       }
-      options.role = 'master'
-      options.forwardToSyncingClients = false
-      super(y, options)
-      this.setUserId((userIdCounter++) + '').then(() => {
-        globalRoom.addUser(this)
-      })
-      this.globalRoom = globalRoom
-      this.syncingClientDuration = 0
+      options.role = 'master';
+      options.forwardToSyncingClients = false;
+
+      var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Test).call(this, y, options));
+
+      _this.setUserId(userIdCounter++ + '').then(function () {
+        globalRoom.addUser(_this);
+      });
+      _this.globalRoom = globalRoom;
+      _this.syncingClientDuration = 0;
+      return _this;
     }
-    receiveMessage (sender, m) {
-      super.receiveMessage(sender, JSON.parse(JSON.stringify(m)))
-    }
-    send (userId, message) {
-      var buffer = globalRoom.buffers[userId]
-      if (buffer != null) {
-        buffer.push(JSON.parse(JSON.stringify([this.userId, message])))
+
+    _createClass(Test, [{
+      key: 'receiveMessage',
+      value: function receiveMessage(sender, m) {
+        _get(Object.getPrototypeOf(Test.prototype), 'receiveMessage', this).call(this, sender, JSON.parse(JSON.stringify(m)));
       }
-    }
-    broadcast (message) {
-      for (var key in globalRoom.buffers) {
-        globalRoom.buffers[key].push(JSON.parse(JSON.stringify([this.userId, message])))
-      }
-    }
-    isDisconnected () {
-      return globalRoom.users[this.userId] == null
-    }
-    reconnect () {
-      if (this.isDisconnected()) {
-        globalRoom.addUser(this)
-        super.reconnect()
-      }
-      return this.flushAll()
-    }
-    disconnect () {
-      if (!this.isDisconnected()) {
-        globalRoom.removeUser(this.userId)
-        super.disconnect()
-      }
-      return wait()
-    }
-    flush () {
-      var self = this
-      return async(function * () {
-        yield wait()
-        while (globalRoom.buffers[self.userId].length > 0) {
-          var m = globalRoom.buffers[self.userId].shift()
-          this.receiveMessage(m[0], m[1])
-          yield wait()
+    }, {
+      key: 'send',
+      value: function send(userId, message) {
+        var buffer = globalRoom.buffers[userId];
+        if (buffer != null) {
+          buffer.push(JSON.parse(JSON.stringify([this.userId, message])));
         }
-      })
-    }
-    flushAll () {
-      return new Promise(function (resolve) {
-        // flushes may result in more created operations,
-        // flush until there is nothing more to flush
-        function nextFlush () {
-          var c = flushOne()
-          if (c) {
-            while (flushOne()) {
-              // nop
+      }
+    }, {
+      key: 'broadcast',
+      value: function broadcast(message) {
+        for (var key in globalRoom.buffers) {
+          globalRoom.buffers[key].push(JSON.parse(JSON.stringify([this.userId, message])));
+        }
+      }
+    }, {
+      key: 'isDisconnected',
+      value: function isDisconnected() {
+        return globalRoom.users[this.userId] == null;
+      }
+    }, {
+      key: 'reconnect',
+      value: function reconnect() {
+        if (this.isDisconnected()) {
+          globalRoom.addUser(this);
+          _get(Object.getPrototypeOf(Test.prototype), 'reconnect', this).call(this);
+        }
+        return this.flushAll();
+      }
+    }, {
+      key: 'disconnect',
+      value: function disconnect() {
+        if (!this.isDisconnected()) {
+          globalRoom.removeUser(this.userId);
+          _get(Object.getPrototypeOf(Test.prototype), 'disconnect', this).call(this);
+        }
+        return wait();
+      }
+    }, {
+      key: 'flush',
+      value: function flush() {
+        var self = this;
+        return async(regeneratorRuntime.mark(function _callee() {
+          var m;
+          return regeneratorRuntime.wrap(function _callee$(_context) {
+            while (1) {
+              switch (_context.prev = _context.next) {
+                case 0:
+                  _context.next = 2;
+                  return wait();
+
+                case 2:
+                  if (!(globalRoom.buffers[self.userId].length > 0)) {
+                    _context.next = 9;
+                    break;
+                  }
+
+                  m = globalRoom.buffers[self.userId].shift();
+
+                  this.receiveMessage(m[0], m[1]);
+                  _context.next = 7;
+                  return wait();
+
+                case 7:
+                  _context.next = 2;
+                  break;
+
+                case 9:
+                case 'end':
+                  return _context.stop();
+              }
+            }
+          }, _callee, this);
+        }));
+      }
+    }, {
+      key: 'flushAll',
+      value: function flushAll() {
+        return new Promise(function (resolve) {
+          // flushes may result in more created operations,
+          // flush until there is nothing more to flush
+          function nextFlush() {
+            var c = _flushOne();
+            if (c) {
+              while (_flushOne()) {
+                // nop
+              }
+              wait().then(nextFlush);
+            } else {
+              wait().then(function () {
+                resolve();
+              });
             }
-            wait().then(nextFlush)
-          } else {
-            wait().then(function () {
-              resolve()
-            })
           }
-        }
-        // in the case that there are
-        // still actions that want to be performed
-        wait().then(nextFlush)
-      })
-    }
-    /*
-      Flushes an operation for some user..
-    */
-    flushOne () {
-      flushOne()
-    }
-  }
+          // in the case that there are
+          // still actions that want to be performed
+          wait().then(nextFlush);
+        });
+      }
+      /*
+        Flushes an operation for some user..
+      */
 
-  Y.Test = Test
-}
+    }, {
+      key: 'flushOne',
+      value: function flushOne() {
+        _flushOne();
+      }
+    }]);
 
-},{}],3:[function(require,module,exports){
-'use strict'
+    return Test;
+  })(Y.AbstractConnector);
+
+  Y.Test = Test;
+};
+
+},{}],5:[function(require,module,exports){
+'use strict';
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 module.exports = function (Y) {
   /*
     Partial definition of an OperationStore.
     TODO: name it Database, operation store only holds operations.
-
-    A database definition must alse define the following methods:
+     A database definition must alse define the following methods:
     * logTable() (optional)
       - show relevant information information in a table
     * requestTransaction(makeGen)
@@ -485,336 +1567,633 @@ module.exports = function (Y) {
     * destroy()
       - destroy the database
   */
-  class AbstractDatabase {
-    constructor (y, opts) {
-      this.y = y
+
+  var AbstractDatabase = (function () {
+    function AbstractDatabase(y, opts) {
+      _classCallCheck(this, AbstractDatabase);
+
+      this.y = y;
+      // whether to broadcast all applied operations (insert & delete hook)
+      this.forwardAppliedOperations = false;
       // E.g. this.listenersById[id] : Array<Listener>
-      this.listenersById = {}
+      this.listenersById = {};
       // Execute the next time a transaction is requested
-      this.listenersByIdExecuteNow = []
+      this.listenersByIdExecuteNow = [];
       // A transaction is requested
-      this.listenersByIdRequestPending = false
+      this.listenersByIdRequestPending = false;
       /* To make things more clear, the following naming conventions:
          * ls : we put this.listenersById on ls
          * l : Array<Listener>
          * id : Id (can't use as property name)
          * sid : String (converted from id via JSON.stringify
                          so we can use it as a property name)
-
-        Always remember to first overwrite
+         Always remember to first overwrite
         a property before you iterate over it!
       */
       // TODO: Use ES7 Weak Maps. This way types that are no longer user,
       // wont be kept in memory.
-      this.initializedTypes = {}
-      this.whenUserIdSetListener = null
-      this.waitingTransactions = []
-      this.transactionInProgress = false
+      this.initializedTypes = {};
+      this.whenUserIdSetListener = null;
+      this.waitingTransactions = [];
+      this.transactionInProgress = false;
       if (typeof YConcurrency_TestingMode !== 'undefined') {
-        this.executeOrder = []
+        this.executeOrder = [];
       }
-      this.gc1 = [] // first stage
-      this.gc2 = [] // second stage -> after that, remove the op
-      this.gcTimeout = opts.gcTimeout || 5000
-      var os = this
-      function garbageCollect () {
-        return new Promise((resolve) => {
-          os.requestTransaction(function * () {
-            if (os.y.connector != null && os.y.connector.isSynced) {
-              for (var i in os.gc2) {
-                var oid = os.gc2[i]
-                yield* this.garbageCollectOperation(oid)
+      this.gc1 = []; // first stage
+      this.gc2 = []; // second stage -> after that, remove the op
+      this.gcTimeout = opts.gcTimeout || 5000;
+      var os = this;
+      function garbageCollect() {
+        return new Promise(function (resolve) {
+          os.requestTransaction(regeneratorRuntime.mark(function _callee() {
+            var i, oid;
+            return regeneratorRuntime.wrap(function _callee$(_context) {
+              while (1) {
+                switch (_context.prev = _context.next) {
+                  case 0:
+                    if (!(os.y.connector != null && os.y.connector.isSynced)) {
+                      _context.next = 10;
+                      break;
+                    }
+
+                    _context.t0 = regeneratorRuntime.keys(os.gc2);
+
+                  case 2:
+                    if ((_context.t1 = _context.t0()).done) {
+                      _context.next = 8;
+                      break;
+                    }
+
+                    i = _context.t1.value;
+                    oid = os.gc2[i];
+                    return _context.delegateYield(this.garbageCollectOperation(oid), 't2', 6);
+
+                  case 6:
+                    _context.next = 2;
+                    break;
+
+                  case 8:
+                    os.gc2 = os.gc1;
+                    os.gc1 = [];
+
+                  case 10:
+                    if (os.gcTimeout > 0) {
+                      os.gcInterval = setTimeout(garbageCollect, os.gcTimeout);
+                    }
+                    resolve();
+
+                  case 12:
+                  case 'end':
+                    return _context.stop();
+                }
               }
-              os.gc2 = os.gc1
-              os.gc1 = []
-            }
-            if (os.gcTimeout > 0) {
-              os.gcInterval = setTimeout(garbageCollect, os.gcTimeout)
-            }
-            resolve()
-          })
-        })
+            }, _callee, this);
+          }));
+        });
       }
-      this.garbageCollect = garbageCollect
+      this.garbageCollect = garbageCollect;
       if (this.gcTimeout > 0) {
-        garbageCollect()
+        garbageCollect();
       }
     }
-    addToDebug () {
-      if (typeof YConcurrency_TestingMode !== 'undefined') {
-        var command = Array.prototype.map.call(arguments, function (s) {
-          if (typeof s === 'string') {
-            return s
-          } else {
-            return JSON.stringify(s)
+
+    _createClass(AbstractDatabase, [{
+      key: 'addToDebug',
+      value: function addToDebug() {
+        if (typeof YConcurrency_TestingMode !== 'undefined') {
+          var command = Array.prototype.map.call(arguments, function (s) {
+            if (typeof s === 'string') {
+              return s;
+            } else {
+              return JSON.stringify(s);
+            }
+          }).join('').replace(/"/g, "'").replace(/,/g, ', ').replace(/:/g, ': ');
+          this.executeOrder.push(command);
+        }
+      }
+    }, {
+      key: 'getDebugData',
+      value: function getDebugData() {
+        console.log(this.executeOrder.join('\n'));
+      }
+    }, {
+      key: 'stopGarbageCollector',
+      value: function stopGarbageCollector() {
+        var self = this;
+        return new Promise(function (resolve) {
+          self.requestTransaction(regeneratorRuntime.mark(function _callee2() {
+            var ungc, i, op;
+            return regeneratorRuntime.wrap(function _callee2$(_context2) {
+              while (1) {
+                switch (_context2.prev = _context2.next) {
+                  case 0:
+                    ungc = self.gc1.concat(self.gc2);
+
+                    self.gc1 = [];
+                    self.gc2 = [];
+                    _context2.t0 = regeneratorRuntime.keys(ungc);
+
+                  case 4:
+                    if ((_context2.t1 = _context2.t0()).done) {
+                      _context2.next = 12;
+                      break;
+                    }
+
+                    i = _context2.t1.value;
+                    return _context2.delegateYield(this.getOperation(ungc[i]), 't2', 7);
+
+                  case 7:
+                    op = _context2.t2;
+
+                    delete op.gc;
+                    return _context2.delegateYield(this.setOperation(op), 't3', 10);
+
+                  case 10:
+                    _context2.next = 4;
+                    break;
+
+                  case 12:
+                    resolve();
+
+                  case 13:
+                  case 'end':
+                    return _context2.stop();
+                }
+              }
+            }, _callee2, this);
+          }));
+        });
+      }
+      /*
+        Try to add to GC.
+         TODO: rename this function
+         Rulez:
+        * Only gc if this user is online
+        * The most left element in a list must not be gc'd.
+          => There is at least one element in the list
+         returns true iff op was added to GC
+      */
+
+    }, {
+      key: 'addToGarbageCollector',
+      value: function addToGarbageCollector(op, left) {
+        if (op.gc == null && op.deleted === true && this.y.connector.isSynced && left != null && left.deleted === true) {
+          op.gc = true;
+          this.gc1.push(op.id);
+          return true;
+        } else {
+          return false;
+        }
+      }
+    }, {
+      key: 'removeFromGarbageCollector',
+      value: function removeFromGarbageCollector(op) {
+        function filter(o) {
+          return !Y.utils.compareIds(o, op.id);
+        }
+        this.gc1 = this.gc1.filter(filter);
+        this.gc2 = this.gc2.filter(filter);
+        delete op.gc;
+      }
+    }, {
+      key: 'destroy',
+      value: function destroy() {
+        clearInterval(this.gcInterval);
+        this.gcInterval = null;
+      }
+    }, {
+      key: 'setUserId',
+      value: function setUserId(userId) {
+        var self = this;
+        return new Promise(function (resolve) {
+          self.requestTransaction(regeneratorRuntime.mark(function _callee3() {
+            return regeneratorRuntime.wrap(function _callee3$(_context3) {
+              while (1) {
+                switch (_context3.prev = _context3.next) {
+                  case 0:
+                    self.userId = userId;
+                    return _context3.delegateYield(this.getState(userId), 't0', 2);
+
+                  case 2:
+                    self.opClock = _context3.t0.clock;
+
+                    if (self.whenUserIdSetListener != null) {
+                      self.whenUserIdSetListener();
+                      self.whenUserIdSetListener = null;
+                    }
+                    resolve();
+
+                  case 5:
+                  case 'end':
+                    return _context3.stop();
+                }
+              }
+            }, _callee3, this);
+          }));
+        });
+      }
+    }, {
+      key: 'whenUserIdSet',
+      value: function whenUserIdSet(f) {
+        if (this.userId != null) {
+          f();
+        } else {
+          this.whenUserIdSetListener = f;
+        }
+      }
+    }, {
+      key: 'getNextOpId',
+      value: function getNextOpId() {
+        if (this.userId == null) {
+          throw new Error('OperationStore not yet initialized!');
+        }
+        return [this.userId, this.opClock++];
+      }
+      /*
+        Apply a list of operations.
+         * get a transaction
+        * check whether all Struct.*.requiredOps are in the OS
+        * check if it is an expected op (otherwise wait for it)
+        * check if was deleted, apply a delete operation after op was applied
+      */
+
+    }, {
+      key: 'apply',
+      value: function apply(ops) {
+        for (var key in ops) {
+          var o = ops[key];
+          var required = Y.Struct[o.struct].requiredOps(o);
+          this.whenOperationsExist(required, o);
+        }
+      }
+      /*
+        op is executed as soon as every operation requested is available.
+        Note that Transaction can (and should) buffer requests.
+      */
+
+    }, {
+      key: 'whenOperationsExist',
+      value: function whenOperationsExist(ids, op) {
+        if (ids.length > 0) {
+          var listener = {
+            op: op,
+            missing: ids.length
+          };
+
+          for (var key in ids) {
+            var id = ids[key];
+            var sid = JSON.stringify(id);
+            var l = this.listenersById[sid];
+            if (l == null) {
+              l = [];
+              this.listenersById[sid] = l;
+            }
+            l.push(listener);
           }
-        }).join('').replace(/"/g, "'").replace(/,/g, ', ').replace(/:/g, ': ')
-        this.executeOrder.push(command)
-      }
-    }
-    getDebugData () {
-      console.log(this.executeOrder.join('\n'))
-    }
-    stopGarbageCollector () {
-      var self = this
-      return new Promise(function (resolve) {
-        self.requestTransaction(function * () {
-          var ungc = self.gc1.concat(self.gc2)
-          self.gc1 = []
-          self.gc2 = []
-          for (var i in ungc) {
-            var op = yield* this.getOperation(ungc[i])
-            delete op.gc
-            yield* this.setOperation(op)
-          }
-          resolve()
-        })
-      })
-    }
-    /*
-      Try to add to GC.
-
-      TODO: rename this function
-
-      Rulez:
-      * Only gc if this user is online
-      * The most left element in a list must not be gc'd.
-        => There is at least one element in the list
-
-      returns true iff op was added to GC
-    */
-    addToGarbageCollector (op, left) {
-      if (
-        op.gc == null &&
-        op.deleted === true &&
-        this.y.connector.isSynced &&
-        left != null &&
-        left.deleted === true
-      ) {
-        op.gc = true
-        this.gc1.push(op.id)
-        return true
-      } else {
-        return false
-      }
-    }
-    removeFromGarbageCollector (op) {
-      function filter (o) {
-        return !Y.utils.compareIds(o, op.id)
-      }
-      this.gc1 = this.gc1.filter(filter)
-      this.gc2 = this.gc2.filter(filter)
-      delete op.gc
-    }
-    destroy () {
-      clearInterval(this.gcInterval)
-      this.gcInterval = null
-    }
-    setUserId (userId) {
-      var self = this
-      return new Promise(function (resolve) {
-        self.requestTransaction(function * () {
-          self.userId = userId
-          self.opClock = (yield* this.getState(userId)).clock
-          if (self.whenUserIdSetListener != null) {
-            self.whenUserIdSetListener()
-            self.whenUserIdSetListener = null
-          }
-          resolve()
-        })
-      })
-    }
-    whenUserIdSet (f) {
-      if (this.userId != null) {
-        f()
-      } else {
-        this.whenUserIdSetListener = f
-      }
-    }
-    getNextOpId () {
-      if (this.userId == null) {
-        throw new Error('OperationStore not yet initialized!')
-      }
-      return [this.userId, this.opClock++]
-    }
-    /*
-      Apply a list of operations.
-
-      * get a transaction
-      * check whether all Struct.*.requiredOps are in the OS
-      * check if it is an expected op (otherwise wait for it)
-      * check if was deleted, apply a delete operation after op was applied
-    */
-    apply (ops) {
-      for (var key in ops) {
-        var o = ops[key]
-        var required = Y.Struct[o.struct].requiredOps(o)
-        this.whenOperationsExist(required, o)
-      }
-    }
-    /*
-      op is executed as soon as every operation requested is available.
-      Note that Transaction can (and should) buffer requests.
-    */
-    whenOperationsExist (ids, op) {
-      if (ids.length > 0) {
-        let listener = {
-          op: op,
-          missing: ids.length
+        } else {
+          this.listenersByIdExecuteNow.push({
+            op: op
+          });
         }
 
-        for (let key in ids) {
-          let id = ids[key]
-          let sid = JSON.stringify(id)
-          let l = this.listenersById[sid]
-          if (l == null) {
-            l = []
-            this.listenersById[sid] = l
-          }
-          l.push(listener)
-        }
-      } else {
-        this.listenersByIdExecuteNow.push({
-          op: op
-        })
-      }
-
-      if (this.listenersByIdRequestPending) {
-        return
-      }
-
-      this.listenersByIdRequestPending = true
-      var store = this
-
-      this.requestTransaction(function * () {
-        var exeNow = store.listenersByIdExecuteNow
-        store.listenersByIdExecuteNow = []
-
-        var ls = store.listenersById
-        store.listenersById = {}
-
-        store.listenersByIdRequestPending = false
-
-        for (let key in exeNow) {
-          let o = exeNow[key].op
-          yield* store.tryExecute.call(this, o)
+        if (this.listenersByIdRequestPending) {
+          return;
         }
 
-        for (var sid in ls) {
-          var l = ls[sid]
-          var id = JSON.parse(sid)
-          if ((yield* this.getOperation(id)) == null) {
-            store.listenersById[sid] = l
-          } else {
-            for (let key in l) {
-              let listener = l[key]
-              let o = listener.op
-              if (--listener.missing === 0) {
-                yield* store.tryExecute.call(this, o)
+        this.listenersByIdRequestPending = true;
+        var store = this;
+
+        this.requestTransaction(regeneratorRuntime.mark(function _callee4() {
+          var exeNow, ls, key, o, sid, l, id, listener;
+          return regeneratorRuntime.wrap(function _callee4$(_context4) {
+            while (1) {
+              switch (_context4.prev = _context4.next) {
+                case 0:
+                  exeNow = store.listenersByIdExecuteNow;
+
+                  store.listenersByIdExecuteNow = [];
+
+                  ls = store.listenersById;
+
+                  store.listenersById = {};
+
+                  store.listenersByIdRequestPending = false;
+
+                  _context4.t0 = regeneratorRuntime.keys(exeNow);
+
+                case 6:
+                  if ((_context4.t1 = _context4.t0()).done) {
+                    _context4.next = 12;
+                    break;
+                  }
+
+                  key = _context4.t1.value;
+                  o = exeNow[key].op;
+                  return _context4.delegateYield(store.tryExecute.call(this, o), 't2', 10);
+
+                case 10:
+                  _context4.next = 6;
+                  break;
+
+                case 12:
+                  _context4.t3 = regeneratorRuntime.keys(ls);
+
+                case 13:
+                  if ((_context4.t4 = _context4.t3()).done) {
+                    _context4.next = 34;
+                    break;
+                  }
+
+                  sid = _context4.t4.value;
+                  l = ls[sid];
+                  id = JSON.parse(sid);
+                  return _context4.delegateYield(this.getOperation(id), 't5', 18);
+
+                case 18:
+                  _context4.t6 = _context4.t5;
+
+                  if (!(_context4.t6 == null)) {
+                    _context4.next = 23;
+                    break;
+                  }
+
+                  store.listenersById[sid] = l;
+                  _context4.next = 32;
+                  break;
+
+                case 23:
+                  _context4.t7 = regeneratorRuntime.keys(l);
+
+                case 24:
+                  if ((_context4.t8 = _context4.t7()).done) {
+                    _context4.next = 32;
+                    break;
+                  }
+
+                  key = _context4.t8.value;
+                  listener = l[key];
+                  o = listener.op;
+
+                  if (!(--listener.missing === 0)) {
+                    _context4.next = 30;
+                    break;
+                  }
+
+                  return _context4.delegateYield(store.tryExecute.call(this, o), 't9', 30);
+
+                case 30:
+                  _context4.next = 24;
+                  break;
+
+                case 32:
+                  _context4.next = 13;
+                  break;
+
+                case 34:
+                case 'end':
+                  return _context4.stop();
               }
             }
-          }
-        }
-      })
-    }
-    /*
-      Actually execute an operation, when all expected operations are available.
-    */
-    * tryExecute (op) {
-      this.store.addToDebug('yield* this.store.tryExecute.call(this, ', JSON.stringify(op), ')')
-      if (op.struct === 'Delete') {
-        yield* Y.Struct.Delete.execute.call(this, op)
-        yield* this.store.operationAdded(this, op)
-      } else if ((yield* this.getOperation(op.id)) == null && !(yield* this.isGarbageCollected(op.id))) {
-        yield* Y.Struct[op.struct].execute.call(this, op)
-        yield* this.addOperation(op)
-        yield* this.store.operationAdded(this, op)
+          }, _callee4, this);
+        }));
       }
-    }
-    // called by a transaction when an operation is added
-    * operationAdded (transaction, op) {
-      if (op.struct === 'Delete') {
-        var target = yield* transaction.getOperation(op.target)
-        if (target != null) {
-          var type = transaction.store.initializedTypes[JSON.stringify(target.parent)]
-          if (type != null) {
-            yield* type._changed(transaction, {
-              struct: 'Delete',
-              target: op.target
-            })
-          }
-        }
-      } else {
-        // increase SS
-        var o = op
-        var state = yield* transaction.getState(op.id[0])
-        while (o != null && o.id[1] === state.clock && op.id[0] === o.id[0]) {
-          // either its a new operation (1. case), or it is an operation that was deleted, but is not yet in the OS
-          state.clock++
-          yield* transaction.checkDeleteStoreForState(state)
-          o = yield* transaction.os.findNext(o.id)
-        }
-        yield* transaction.setState(state)
+      /*
+        Actually execute an operation, when all expected operations are available.
+      */
 
-        // notify whenOperation listeners (by id)
-        var sid = JSON.stringify(op.id)
-        var l = this.listenersById[sid]
-        delete this.listenersById[sid]
+    }, {
+      key: 'tryExecute',
+      value: regeneratorRuntime.mark(function tryExecute(op) {
+        return regeneratorRuntime.wrap(function tryExecute$(_context5) {
+          while (1) {
+            switch (_context5.prev = _context5.next) {
+              case 0:
+                this.store.addToDebug('yield* this.store.tryExecute.call(this, ', JSON.stringify(op), ')');
 
-        if (l != null) {
-          for (var key in l) {
-            var listener = l[key]
-            if (--listener.missing === 0) {
-              this.whenOperationsExist([], listener.op)
+                if (!(op.struct === 'Delete')) {
+                  _context5.next = 6;
+                  break;
+                }
+
+                return _context5.delegateYield(Y.Struct.Delete.execute.call(this, op), 't0', 3);
+
+              case 3:
+                return _context5.delegateYield(this.store.operationAdded(this, op), 't1', 4);
+
+              case 4:
+                _context5.next = 16;
+                break;
+
+              case 6:
+                return _context5.delegateYield(this.getOperation(op.id), 't3', 7);
+
+              case 7:
+                _context5.t4 = _context5.t3;
+                _context5.t2 = _context5.t4 == null;
+
+                if (!_context5.t2) {
+                  _context5.next = 12;
+                  break;
+                }
+
+                return _context5.delegateYield(this.isGarbageCollected(op.id), 't5', 11);
+
+              case 11:
+                _context5.t2 = !_context5.t5;
+
+              case 12:
+                if (!_context5.t2) {
+                  _context5.next = 16;
+                  break;
+                }
+
+                return _context5.delegateYield(Y.Struct[op.struct].execute.call(this, op), 't6', 14);
+
+              case 14:
+                return _context5.delegateYield(this.addOperation(op), 't7', 15);
+
+              case 15:
+                return _context5.delegateYield(this.store.operationAdded(this, op), 't8', 16);
+
+              case 16:
+              case 'end':
+                return _context5.stop();
             }
           }
-        }
-        var t = this.initializedTypes[JSON.stringify(op.parent)]
-        // notify parent, if it has been initialized as a custom type
-        if (t != null) {
-          yield* t._changed(transaction, Y.utils.copyObject(op))
-        }
+        }, tryExecute, this);
+      })
+      // called by a transaction when an operation is added
 
-        // Delete if DS says this is actually deleted
-        if (!op.deleted && (yield* transaction.isDeleted(op.id))) {
-          var delop = {
-            struct: 'Delete',
-            target: op.id
-          }
-          yield* Y.Struct['Delete'].execute.call(transaction, delop)
-          if (t != null) {
-            yield* t._changed(transaction, delop)
+    }, {
+      key: 'operationAdded',
+      value: regeneratorRuntime.mark(function operationAdded(transaction, op) {
+        var target, type, o, state, sid, l, key, listener, t, delop;
+        return regeneratorRuntime.wrap(function operationAdded$(_context6) {
+          while (1) {
+            switch (_context6.prev = _context6.next) {
+              case 0:
+                if (!(op.struct === 'Delete')) {
+                  _context6.next = 9;
+                  break;
+                }
+
+                return _context6.delegateYield(transaction.getOperation(op.target), 't0', 2);
+
+              case 2:
+                target = _context6.t0;
+
+                if (!(target != null)) {
+                  _context6.next = 7;
+                  break;
+                }
+
+                type = transaction.store.initializedTypes[JSON.stringify(target.parent)];
+
+                if (!(type != null)) {
+                  _context6.next = 7;
+                  break;
+                }
+
+                return _context6.delegateYield(type._changed(transaction, {
+                  struct: 'Delete',
+                  target: op.target
+                }), 't1', 7);
+
+              case 7:
+                _context6.next = 36;
+                break;
+
+              case 9:
+                // increase SS
+                o = op;
+                return _context6.delegateYield(transaction.getState(op.id[0]), 't2', 11);
+
+              case 11:
+                state = _context6.t2;
+
+              case 12:
+                if (!(o != null && o.id[1] === state.clock && op.id[0] === o.id[0])) {
+                  _context6.next = 19;
+                  break;
+                }
+
+                // either its a new operation (1. case), or it is an operation that was deleted, but is not yet in the OS
+                state.clock++;
+                return _context6.delegateYield(transaction.checkDeleteStoreForState(state), 't3', 15);
+
+              case 15:
+                return _context6.delegateYield(transaction.os.findNext(o.id), 't4', 16);
+
+              case 16:
+                o = _context6.t4;
+                _context6.next = 12;
+                break;
+
+              case 19:
+                return _context6.delegateYield(transaction.setState(state), 't5', 20);
+
+              case 20:
+
+                // notify whenOperation listeners (by id)
+                sid = JSON.stringify(op.id);
+                l = this.listenersById[sid];
+
+                delete this.listenersById[sid];
+
+                if (l != null) {
+                  for (key in l) {
+                    listener = l[key];
+
+                    if (--listener.missing === 0) {
+                      this.whenOperationsExist([], listener.op);
+                    }
+                  }
+                }
+                t = this.initializedTypes[JSON.stringify(op.parent)];
+                // notify parent, if it has been initialized as a custom type
+
+                if (!(t != null)) {
+                  _context6.next = 27;
+                  break;
+                }
+
+                return _context6.delegateYield(t._changed(transaction, Y.utils.copyObject(op)), 't6', 27);
+
+              case 27:
+                _context6.t7 = !op.deleted;
+
+                if (!_context6.t7) {
+                  _context6.next = 31;
+                  break;
+                }
+
+                return _context6.delegateYield(transaction.isDeleted(op.id), 't8', 30);
+
+              case 30:
+                _context6.t7 = _context6.t8;
+
+              case 31:
+                if (!_context6.t7) {
+                  _context6.next = 36;
+                  break;
+                }
+
+                delop = {
+                  struct: 'Delete',
+                  target: op.id
+                };
+                return _context6.delegateYield(Y.Struct['Delete'].execute.call(transaction, delop), 't9', 34);
+
+              case 34:
+                if (!(t != null)) {
+                  _context6.next = 36;
+                  break;
+                }
+
+                return _context6.delegateYield(t._changed(transaction, delop), 't10', 36);
+
+              case 36:
+              case 'end':
+                return _context6.stop();
+            }
           }
+        }, operationAdded, this);
+      })
+    }, {
+      key: 'getNextRequest',
+      value: function getNextRequest() {
+        if (this.waitingTransactions.length === 0) {
+          this.transactionInProgress = false;
+          return null;
+        } else {
+          return this.waitingTransactions.shift();
         }
       }
-    }
-    getNextRequest () {
-      if (this.waitingTransactions.length === 0) {
-        this.transactionInProgress = false
-        return null
-      } else {
-        return this.waitingTransactions.shift()
+    }, {
+      key: 'requestTransaction',
+      value: function requestTransaction(makeGen, callImmediately) {
+        if (callImmediately) {
+          this.transact(makeGen);
+        } else if (!this.transactionInProgress) {
+          this.transactionInProgress = true;
+          var self = this;
+          setTimeout(function () {
+            self.transact(makeGen);
+          }, 0);
+        } else {
+          this.waitingTransactions.push(makeGen);
+        }
       }
-    }
-    requestTransaction (makeGen, callImmediately) {
-      if (callImmediately) {
-        this.transact(makeGen)
-      } else if (!this.transactionInProgress) {
-        this.transactionInProgress = true
-        var self = this
-        setTimeout(function () {
-          self.transact(makeGen)
-        }, 0)
-      } else {
-        this.waitingTransactions.push(makeGen)
-      }
-    }
-  }
-  Y.AbstractDatabase = AbstractDatabase
-}
+    }]);
 
-},{}],4:[function(require,module,exports){
-'use strict'
+    return AbstractDatabase;
+  })();
+
+  Y.AbstractDatabase = AbstractDatabase;
+};
+
+},{}],6:[function(require,module,exports){
+'use strict';
 
 /*
  An operation also defines the structure of a type. This is why operation and
@@ -834,25 +2213,39 @@ module.exports = function (Y) {
  * requiredOps
      - Operations that are required to execute this operation.
 */
+
 module.exports = function (Y) {
   var Struct = {
     /* This is the only operation that is actually not a structure, because
     it is not stored in the OS. This is why it _does not_ have an id
-
-    op = {
+     op = {
       target: Id
     }
     */
     Delete: {
-      encode: function (op) {
-        return op
+      encode: function encode(op) {
+        return op;
       },
-      requiredOps: function (op) {
-        return [] // [op.target]
+      requiredOps: function requiredOps(op) {
+        return []; // [op.target]
       },
-      execute: function * (op) {
-        return yield* this.deleteOperation(op.target)
-      }
+      execute: regeneratorRuntime.mark(function execute(op) {
+        return regeneratorRuntime.wrap(function execute$(_context) {
+          while (1) {
+            switch (_context.prev = _context.next) {
+              case 0:
+                return _context.delegateYield(this.deleteOperation(op.target), 't0', 1);
+
+              case 1:
+                return _context.abrupt('return', _context.t0);
+
+              case 2:
+              case 'end':
+                return _context.stop();
+            }
+          }
+        }, execute, this);
+      })
     },
     Insert: {
       /* {
@@ -865,7 +2258,7 @@ module.exports = function (Y) {
           parentSub: string (optional), // child of Map type
         }
       */
-      encode: function (op) {
+      encode: function encode(op) {
         // TODO: you could not send the "left" property, then you also have to
         // "op.left = null" in $execute or $decode
         var e = {
@@ -875,54 +2268,92 @@ module.exports = function (Y) {
           origin: op.origin,
           parent: op.parent,
           struct: op.struct
-        }
+        };
         if (op.parentSub != null) {
-          e.parentSub = op.parentSub
+          e.parentSub = op.parentSub;
         }
         if (op.opContent != null) {
-          e.opContent = op.opContent
+          e.opContent = op.opContent;
         } else {
-          e.content = op.content
+          e.content = op.content;
         }
 
-        return e
+        return e;
       },
-      requiredOps: function (op) {
-        var ids = []
+      requiredOps: function requiredOps(op) {
+        var ids = [];
         if (op.left != null) {
-          ids.push(op.left)
+          ids.push(op.left);
         }
         if (op.right != null) {
-          ids.push(op.right)
+          ids.push(op.right);
         }
         if (op.origin != null && !Y.utils.compareIds(op.left, op.origin)) {
-          ids.push(op.origin)
+          ids.push(op.origin);
         }
         // if (op.right == null && op.left == null) {
-        ids.push(op.parent)
+        ids.push(op.parent);
 
         if (op.opContent != null) {
-          ids.push(op.opContent)
+          ids.push(op.opContent);
         }
-        return ids
+        return ids;
       },
-      getDistanceToOrigin: function * (op) {
-        if (op.left == null) {
-          return 0
-        } else {
-          var d = 0
-          var o = yield* this.getOperation(op.left)
-          while (!Y.utils.compareIds(op.origin, (o ? o.id : null))) {
-            d++
-            if (o.left == null) {
-              break
-            } else {
-              o = yield* this.getOperation(o.left)
+      getDistanceToOrigin: regeneratorRuntime.mark(function getDistanceToOrigin(op) {
+        var d, o;
+        return regeneratorRuntime.wrap(function getDistanceToOrigin$(_context2) {
+          while (1) {
+            switch (_context2.prev = _context2.next) {
+              case 0:
+                if (!(op.left == null)) {
+                  _context2.next = 4;
+                  break;
+                }
+
+                return _context2.abrupt('return', 0);
+
+              case 4:
+                d = 0;
+                return _context2.delegateYield(this.getOperation(op.left), 't0', 6);
+
+              case 6:
+                o = _context2.t0;
+
+              case 7:
+                if (Y.utils.compareIds(op.origin, o ? o.id : null)) {
+                  _context2.next = 17;
+                  break;
+                }
+
+                d++;
+
+                if (!(o.left == null)) {
+                  _context2.next = 13;
+                  break;
+                }
+
+                return _context2.abrupt('break', 17);
+
+              case 13:
+                return _context2.delegateYield(this.getOperation(o.left), 't1', 14);
+
+              case 14:
+                o = _context2.t1;
+
+              case 15:
+                _context2.next = 7;
+                break;
+
+              case 17:
+                return _context2.abrupt('return', d);
+
+              case 18:
+              case 'end':
+                return _context2.stop();
             }
           }
-          return d
-        }
-      },
+        }, getDistanceToOrigin, this);
+      }),
       /*
       # $this has to find a unique position between origin and the next known character
       # case 1: $origin equals $o.origin: the $creator parameter decides if left or right
@@ -938,103 +2369,266 @@ module.exports = function (Y) {
       # case 3: $origin > $o.origin
       #         $this insert_position is to the left of $o (forever!)
       */
-      execute: function *(op) {
-        var i // loop counter
-        var distanceToOrigin = i = yield* Struct.Insert.getDistanceToOrigin.call(this, op) // most cases: 0 (starts from 0)
-        var o
-        var parent
-        var start
+      execute: regeneratorRuntime.mark(function execute(op) {
+        var i, distanceToOrigin, o, parent, start, startId, oOriginDistance, left, right;
+        return regeneratorRuntime.wrap(function execute$(_context3) {
+          while (1) {
+            switch (_context3.prev = _context3.next) {
+              case 0:
+                return _context3.delegateYield(Struct.Insert.getDistanceToOrigin.call(this, op), 't0', 1);
 
-        // find o. o is the first conflicting operation
-        if (op.left != null) {
-          o = yield* this.getOperation(op.left)
-          o = (o.right == null) ? null : yield* this.getOperation(o.right)
-        } else { // left == null
-          parent = yield* this.getOperation(op.parent)
-          let startId = op.parentSub ? parent.map[op.parentSub] : parent.start
-          start = startId == null ? null : yield* this.getOperation(startId)
-          o = start
-        }
+              case 1:
+                distanceToOrigin = i = _context3.t0;
 
-        // handle conflicts
-        while (true) {
-          if (o != null && !Y.utils.compareIds(o.id, op.right)) {
-            var oOriginDistance = yield* Struct.Insert.getDistanceToOrigin.call(this, o)
-            if (oOriginDistance === i) {
-              // case 1
-              if (o.id[0] < op.id[0]) {
-                op.left = o.id
-                distanceToOrigin = i + 1
-              }
-            } else if (oOriginDistance < i) {
-              // case 2
-              if (i - distanceToOrigin <= oOriginDistance) {
-                op.left = o.id
-                distanceToOrigin = i + 1
-              }
-            } else {
-              break
+                if (!(op.left != null)) {
+                  _context3.next = 14;
+                  break;
+                }
+
+                return _context3.delegateYield(this.getOperation(op.left), 't1', 4);
+
+              case 4:
+                o = _context3.t1;
+
+                if (!(o.right == null)) {
+                  _context3.next = 9;
+                  break;
+                }
+
+                _context3.t2 = null;
+                _context3.next = 11;
+                break;
+
+              case 9:
+                return _context3.delegateYield(this.getOperation(o.right), 't3', 10);
+
+              case 10:
+                _context3.t2 = _context3.t3;
+
+              case 11:
+                o = _context3.t2;
+                _context3.next = 25;
+                break;
+
+              case 14:
+                return _context3.delegateYield(this.getOperation(op.parent), 't4', 15);
+
+              case 15:
+                parent = _context3.t4;
+                startId = op.parentSub ? parent.map[op.parentSub] : parent.start;
+
+                if (!(startId == null)) {
+                  _context3.next = 21;
+                  break;
+                }
+
+                _context3.t5 = null;
+                _context3.next = 23;
+                break;
+
+              case 21:
+                return _context3.delegateYield(this.getOperation(startId), 't6', 22);
+
+              case 22:
+                _context3.t5 = _context3.t6;
+
+              case 23:
+                start = _context3.t5;
+
+                o = start;
+
+              case 25:
+                if (!true) {
+                  _context3.next = 51;
+                  break;
+                }
+
+                if (!(o != null && !Y.utils.compareIds(o.id, op.right))) {
+                  _context3.next = 48;
+                  break;
+                }
+
+                return _context3.delegateYield(Struct.Insert.getDistanceToOrigin.call(this, o), 't7', 28);
+
+              case 28:
+                oOriginDistance = _context3.t7;
+
+                if (!(oOriginDistance === i)) {
+                  _context3.next = 33;
+                  break;
+                }
+
+                // case 1
+                if (o.id[0] < op.id[0]) {
+                  op.left = o.id;
+                  distanceToOrigin = i + 1;
+                }
+                _context3.next = 38;
+                break;
+
+              case 33:
+                if (!(oOriginDistance < i)) {
+                  _context3.next = 37;
+                  break;
+                }
+
+                // case 2
+                if (i - distanceToOrigin <= oOriginDistance) {
+                  op.left = o.id;
+                  distanceToOrigin = i + 1;
+                }
+                _context3.next = 38;
+                break;
+
+              case 37:
+                return _context3.abrupt('break', 51);
+
+              case 38:
+                i++;
+
+                if (!o.right) {
+                  _context3.next = 44;
+                  break;
+                }
+
+                return _context3.delegateYield(this.getOperation(o.right), 't9', 41);
+
+              case 41:
+                _context3.t8 = _context3.t9;
+                _context3.next = 45;
+                break;
+
+              case 44:
+                _context3.t8 = null;
+
+              case 45:
+                o = _context3.t8;
+                _context3.next = 49;
+                break;
+
+              case 48:
+                return _context3.abrupt('break', 51);
+
+              case 49:
+                _context3.next = 25;
+                break;
+
+              case 51:
+
+                // reconnect..
+                left = null;
+                right = null;
+                _context3.t10 = parent;
+
+                if (_context3.t10) {
+                  _context3.next = 57;
+                  break;
+                }
+
+                return _context3.delegateYield(this.getOperation(op.parent), 't11', 56);
+
+              case 56:
+                _context3.t10 = _context3.t11;
+
+              case 57:
+                parent = _context3.t10;
+
+                if (!(op.left != null)) {
+                  _context3.next = 66;
+                  break;
+                }
+
+                return _context3.delegateYield(this.getOperation(op.left), 't12', 60);
+
+              case 60:
+                left = _context3.t12;
+
+                op.right = left.right;
+                left.right = op.id;
+
+                return _context3.delegateYield(this.setOperation(left), 't13', 64);
+
+              case 64:
+                _context3.next = 67;
+                break;
+
+              case 66:
+                op.right = op.parentSub ? parent.map[op.parentSub] || null : parent.start;
+
+              case 67:
+                if (!(op.right != null)) {
+                  _context3.next = 73;
+                  break;
+                }
+
+                return _context3.delegateYield(this.getOperation(op.right), 't14', 69);
+
+              case 69:
+                right = _context3.t14;
+
+                right.left = op.id;
+
+                // if right exists, and it is supposed to be gc'd. Remove it from the gc
+                if (right.gc != null) {
+                  this.store.removeFromGarbageCollector(right);
+                }
+                return _context3.delegateYield(this.setOperation(right), 't15', 73);
+
+              case 73:
+                if (!(op.parentSub != null)) {
+                  _context3.next = 83;
+                  break;
+                }
+
+                if (!(left == null)) {
+                  _context3.next = 77;
+                  break;
+                }
+
+                parent.map[op.parentSub] = op.id;
+                return _context3.delegateYield(this.setOperation(parent), 't16', 77);
+
+              case 77:
+                if (!(op.right != null)) {
+                  _context3.next = 79;
+                  break;
+                }
+
+                return _context3.delegateYield(this.deleteOperation(op.right, true), 't17', 79);
+
+              case 79:
+                if (!(op.left != null)) {
+                  _context3.next = 81;
+                  break;
+                }
+
+                return _context3.delegateYield(this.deleteOperation(op.id, true), 't18', 81);
+
+              case 81:
+                _context3.next = 87;
+                break;
+
+              case 83:
+                if (!(right == null || left == null)) {
+                  _context3.next = 87;
+                  break;
+                }
+
+                if (right == null) {
+                  parent.end = op.id;
+                }
+                if (left == null) {
+                  parent.start = op.id;
+                }
+                return _context3.delegateYield(this.setOperation(parent), 't19', 87);
+
+              case 87:
+              case 'end':
+                return _context3.stop();
             }
-            i++
-            o = o.right ? yield* this.getOperation(o.right) : null
-          } else {
-            break
           }
-        }
-
-        // reconnect..
-        var left = null
-        var right = null
-        parent = parent || (yield* this.getOperation(op.parent))
-
-        // reconnect left and set right of op
-        if (op.left != null) {
-          left = yield* this.getOperation(op.left)
-          op.right = left.right
-          left.right = op.id
-
-          yield* this.setOperation(left)
-        } else {
-          op.right = op.parentSub ? parent.map[op.parentSub] || null : parent.start
-        }
-        // reconnect right
-        if (op.right != null) {
-          right = yield* this.getOperation(op.right)
-          right.left = op.id
-
-          // if right exists, and it is supposed to be gc'd. Remove it from the gc
-          if (right.gc != null) {
-            this.store.removeFromGarbageCollector(right)
-          }
-          yield* this.setOperation(right)
-        }
-
-        // update parents .map/start/end properties
-        if (op.parentSub != null) {
-          if (left == null) {
-            parent.map[op.parentSub] = op.id
-            yield* this.setOperation(parent)
-          }
-          // is a child of a map struct.
-          // Then also make sure that only the most left element is not deleted
-          if (op.right != null) {
-            yield* this.deleteOperation(op.right, true)
-          }
-          if (op.left != null) {
-            yield* this.deleteOperation(op.id, true)
-          }
-        } else {
-          if (right == null || left == null) {
-            if (right == null) {
-              parent.end = op.id
-            }
-            if (left == null) {
-              parent.start = op.id
-            }
-            yield* this.setOperation(parent)
-          }
-        }
-      }
+        }, execute, this);
+      })
     },
     List: {
       /*
@@ -1046,14 +2640,14 @@ module.exports = function (Y) {
         id: this.os.getNextOpId()
       }
       */
-      encode: function (op) {
+      encode: function encode(op) {
         return {
           struct: 'List',
           id: op.id,
           type: op.type
-        }
+        };
       },
-      requiredOps: function () {
+      requiredOps: function requiredOps() {
         /*
         var ids = []
         if (op.start != null) {
@@ -1064,44 +2658,120 @@ module.exports = function (Y) {
         }
         return ids
         */
-        return []
+        return [];
       },
-      execute: function * (op) {
-        op.start = null
-        op.end = null
-      },
-      ref: function * (op, pos) {
-        if (op.start == null) {
-          return null
-        }
-        var res = null
-        var o = yield* this.getOperation(op.start)
+      execute: regeneratorRuntime.mark(function execute(op) {
+        return regeneratorRuntime.wrap(function execute$(_context4) {
+          while (1) {
+            switch (_context4.prev = _context4.next) {
+              case 0:
+                op.start = null;
+                op.end = null;
 
-        while (true) {
-          if (!o.deleted) {
-            res = o
-            pos--
+              case 2:
+              case 'end':
+                return _context4.stop();
+            }
           }
-          if (pos >= 0 && o.right != null) {
-            o = (yield* this.getOperation(o.right))
-          } else {
-            break
+        }, execute, this);
+      }),
+      ref: regeneratorRuntime.mark(function ref(op, pos) {
+        var res, o;
+        return regeneratorRuntime.wrap(function ref$(_context5) {
+          while (1) {
+            switch (_context5.prev = _context5.next) {
+              case 0:
+                if (!(op.start == null)) {
+                  _context5.next = 2;
+                  break;
+                }
+
+                return _context5.abrupt('return', null);
+
+              case 2:
+                res = null;
+                return _context5.delegateYield(this.getOperation(op.start), 't0', 4);
+
+              case 4:
+                o = _context5.t0;
+
+              case 5:
+                if (!true) {
+                  _context5.next = 15;
+                  break;
+                }
+
+                if (!o.deleted) {
+                  res = o;
+                  pos--;
+                }
+
+                if (!(pos >= 0 && o.right != null)) {
+                  _context5.next = 12;
+                  break;
+                }
+
+                return _context5.delegateYield(this.getOperation(o.right), 't1', 9);
+
+              case 9:
+                o = _context5.t1;
+                _context5.next = 13;
+                break;
+
+              case 12:
+                return _context5.abrupt('break', 15);
+
+              case 13:
+                _context5.next = 5;
+                break;
+
+              case 15:
+                return _context5.abrupt('return', res);
+
+              case 16:
+              case 'end':
+                return _context5.stop();
+            }
           }
-        }
-        return res
-      },
-      map: function * (o, f) {
-        o = o.start
-        var res = []
-        while (o != null) { // TODO: change to != (at least some convention)
-          var operation = yield* this.getOperation(o)
-          if (!operation.deleted) {
-            res.push(f(operation))
+        }, ref, this);
+      }),
+      map: regeneratorRuntime.mark(function map(o, f) {
+        var res, operation;
+        return regeneratorRuntime.wrap(function map$(_context6) {
+          while (1) {
+            switch (_context6.prev = _context6.next) {
+              case 0:
+                o = o.start;
+                res = [];
+
+              case 2:
+                if (!(o != null)) {
+                  _context6.next = 9;
+                  break;
+                }
+
+                return _context6.delegateYield(this.getOperation(o), 't0', 4);
+
+              case 4:
+                operation = _context6.t0;
+
+                if (!operation.deleted) {
+                  res.push(f(operation));
+                }
+                o = operation.right;
+                _context6.next = 2;
+                break;
+
+              case 9:
+                return _context6.abrupt('return', res);
+
+              case 10:
+              case 'end':
+                return _context6.stop();
+            }
           }
-          o = operation.right
-        }
-        return res
-      }
+        }, map, this);
+      })
     },
     Map: {
       /*
@@ -1112,47 +2782,121 @@ module.exports = function (Y) {
           id: this.os.getNextOpId()
         }
       */
-      encode: function (op) {
+      encode: function encode(op) {
         return {
           struct: 'Map',
           type: op.type,
           id: op.id,
           map: {} // overwrite map!!
-        }
+        };
       },
-      requiredOps: function () {
-        return []
+      requiredOps: function requiredOps() {
+        return [];
       },
-      execute: function * () {},
+      execute: regeneratorRuntime.mark(function execute() {
+        return regeneratorRuntime.wrap(function execute$(_context7) {
+          while (1) {
+            switch (_context7.prev = _context7.next) {
+              case 0:
+              case 'end':
+                return _context7.stop();
+            }
+          }
+        }, execute, this);
+      }),
       /*
         Get a property by name
       */
-      get: function * (op, name) {
-        var oid = op.map[name]
-        if (oid != null) {
-          var res = yield* this.getOperation(oid)
-          return (res == null || res.deleted) ? void 0 : (res.opContent == null
-            ? res.content : yield* this.getType(res.opContent))
-        }
-      },
+      get: regeneratorRuntime.mark(function get(op, name) {
+        var oid, res;
+        return regeneratorRuntime.wrap(function get$(_context8) {
+          while (1) {
+            switch (_context8.prev = _context8.next) {
+              case 0:
+                oid = op.map[name];
+
+                if (!(oid != null)) {
+                  _context8.next = 16;
+                  break;
+                }
+
+                return _context8.delegateYield(this.getOperation(oid), 't0', 3);
+
+              case 3:
+                res = _context8.t0;
+
+                if (!(res == null || res.deleted)) {
+                  _context8.next = 8;
+                  break;
+                }
+
+                _context8.t1 = void 0;
+                _context8.next = 15;
+                break;
+
+              case 8:
+                if (!(res.opContent == null)) {
+                  _context8.next = 12;
+                  break;
+                }
+
+                _context8.t2 = res.content;
+                _context8.next = 14;
+                break;
+
+              case 12:
+                return _context8.delegateYield(this.getType(res.opContent), 't3', 13);
+
+              case 13:
+                _context8.t2 = _context8.t3;
+
+              case 14:
+                _context8.t1 = _context8.t2;
+
+              case 15:
+                return _context8.abrupt('return', _context8.t1);
+
+              case 16:
+              case 'end':
+                return _context8.stop();
+            }
+          }
+        }, get, this);
+      }),
       /*
         Delete a property by name
       */
-      delete: function * (op, name) {
-        var v = op.map[name] || null
-        if (v != null) {
-          yield* Struct.Delete.create.call(this, {
-            target: v
-          })
-        }
-      }
-    }
-  }
-  Y.Struct = Struct
-}
+      delete: regeneratorRuntime.mark(function _delete(op, name) {
+        var v;
+        return regeneratorRuntime.wrap(function _delete$(_context9) {
+          while (1) {
+            switch (_context9.prev = _context9.next) {
+              case 0:
+                v = op.map[name] || null;
 
-},{}],5:[function(require,module,exports){
-'use strict'
+                if (!(v != null)) {
+                  _context9.next = 3;
+                  break;
+                }
+
+                return _context9.delegateYield(Struct.Delete.create.call(this, {
+                  target: v
+                }), 't0', 3);
+
+              case 3:
+              case 'end':
+                return _context9.stop();
+            }
+          }
+        }, _delete, this);
+      })
+    }
+  };
+  Y.Struct = Struct;
+};
+
+},{}],7:[function(require,module,exports){
+'use strict';
 
 /*
   Partial definition of a transaction
@@ -1227,884 +2971,2002 @@ module.exports = function (Y) {
      - this is called only by `getOperations(startSS)`. It makes an operation
        applyable on a given SS.
 */
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
 module.exports = function (Y) {
-  class Transaction {
-    /*
-      Get a type based on the id of its model.
-      If it does not exist yes, create it.
-      TODO: delete type from store.initializedTypes[id] when corresponding id was deleted!
-    */
-    * getType (id) {
-      var sid = JSON.stringify(id)
-      var t = this.store.initializedTypes[sid]
-      if (t == null) {
-        var op = yield* this.getOperation(id)
-        if (op != null) {
-          t = yield* Y[op.type].initType.call(this, this.store, op)
-          this.store.initializedTypes[sid] = t
-        }
-      }
-      return t
-    }
-    /*
-      Apply operations that this user created (no remote ones!)
-        * does not check for Struct.*.requiredOps()
-        * also broadcasts it through the connector
-    */
-    * applyCreatedOperations (ops) {
-      var send = []
-      for (var i = 0; i < ops.length; i++) {
-        var op = ops[i]
-        yield* this.store.tryExecute.call(this, op)
-        send.push(Y.Struct[op.struct].encode(op))
-      }
-      if (!this.store.y.connector.isDisconnected()) {
-        this.store.y.connector.broadcast({
-          type: 'update',
-          ops: send
-        })
-      }
+  var Transaction = (function () {
+    function Transaction() {
+      _classCallCheck(this, Transaction);
     }
 
-    * deleteList (start) {
-      if (this.store.y.connector.isSynced) {
-        while (start != null && this.store.y.connector.isSynced) {
-          start = (yield* this.getOperation(start))
-          start.gc = true
-          yield* this.setOperation(start)
-          // TODO: will always reset the parent..
-          this.store.gc1.push(start.id)
-          start = start.right
-        }
-      } else {
-        // TODO: when not possible??? do later in (gcWhenSynced)
-      }
-    }
+    _createClass(Transaction, [{
+      key: 'getType',
 
-    /*
-      Mark an operation as deleted, and add it to the GC, if possible.
-    */
-    * deleteOperation (targetId, preventCallType) {
-      var target = yield* this.getOperation(targetId)
-      var callType = false
+      /*
+        Get a type based on the id of its model.
+        If it does not exist yes, create it.
+        TODO: delete type from store.initializedTypes[id] when corresponding id was deleted!
+      */
+      value: regeneratorRuntime.mark(function getType(id) {
+        var sid, t, op;
+        return regeneratorRuntime.wrap(function getType$(_context) {
+          while (1) {
+            switch (_context.prev = _context.next) {
+              case 0:
+                sid = JSON.stringify(id);
+                t = this.store.initializedTypes[sid];
 
-      if (target == null || !target.deleted) {
-        yield* this.markDeleted(targetId)
-      }
+                if (!(t == null)) {
+                  _context.next = 9;
+                  break;
+                }
 
-      if (target != null && target.gc == null) {
-        if (!target.deleted) {
-          callType = true
-          // set deleted & notify type
-          target.deleted = true
-          /*
-          if (!preventCallType) {
-            var type = this.store.initializedTypes[JSON.stringify(target.parent)]
-            if (type != null) {
-              yield* type._changed(this, {
-                struct: 'Delete',
-                target: targetId
-              })
+                return _context.delegateYield(this.getOperation(id), 't0', 4);
+
+              case 4:
+                op = _context.t0;
+
+                if (!(op != null)) {
+                  _context.next = 9;
+                  break;
+                }
+
+                return _context.delegateYield(Y[op.type].initType.call(this, this.store, op), 't1', 7);
+
+              case 7:
+                t = _context.t1;
+
+                this.store.initializedTypes[sid] = t;
+
+              case 9:
+                return _context.abrupt('return', t);
+
+              case 10:
+              case 'end':
+                return _context.stop();
             }
           }
-          */
-          // delete containing lists
-          if (target.start != null) {
-            // TODO: don't do it like this .. -.-
-            yield* this.deleteList(target.start)
-            yield* this.deleteList(target.id)
-          }
-          if (target.map != null) {
-            for (var name in target.map) {
-              yield* this.deleteList(target.map[name])
-            }
-            // TODO: here to..  (see above)
-            yield* this.deleteList(target.id)
-          }
-          if (target.opContent != null) {
-            yield* this.deleteOperation(target.opContent)
-            target.opContent = null
-          }
-        }
-        var left = target.left != null ? yield* this.getOperation(target.left) : null
-
-        this.store.addToGarbageCollector(target, left)
-
-        // set here because it was deleted and/or gc'd
-        yield* this.setOperation(target)
-
-        /*
-          Check if it is possible to add right to the gc.
-          Because this delete can't be responsible for left being gc'd,
-          we don't have to add left to the gc..
-        */
-        var right = target.right != null ? yield* this.getOperation(target.right) : null
-        if (
-          right != null &&
-          this.store.addToGarbageCollector(right, target)
-        ) {
-          yield* this.setOperation(right)
-        }
-        return callType
-      }
-    }
-    /*
-      Mark an operation as deleted&gc'd
-    */
-    * markGarbageCollected (id) {
-      // this.mem.push(["gc", id]);
-      var n = yield* this.markDeleted(id)
-      if (!n.gc) {
-        if (n.id[1] < id[1]) {
-          // un-extend left
-          var newlen = n.len - (id[1] - n.id[1])
-          n.len -= newlen
-          yield* this.ds.put(n)
-          n = {id: id, len: newlen, gc: false}
-          yield* this.ds.put(n)
-        }
-        // get prev&next before adding a new operation
-        var prev = yield* this.ds.findPrev(id)
-        var next = yield* this.ds.findNext(id)
-
-        if (id[1] < n.id[1] + n.len - 1) {
-          // un-extend right
-          yield* this.ds.put({id: [id[0], id[1] + 1], len: n.len - 1, gc: false})
-          n.len = 1
-        }
-        // set gc'd
-        n.gc = true
-        // can extend left?
-        if (
-          prev != null &&
-          prev.gc &&
-          Y.utils.compareIds([prev.id[0], prev.id[1] + prev.len], n.id)
-        ) {
-          prev.len += n.len
-          yield* this.ds.delete(n.id)
-          n = prev
-          // ds.put n here?
-        }
-        // can extend right?
-        if (
-          next != null &&
-          next.gc &&
-          Y.utils.compareIds([n.id[0], n.id[1] + n.len], next.id)
-        ) {
-          n.len += next.len
-          yield* this.ds.delete(next.id)
-        }
-        yield* this.ds.put(n)
-      }
-    }
-    /*
-      Mark an operation as deleted.
-
-      returns the delete node
-    */
-    * markDeleted (id) {
-      // this.mem.push(["del", id]);
-      var n = yield* this.ds.findWithUpperBound(id)
-      if (n != null && n.id[0] === id[0]) {
-        if (n.id[1] <= id[1] && id[1] < n.id[1] + n.len) {
-          // already deleted
-          return n
-        } else if (n.id[1] + n.len === id[1] && !n.gc) {
-          // can extend existing deletion
-          n.len++
-        } else {
-          // cannot extend left
-          n = {id: id, len: 1, gc: false}
-          yield* this.ds.put(n)
-        }
-      } else {
-        // cannot extend left
-        n = {id: id, len: 1, gc: false}
-        yield* this.ds.put(n)
-      }
-      // can extend right?
-      var next = yield* this.ds.findNext(n.id)
-      if (
-        next != null &&
-        Y.utils.compareIds([n.id[0], n.id[1] + n.len], next.id) &&
-        !next.gc
-      ) {
-        n.len = n.len + next.len
-        yield* this.ds.delete(next.id)
-      }
-      yield* this.ds.put(n)
-      return n
-    }
-    /*
-      Call this method when the client is connected&synced with the
-      other clients (e.g. master). This will query the database for
-      operations that can be gc'd and add them to the garbage collector.
-    */
-    * garbageCollectAfterSync () {
-      yield* this.os.iterate(this, null, null, function * (op) {
-        if (op.deleted && op.left != null) {
-          var left = yield* this.getOperation(op.left)
-          this.store.addToGarbageCollector(op, left)
-        }
+        }, getType, this);
       })
-    }
-    /*
-      Really remove an op and all its effects.
-      The complicated case here is the Insert operation:
-      * reset left
-      * reset right
-      * reset parent.start
-      * reset parent.end
-      * reset origins of all right ops
-    */
-    * garbageCollectOperation (id) {
-      this.store.addToDebug('yield* this.garbageCollectOperation(', id, ')')
-      // check to increase the state of the respective user
-      var state = yield* this.getState(id[0])
-      if (state.clock === id[1]) {
-        state.clock++
-        // also check if more expected operations were gc'd
-        yield* this.checkDeleteStoreForState(state)
-        // then set the state
-        yield* this.setState(state)
-      }
-      yield* this.markGarbageCollected(id)
+      /*
+        Apply operations that this user created (no remote ones!)
+          * does not check for Struct.*.requiredOps()
+          * also broadcasts it through the connector
+      */
 
-      // if op exists, then clean that mess up..
-      var o = yield* this.getOperation(id)
-      if (o != null) {
-        /*
-        if (!o.deleted) {
-          yield* this.deleteOperation(id)
-          o = yield* this.getOperation(id)
-        }
-        */
+    }, {
+      key: 'applyCreatedOperations',
+      value: regeneratorRuntime.mark(function applyCreatedOperations(ops) {
+        var send, i, op;
+        return regeneratorRuntime.wrap(function applyCreatedOperations$(_context2) {
+          while (1) {
+            switch (_context2.prev = _context2.next) {
+              case 0:
+                send = [];
+                i = 0;
 
-        // remove gc'd op from the left op, if it exists
-        if (o.left != null) {
-          var left = yield* this.getOperation(o.left)
-          left.right = o.right
-          yield* this.setOperation(left)
-        }
-        // remove gc'd op from the right op, if it exists
-        // also reset origins of right ops
-        if (o.right != null) {
-          var right = yield* this.getOperation(o.right)
-          right.left = o.left
-          if (Y.utils.compareIds(right.origin, o.id)) { // rights origin is o
-            // find new origin of right ops
-            // origin is the first left deleted operation
-            var neworigin = o.left
-            while (neworigin != null) {
-              var neworigin_ = yield* this.getOperation(neworigin)
-              if (neworigin_.deleted) {
-                break
-              }
-              neworigin = neworigin_.left
+              case 2:
+                if (!(i < ops.length)) {
+                  _context2.next = 9;
+                  break;
+                }
+
+                op = ops[i];
+                return _context2.delegateYield(this.store.tryExecute.call(this, op), 't0', 5);
+
+              case 5:
+                send.push(Y.Struct[op.struct].encode(op));
+
+              case 6:
+                i++;
+                _context2.next = 2;
+                break;
+
+              case 9:
+                if (!this.store.y.connector.isDisconnected()) {
+                  // TODO: && !this.store.forwardAppliedOperations (but then i don't send delete ops)
+                  // is connected, and this is not going to be send in addOperation
+                  this.store.y.connector.broadcast({
+                    type: 'update',
+                    ops: send
+                  });
+                }
+
+              case 10:
+              case 'end':
+                return _context2.stop();
             }
+          }
+        }, applyCreatedOperations, this);
+      })
+    }, {
+      key: 'deleteList',
+      value: regeneratorRuntime.mark(function deleteList(start) {
+        return regeneratorRuntime.wrap(function deleteList$(_context3) {
+          while (1) {
+            switch (_context3.prev = _context3.next) {
+              case 0:
+                if (!this.store.y.connector.isSynced) {
+                  _context3.next = 12;
+                  break;
+                }
 
-            // reset origin of right
-            right.origin = neworigin
+              case 1:
+                if (!(start != null && this.store.y.connector.isSynced)) {
+                  _context3.next = 10;
+                  break;
+                }
+
+                return _context3.delegateYield(this.getOperation(start), 't0', 3);
+
+              case 3:
+                start = _context3.t0;
+
+                start.gc = true;
+                return _context3.delegateYield(this.setOperation(start), 't1', 6);
+
+              case 6:
+                // TODO: will always reset the parent..
+                this.store.gc1.push(start.id);
+                start = start.right;
+                _context3.next = 1;
+                break;
+
+              case 10:
+                _context3.next = 12;
+                break;
+
+              case 12:
+              case 'end':
+                return _context3.stop();
+            }
+          }
+        }, deleteList, this);
+      })
+
+      /*
+        Mark an operation as deleted, and add it to the GC, if possible.
+      */
+
+    }, {
+      key: 'deleteOperation',
+
+      // TODO: when not possible??? do later in (gcWhenSynced)
+      value: regeneratorRuntime.mark(function deleteOperation(targetId, preventCallType) {
+        var target, callType, name, left, right;
+        return regeneratorRuntime.wrap(function deleteOperation$(_context4) {
+          while (1) {
+            switch (_context4.prev = _context4.next) {
+              case 0:
+                return _context4.delegateYield(this.getOperation(targetId), 't0', 1);
+
+              case 1:
+                target = _context4.t0;
+                callType = false;
+
+                if (!(target == null || !target.deleted)) {
+                  _context4.next = 5;
+                  break;
+                }
+
+                return _context4.delegateYield(this.markDeleted(targetId), 't1', 5);
+
+              case 5:
+                if (!(target != null && target.gc == null)) {
+                  _context4.next = 42;
+                  break;
+                }
+
+                if (target.deleted) {
+                  _context4.next = 23;
+                  break;
+                }
+
+                callType = true;
+                // set deleted & notify type
+                target.deleted = true;
+                /*
+                if (!preventCallType) {
+                  var type = this.store.initializedTypes[JSON.stringify(target.parent)]
+                  if (type != null) {
+                    yield* type._changed(this, {
+                      struct: 'Delete',
+                      target: targetId
+                    })
+                  }
+                }
+                */
+                // delete containing lists
+
+                if (!(target.start != null)) {
+                  _context4.next = 12;
+                  break;
+                }
+
+                return _context4.delegateYield(this.deleteList(target.start), 't2', 11);
+
+              case 11:
+                return _context4.delegateYield(this.deleteList(target.id), 't3', 12);
+
+              case 12:
+                if (!(target.map != null)) {
+                  _context4.next = 20;
+                  break;
+                }
+
+                _context4.t4 = regeneratorRuntime.keys(target.map);
+
+              case 14:
+                if ((_context4.t5 = _context4.t4()).done) {
+                  _context4.next = 19;
+                  break;
+                }
+
+                name = _context4.t5.value;
+                return _context4.delegateYield(this.deleteList(target.map[name]), 't6', 17);
+
+              case 17:
+                _context4.next = 14;
+                break;
+
+              case 19:
+                return _context4.delegateYield(this.deleteList(target.id), 't7', 20);
+
+              case 20:
+                if (!(target.opContent != null)) {
+                  _context4.next = 23;
+                  break;
+                }
+
+                return _context4.delegateYield(this.deleteOperation(target.opContent), 't8', 22);
+
+              case 22:
+                target.opContent = null;
+
+              case 23:
+                if (!(target.left != null)) {
+                  _context4.next = 28;
+                  break;
+                }
+
+                return _context4.delegateYield(this.getOperation(target.left), 't10', 25);
+
+              case 25:
+                _context4.t9 = _context4.t10;
+                _context4.next = 29;
+                break;
+
+              case 28:
+                _context4.t9 = null;
+
+              case 29:
+                left = _context4.t9;
+
+                this.store.addToGarbageCollector(target, left);
+
+                // set here because it was deleted and/or gc'd
+                return _context4.delegateYield(this.setOperation(target), 't11', 32);
+
+              case 32:
+                if (!(target.right != null)) {
+                  _context4.next = 37;
+                  break;
+                }
+
+                return _context4.delegateYield(this.getOperation(target.right), 't13', 34);
+
+              case 34:
+                _context4.t12 = _context4.t13;
+                _context4.next = 38;
+                break;
+
+              case 37:
+                _context4.t12 = null;
+
+              case 38:
+                right = _context4.t12;
+
+                if (!(right != null && this.store.addToGarbageCollector(right, target))) {
+                  _context4.next = 41;
+                  break;
+                }
+
+                return _context4.delegateYield(this.setOperation(right), 't14', 41);
+
+              case 41:
+                return _context4.abrupt('return', callType);
+
+              case 42:
+              case 'end':
+                return _context4.stop();
+            }
+          }
+        }, deleteOperation, this);
+      })
+      /*
+        Mark an operation as deleted&gc'd
+      */
+
+    }, {
+      key: 'markGarbageCollected',
+      value: regeneratorRuntime.mark(function markGarbageCollected(id) {
+        var n, newlen, prev, next;
+        return regeneratorRuntime.wrap(function markGarbageCollected$(_context5) {
+          while (1) {
+            switch (_context5.prev = _context5.next) {
+              case 0:
+                return _context5.delegateYield(this.markDeleted(id), 't0', 1);
+
+              case 1:
+                n = _context5.t0;
+
+                if (n.gc) {
+                  _context5.next = 25;
+                  break;
+                }
+
+                if (!(n.id[1] < id[1])) {
+                  _context5.next = 9;
+                  break;
+                }
+
+                // un-extend left
+                newlen = n.len - (id[1] - n.id[1]);
+
+                n.len -= newlen;
+                return _context5.delegateYield(this.ds.put(n), 't1', 7);
+
+              case 7:
+                n = { id: id, len: newlen, gc: false };
+                return _context5.delegateYield(this.ds.put(n), 't2', 9);
+
+              case 9:
+                return _context5.delegateYield(this.ds.findPrev(id), 't3', 10);
+
+              case 10:
+                prev = _context5.t3;
+                return _context5.delegateYield(this.ds.findNext(id), 't4', 12);
+
+              case 12:
+                next = _context5.t4;
+
+                if (!(id[1] < n.id[1] + n.len - 1)) {
+                  _context5.next = 16;
+                  break;
+                }
+
+                return _context5.delegateYield(this.ds.put({ id: [id[0], id[1] + 1], len: n.len - 1, gc: false }), 't5', 15);
+
+              case 15:
+                n.len = 1;
+
+              case 16:
+                // set gc'd
+                n.gc = true;
+                // can extend left?
+
+                if (!(prev != null && prev.gc && Y.utils.compareIds([prev.id[0], prev.id[1] + prev.len], n.id))) {
+                  _context5.next = 21;
+                  break;
+                }
+
+                prev.len += n.len;
+                return _context5.delegateYield(this.ds.delete(n.id), 't6', 20);
+
+              case 20:
+                n = prev;
+                // ds.put n here?
+
+              case 21:
+                if (!(next != null && next.gc && Y.utils.compareIds([n.id[0], n.id[1] + n.len], next.id))) {
+                  _context5.next = 24;
+                  break;
+                }
+
+                n.len += next.len;
+                return _context5.delegateYield(this.ds.delete(next.id), 't7', 24);
+
+              case 24:
+                return _context5.delegateYield(this.ds.put(n), 't8', 25);
+
+              case 25:
+              case 'end':
+                return _context5.stop();
+            }
+          }
+        }, markGarbageCollected, this);
+      })
+      /*
+        Mark an operation as deleted.
+         returns the delete node
+      */
+
+    }, {
+      key: 'markDeleted',
+      value: regeneratorRuntime.mark(function markDeleted(id) {
+        var n, next;
+        return regeneratorRuntime.wrap(function markDeleted$(_context6) {
+          while (1) {
+            switch (_context6.prev = _context6.next) {
+              case 0:
+                return _context6.delegateYield(this.ds.findWithUpperBound(id), 't0', 1);
+
+              case 1:
+                n = _context6.t0;
+
+                if (!(n != null && n.id[0] === id[0])) {
+                  _context6.next = 15;
+                  break;
+                }
+
+                if (!(n.id[1] <= id[1] && id[1] < n.id[1] + n.len)) {
+                  _context6.next = 7;
+                  break;
+                }
+
+                return _context6.abrupt('return', n);
+
+              case 7:
+                if (!(n.id[1] + n.len === id[1] && !n.gc)) {
+                  _context6.next = 11;
+                  break;
+                }
+
+                // can extend existing deletion
+                n.len++;
+                _context6.next = 13;
+                break;
+
+              case 11:
+                // cannot extend left
+                n = { id: id, len: 1, gc: false };
+                return _context6.delegateYield(this.ds.put(n), 't1', 13);
+
+              case 13:
+                _context6.next = 17;
+                break;
+
+              case 15:
+                // cannot extend left
+                n = { id: id, len: 1, gc: false };
+                return _context6.delegateYield(this.ds.put(n), 't2', 17);
+
+              case 17:
+                return _context6.delegateYield(this.ds.findNext(n.id), 't3', 18);
+
+              case 18:
+                next = _context6.t3;
+
+                if (!(next != null && Y.utils.compareIds([n.id[0], n.id[1] + n.len], next.id) && !next.gc)) {
+                  _context6.next = 22;
+                  break;
+                }
+
+                n.len = n.len + next.len;
+                return _context6.delegateYield(this.ds.delete(next.id), 't4', 22);
+
+              case 22:
+                return _context6.delegateYield(this.ds.put(n), 't5', 23);
+
+              case 23:
+                return _context6.abrupt('return', n);
+
+              case 24:
+              case 'end':
+                return _context6.stop();
+            }
+          }
+        }, markDeleted, this);
+      })
+      /*
+        Call this method when the client is connected&synced with the
+        other clients (e.g. master). This will query the database for
+        operations that can be gc'd and add them to the garbage collector.
+      */
+
+    }, {
+      key: 'garbageCollectAfterSync',
+      value: regeneratorRuntime.mark(function garbageCollectAfterSync() {
+        return regeneratorRuntime.wrap(function garbageCollectAfterSync$(_context8) {
+          while (1) {
+            switch (_context8.prev = _context8.next) {
+              case 0:
+                return _context8.delegateYield(this.os.iterate(this, null, null, regeneratorRuntime.mark(function _callee(op) {
+                  var left;
+                  return regeneratorRuntime.wrap(function _callee$(_context7) {
+                    while (1) {
+                      switch (_context7.prev = _context7.next) {
+                        case 0:
+                          if (!(op.deleted && op.left != null)) {
+                            _context7.next = 4;
+                            break;
+                          }
+
+                          return _context7.delegateYield(this.getOperation(op.left), 't0', 2);
+
+                        case 2:
+                          left = _context7.t0;
+
+                          this.store.addToGarbageCollector(op, left);
+
+                        case 4:
+                        case 'end':
+                          return _context7.stop();
+                      }
+                    }
+                  }, _callee, this);
+                })), 't0', 1);
+
+              case 1:
+              case 'end':
+                return _context8.stop();
+            }
+          }
+        }, garbageCollectAfterSync, this);
+      })
+      /*
+        Really remove an op and all its effects.
+        The complicated case here is the Insert operation:
+        * reset left
+        * reset right
+        * reset parent.start
+        * reset parent.end
+        * reset origins of all right ops
+      */
+
+    }, {
+      key: 'garbageCollectOperation',
+      value: regeneratorRuntime.mark(function garbageCollectOperation(id) {
+        var state, o, left, right, neworigin, neworigin_, i, ids, parent, setParent;
+        return regeneratorRuntime.wrap(function garbageCollectOperation$(_context9) {
+          while (1) {
+            switch (_context9.prev = _context9.next) {
+              case 0:
+                this.store.addToDebug('yield* this.garbageCollectOperation(', id, ')');
+                // check to increase the state of the respective user
+                return _context9.delegateYield(this.getState(id[0]), 't0', 2);
+
+              case 2:
+                state = _context9.t0;
+
+                if (!(state.clock === id[1])) {
+                  _context9.next = 7;
+                  break;
+                }
+
+                state.clock++;
+                // also check if more expected operations were gc'd
+                return _context9.delegateYield(this.checkDeleteStoreForState(state), 't1', 6);
+
+              case 6:
+                return _context9.delegateYield(this.setState(state), 't2', 7);
+
+              case 7:
+                return _context9.delegateYield(this.markGarbageCollected(id), 't3', 8);
+
+              case 8:
+                return _context9.delegateYield(this.getOperation(id), 't4', 9);
+
+              case 9:
+                o = _context9.t4;
+
+                if (!(o != null)) {
+                  _context9.next = 61;
+                  break;
+                }
+
+                if (!(o.left != null)) {
+                  _context9.next = 16;
+                  break;
+                }
+
+                return _context9.delegateYield(this.getOperation(o.left), 't5', 13);
+
+              case 13:
+                left = _context9.t5;
+
+                left.right = o.right;
+                return _context9.delegateYield(this.setOperation(left), 't6', 16);
+
+              case 16:
+                if (!(o.right != null)) {
+                  _context9.next = 53;
+                  break;
+                }
+
+                return _context9.delegateYield(this.getOperation(o.right), 't7', 18);
+
+              case 18:
+                right = _context9.t7;
+
+                right.left = o.left;
+
+                if (!Y.utils.compareIds(right.origin, o.id)) {
+                  _context9.next = 52;
+                  break;
+                }
+
+                // rights origin is o
+                // find new origin of right ops
+                // origin is the first left deleted operation
+                neworigin = o.left;
+
+              case 22:
+                if (!(neworigin != null)) {
+                  _context9.next = 30;
+                  break;
+                }
+
+                return _context9.delegateYield(this.getOperation(neworigin), 't8', 24);
+
+              case 24:
+                neworigin_ = _context9.t8;
+
+                if (!neworigin_.deleted) {
+                  _context9.next = 27;
+                  break;
+                }
+
+                return _context9.abrupt('break', 30);
+
+              case 27:
+                neworigin = neworigin_.left;
+                _context9.next = 22;
+                break;
+
+              case 30:
+
+                // reset origin of right
+                right.origin = neworigin;
+
+                // reset origin of all right ops (except first right - duh!),
+                // until you find origin pointer to the left of o
+
+                if (!(right.right == null)) {
+                  _context9.next = 35;
+                  break;
+                }
+
+                _context9.t9 = null;
+                _context9.next = 37;
+                break;
+
+              case 35:
+                return _context9.delegateYield(this.getOperation(right.right), 't10', 36);
+
+              case 36:
+                _context9.t9 = _context9.t10;
+
+              case 37:
+                i = _context9.t9;
+                ids = [o.id, o.right];
+
+              case 39:
+                if (!(i != null && ids.some(function (id) {
+                  return Y.utils.compareIds(id, i.origin);
+                }))) {
+                  _context9.next = 52;
+                  break;
+                }
+
+                if (!Y.utils.compareIds(i.origin, o.id)) {
+                  _context9.next = 43;
+                  break;
+                }
 
-            // reset origin of all right ops (except first right - duh!),
-            // until you find origin pointer to the left of o
-            var i = right.right == null ? null : yield* this.getOperation(right.right)
-            var ids = [o.id, o.right]
-            while (i != null && ids.some(function (id) {
-              return Y.utils.compareIds(id, i.origin)
-            })) {
-              if (Y.utils.compareIds(i.origin, o.id)) {
                 // reset origin of i
-                i.origin = neworigin
-                yield* this.setOperation(i)
-              }
-              // get next i
-              i = i.right == null ? null : yield* this.getOperation(i.right)
-            }
-          } /* otherwise, rights origin is to the left of o,
-               then there is no right op (from o), that origins in o */
-          yield* this.setOperation(right)
-        }
+                i.origin = neworigin;
+                return _context9.delegateYield(this.setOperation(i), 't11', 43);
 
-        if (o.parent != null) {
-          // remove gc'd op from parent, if it exists
-          var parent = yield* this.getOperation(o.parent)
-          var setParent = false // whether to save parent to the os
-          if (o.parentSub != null) {
-            if (Y.utils.compareIds(parent.map[o.parentSub], o.id)) {
-              setParent = true
-              parent.map[o.parentSub] = o.right
-            }
-          } else {
-            if (Y.utils.compareIds(parent.start, o.id)) {
-              // gc'd op is the start
-              setParent = true
-              parent.start = o.right
-            }
-            if (Y.utils.compareIds(parent.end, o.id)) {
-              // gc'd op is the end
-              setParent = true
-              parent.end = o.left
+              case 43:
+                if (!(i.right == null)) {
+                  _context9.next = 47;
+                  break;
+                }
+
+                _context9.t12 = null;
+                _context9.next = 49;
+                break;
+
+              case 47:
+                return _context9.delegateYield(this.getOperation(i.right), 't13', 48);
+
+              case 48:
+                _context9.t12 = _context9.t13;
+
+              case 49:
+                i = _context9.t12;
+                _context9.next = 39;
+                break;
+
+              case 52:
+                return _context9.delegateYield(this.setOperation(right), 't14', 53);
+
+              case 53:
+                if (!(o.parent != null)) {
+                  _context9.next = 60;
+                  break;
+                }
+
+                return _context9.delegateYield(this.getOperation(o.parent), 't15', 55);
+
+              case 55:
+                parent = _context9.t15;
+                setParent = false; // whether to save parent to the os
+
+                if (o.parentSub != null) {
+                  if (Y.utils.compareIds(parent.map[o.parentSub], o.id)) {
+                    setParent = true;
+                    parent.map[o.parentSub] = o.right;
+                  }
+                } else {
+                  if (Y.utils.compareIds(parent.start, o.id)) {
+                    // gc'd op is the start
+                    setParent = true;
+                    parent.start = o.right;
+                  }
+                  if (Y.utils.compareIds(parent.end, o.id)) {
+                    // gc'd op is the end
+                    setParent = true;
+                    parent.end = o.left;
+                  }
+                }
+
+                if (!setParent) {
+                  _context9.next = 60;
+                  break;
+                }
+
+                return _context9.delegateYield(this.setOperation(parent), 't16', 60);
+
+              case 60:
+                return _context9.delegateYield(this.removeOperation(o.id), 't17', 61);
+
+              case 61:
+              case 'end':
+                return _context9.stop();
             }
           }
-          if (setParent) {
-            yield* this.setOperation(parent)
-          }
-        }
-        // finally remove it from the os
-        yield* this.removeOperation(o.id)
-      }
-    }
-    * checkDeleteStoreForState (state) {
-      var n = yield* this.ds.findWithUpperBound([state.user, state.clock])
-      if (n != null && n.id[0] === state.user && n.gc) {
-        state.clock = Math.max(state.clock, n.id[1] + n.len)
-      }
-    }
-    /*
-      apply a delete set in order to get
-      the state of the supplied ds
-    */
-    * applyDeleteSet (ds) {
-      var deletions = []
-      function createDeletions (user, start, len, gc) {
-        for (var c = start; c < start + len; c++) {
-          deletions.push([user, c, gc])
-        }
-      }
+        }, garbageCollectOperation, this);
+      })
+    }, {
+      key: 'checkDeleteStoreForState',
+      value: regeneratorRuntime.mark(function checkDeleteStoreForState(state) {
+        var n;
+        return regeneratorRuntime.wrap(function checkDeleteStoreForState$(_context10) {
+          while (1) {
+            switch (_context10.prev = _context10.next) {
+              case 0:
+                return _context10.delegateYield(this.ds.findWithUpperBound([state.user, state.clock]), 't0', 1);
 
-      for (var user in ds) {
-        var dv = ds[user]
-        var pos = 0
-        var d = dv[pos]
-        yield* this.ds.iterate(this, [user, 0], [user, Number.MAX_VALUE], function * (n) {
-          // cases:
-          // 1. d deletes something to the right of n
-          //  => go to next n (break)
-          // 2. d deletes something to the left of n
-          //  => create deletions
-          //  => reset d accordingly
-          //  *)=> if d doesn't delete anything anymore, go to next d (continue)
-          // 3. not 2) and d deletes something that also n deletes
-          //  => reset d so that it doesn't contain n's deletion
-          //  *)=> if d does not delete anything anymore, go to next d (continue)
-          while (d != null) {
-            var diff = 0 // describe the diff of length in 1) and 2)
-            if (n.id[1] + n.len <= d[0]) {
-              // 1)
-              break
-            } else if (d[0] < n.id[1]) {
-              // 2)
-              // delete maximum the len of d
-              // else delete as much as possible
-              diff = Math.min(n.id[1] - d[0], d[1])
-              createDeletions(user, d[0], diff, d[2])
-            } else {
-              // 3)
-              diff = n.id[1] + n.len - d[0] // never null (see 1)
-              if (d[2] && !n.gc) {
-                // d marks as gc'd but n does not
-                // then delete either way
-                createDeletions(user, d[0], Math.min(diff, d[1]), d[2])
-              }
-            }
-            if (d[1] <= diff) {
-              // d doesn't delete anything anymore
-              d = dv[++pos]
-            } else {
-              d[0] = d[0] + diff // reset pos
-              d[1] = d[1] - diff // reset length
+              case 1:
+                n = _context10.t0;
+
+                if (n != null && n.id[0] === state.user && n.gc) {
+                  state.clock = Math.max(state.clock, n.id[1] + n.len);
+                }
+
+              case 3:
+              case 'end':
+                return _context10.stop();
             }
           }
-        })
-        // for the rest.. just apply it
-        for (; pos < dv.length; pos++) {
-          d = dv[pos]
-          createDeletions(user, d[0], d[1], d[2])
-        }
-      }
-      for (var i in deletions) {
-        var del = deletions[i]
-        var id = [del[0], del[1]]
-        // always try to delete..
-        var addOperation = yield* this.deleteOperation(id)
-        if (addOperation) {
-          // TODO:.. really .. here? You could prevent calling all these functions in operationAdded
-          yield* this.store.operationAdded(this, {struct: 'Delete', target: id})
-        }
-        if (del[2]) {
-          // gc
-          yield* this.garbageCollectOperation(id)
-        }
-      }
-    }
-    * isGarbageCollected (id) {
-      var n = yield* this.ds.findWithUpperBound(id)
-      return n != null && n.id[0] === id[0] && id[1] < n.id[1] + n.len && n.gc
-    }
-    /*
-      A DeleteSet (ds) describes all the deleted ops in the OS
-    */
-    * getDeleteSet () {
-      var ds = {}
-      yield* this.ds.iterate(this, null, null, function * (n) {
-        var user = n.id[0]
-        var counter = n.id[1]
-        var len = n.len
-        var gc = n.gc
-        var dv = ds[user]
-        if (dv === void 0) {
-          dv = []
-          ds[user] = dv
-        }
-        dv.push([counter, len, gc])
+        }, checkDeleteStoreForState, this);
       })
-      return ds
-    }
-    * isDeleted (id) {
-      var n = yield* this.ds.findWithUpperBound(id)
-      return n != null && n.id[0] === id[0] && id[1] < n.id[1] + n.len
-    }
-    * setOperation (op) {
-      yield* this.os.put(op)
-      return op
-    }
-    * addOperation (op) {
-      yield* this.os.put(op)
-    }
-    * getOperation (id) {
-      return yield* this.os.find(id)
-    }
-    * removeOperation (id) {
-      yield* this.os.delete(id)
-    }
-    * setState (state) {
-      var val = {
-        id: [state.user],
-        clock: state.clock
-      }
-      // TODO: find a way to skip this step.. (after implementing some dbs..)
-      if (yield* this.ss.find([state.user])) {
-        yield* this.ss.put(val)
-      } else {
-        yield* this.ss.put(val)
-      }
-    }
-    * getState (user) {
-      var n
-      var clock = (n = yield* this.ss.find([user])) == null ? null : n.clock
-      if (clock == null) {
-        clock = 0
-      }
-      return {
-        user: user,
-        clock: clock
-      }
-    }
-    * getStateVector () {
-      var stateVector = []
-      yield* this.ss.iterate(this, null, null, function * (n) {
-        stateVector.push({
-          user: n.id[0],
-          clock: n.clock
-        })
+      /*
+        apply a delete set in order to get
+        the state of the supplied ds
+      */
+
+    }, {
+      key: 'applyDeleteSet',
+      value: regeneratorRuntime.mark(function applyDeleteSet(ds) {
+        var deletions, createDeletions, user, dv, pos, d, i, del, id, addOperation, ops;
+        return regeneratorRuntime.wrap(function applyDeleteSet$(_context12) {
+          while (1) {
+            switch (_context12.prev = _context12.next) {
+              case 0:
+                createDeletions = function createDeletions(user, start, len, gc) {
+                  for (var c = start; c < start + len; c++) {
+                    deletions.push([user, c, gc]);
+                  }
+                };
+
+                deletions = [];
+                _context12.t0 = regeneratorRuntime.keys(ds);
+
+              case 3:
+                if ((_context12.t1 = _context12.t0()).done) {
+                  _context12.next = 12;
+                  break;
+                }
+
+                user = _context12.t1.value;
+                dv = ds[user];
+                pos = 0;
+                d = dv[pos];
+                return _context12.delegateYield(this.ds.iterate(this, [user, 0], [user, Number.MAX_VALUE], regeneratorRuntime.mark(function _callee2(n) {
+                  var diff;
+                  return regeneratorRuntime.wrap(function _callee2$(_context11) {
+                    while (1) {
+                      switch (_context11.prev = _context11.next) {
+                        case 0:
+                          if (!(d != null)) {
+                            _context11.next = 10;
+                            break;
+                          }
+
+                          diff = 0; // describe the diff of length in 1) and 2)
+
+                          if (!(n.id[1] + n.len <= d[0])) {
+                            _context11.next = 6;
+                            break;
+                          }
+
+                          return _context11.abrupt('break', 10);
+
+                        case 6:
+                          if (d[0] < n.id[1]) {
+                            // 2)
+                            // delete maximum the len of d
+                            // else delete as much as possible
+                            diff = Math.min(n.id[1] - d[0], d[1]);
+                            createDeletions(user, d[0], diff, d[2]);
+                          } else {
+                            // 3)
+                            diff = n.id[1] + n.len - d[0]; // never null (see 1)
+                            if (d[2] && !n.gc) {
+                              // d marks as gc'd but n does not
+                              // then delete either way
+                              createDeletions(user, d[0], Math.min(diff, d[1]), d[2]);
+                            }
+                          }
+
+                        case 7:
+                          if (d[1] <= diff) {
+                            // d doesn't delete anything anymore
+                            d = dv[++pos];
+                          } else {
+                            d[0] = d[0] + diff; // reset pos
+                            d[1] = d[1] - diff; // reset length
+                          }
+                          _context11.next = 0;
+                          break;
+
+                        case 10:
+                        case 'end':
+                          return _context11.stop();
+                      }
+                    }
+                  }, _callee2, this);
+                })), 't2', 9);
+
+              case 9:
+                // for the rest.. just apply it
+                for (; pos < dv.length; pos++) {
+                  d = dv[pos];
+                  createDeletions(user, d[0], d[1], d[2]);
+                }
+                _context12.next = 3;
+                break;
+
+              case 12:
+                _context12.t3 = regeneratorRuntime.keys(deletions);
+
+              case 13:
+                if ((_context12.t4 = _context12.t3()).done) {
+                  _context12.next = 25;
+                  break;
+                }
+
+                i = _context12.t4.value;
+                del = deletions[i];
+                id = [del[0], del[1]];
+                // always try to delete..
+
+                return _context12.delegateYield(this.deleteOperation(id), 't5', 18);
+
+              case 18:
+                addOperation = _context12.t5;
+
+                if (!addOperation) {
+                  _context12.next = 21;
+                  break;
+                }
+
+                return _context12.delegateYield(this.store.operationAdded(this, { struct: 'Delete', target: id }), 't6', 21);
+
+              case 21:
+                if (!del[2]) {
+                  _context12.next = 23;
+                  break;
+                }
+
+                return _context12.delegateYield(this.garbageCollectOperation(id), 't7', 23);
+
+              case 23:
+                _context12.next = 13;
+                break;
+
+              case 25:
+                if (this.store.forwardAppliedOperations) {
+                  ops = deletions.map(function (d) {
+                    return { struct: 'Delete', target: [d[0], d[1]] };
+                  });
+
+                  this.store.y.connector.broadcast({
+                    type: 'update',
+                    ops: ops
+                  });
+                }
+
+              case 26:
+              case 'end':
+                return _context12.stop();
+            }
+          }
+        }, applyDeleteSet, this);
       })
-      return stateVector
-    }
-    * getStateSet () {
-      var ss = {}
-      yield* this.ss.iterate(this, null, null, function * (n) {
-        ss[n.id[0]] = n.clock
+    }, {
+      key: 'isGarbageCollected',
+      value: regeneratorRuntime.mark(function isGarbageCollected(id) {
+        var n;
+        return regeneratorRuntime.wrap(function isGarbageCollected$(_context13) {
+          while (1) {
+            switch (_context13.prev = _context13.next) {
+              case 0:
+                return _context13.delegateYield(this.ds.findWithUpperBound(id), 't0', 1);
+
+              case 1:
+                n = _context13.t0;
+                return _context13.abrupt('return', n != null && n.id[0] === id[0] && id[1] < n.id[1] + n.len && n.gc);
+
+              case 3:
+              case 'end':
+                return _context13.stop();
+            }
+          }
+        }, isGarbageCollected, this);
       })
-      return ss
-    }
-    * getOperations (startSS) {
-      // TODO: use bounds here!
-      if (startSS == null) {
-        startSS = {}
-      }
-      var ops = []
+      /*
+        A DeleteSet (ds) describes all the deleted ops in the OS
+      */
 
-      var endSV = yield* this.getStateVector()
-      for (var endState of endSV) {
-        var user = endState.user
-        if (user === '_') {
-          continue
-        }
-        var startPos = startSS[user] || 0
+    }, {
+      key: 'getDeleteSet',
+      value: regeneratorRuntime.mark(function getDeleteSet() {
+        var ds;
+        return regeneratorRuntime.wrap(function getDeleteSet$(_context15) {
+          while (1) {
+            switch (_context15.prev = _context15.next) {
+              case 0:
+                ds = {};
+                return _context15.delegateYield(this.ds.iterate(this, null, null, regeneratorRuntime.mark(function _callee3(n) {
+                  var user, counter, len, gc, dv;
+                  return regeneratorRuntime.wrap(function _callee3$(_context14) {
+                    while (1) {
+                      switch (_context14.prev = _context14.next) {
+                        case 0:
+                          user = n.id[0];
+                          counter = n.id[1];
+                          len = n.len;
+                          gc = n.gc;
+                          dv = ds[user];
 
-        yield* this.os.iterate(this, [user, startPos], [user, Number.MAX_VALUE], function * (op) {
-          ops.push(op)
-        })
-      }
-      var res = []
-      for (var op of ops) {
-        res.push(yield* this.makeOperationReady(startSS, op))
-      }
-      return res
-    }
-    /*
-      Here, we make op executable for the receiving user.
+                          if (dv === void 0) {
+                            dv = [];
+                            ds[user] = dv;
+                          }
+                          dv.push([counter, len, gc]);
 
-      Notes:
-        startSS: denotes to the SV that the remote user sent
-        currSS:  denotes to the state vector that the user should have if he
-                 applies all already sent operations (increases is each step)
+                        case 7:
+                        case 'end':
+                          return _context14.stop();
+                      }
+                    }
+                  }, _callee3, this);
+                })), 't0', 2);
 
-      We face several problems:
-      * Execute op as is won't work because ops depend on each other
-       -> find a way so that they do not anymore
-      * When changing left, must not go more to the left than the origin
-      * When changing right, you have to consider that other ops may have op
-        as their origin, this means that you must not set one of these ops
-        as the new right (interdependencies of ops)
-      * can't just go to the right until you find the first known operation,
-        With currSS
-          -> interdependency of ops is a problem
-        With startSS
-          -> leads to inconsistencies when two users join at the same time.
-             Then the position depends on the order of execution -> error!
+              case 2:
+                return _context15.abrupt('return', ds);
 
-        Solution:
-        -> re-create originial situation
-          -> set op.left = op.origin (which never changes)
-          -> set op.right
-               to the first operation that is known (according to startSS)
-               or to the first operation that has an origin that is not to the
-               right of op.
-          -> Enforces unique execution order -> happy user
+              case 3:
+              case 'end':
+                return _context15.stop();
+            }
+          }
+        }, getDeleteSet, this);
+      })
+    }, {
+      key: 'isDeleted',
+      value: regeneratorRuntime.mark(function isDeleted(id) {
+        var n;
+        return regeneratorRuntime.wrap(function isDeleted$(_context16) {
+          while (1) {
+            switch (_context16.prev = _context16.next) {
+              case 0:
+                return _context16.delegateYield(this.ds.findWithUpperBound(id), 't0', 1);
 
-        Improvements: TODO
-          * Could set left to origin, or the first known operation
-            (startSS or currSS.. ?)
-            -> Could be necessary when I turn GC again.
-            -> Is a bad(ish) idea because it requires more computation
-    */
-    * makeOperationReady (startSS, op) {
-      op = Y.Struct[op.struct].encode(op)
-      op = Y.utils.copyObject(op)
-      var o = op
-      var ids = [op.id]
-      // search for the new op.right
-      // it is either the first known op (according to startSS)
-      // or the o that has no origin to the right of op
-      // (this is why we use the ids array)
-      while (o.right != null) {
-        var right = yield* this.getOperation(o.right)
-        if (o.right[1] < (startSS[o.right[0]] || 0) || !ids.some(function (id) {
-          return Y.utils.compareIds(id, right.origin)
-        })) {
-          break
-        }
-        ids.push(o.right)
-        o = right
-      }
-      op.right = o.right
-      op.left = op.origin
-      return op
-    }
-  }
-  Y.Transaction = Transaction
-}
+              case 1:
+                n = _context16.t0;
+                return _context16.abrupt('return', n != null && n.id[0] === id[0] && id[1] < n.id[1] + n.len);
 
-},{}],6:[function(require,module,exports){
-'use strict'
+              case 3:
+              case 'end':
+                return _context16.stop();
+            }
+          }
+        }, isDeleted, this);
+      })
+    }, {
+      key: 'setOperation',
+      value: regeneratorRuntime.mark(function setOperation(op) {
+        return regeneratorRuntime.wrap(function setOperation$(_context17) {
+          while (1) {
+            switch (_context17.prev = _context17.next) {
+              case 0:
+                return _context17.delegateYield(this.os.put(op), 't0', 1);
+
+              case 1:
+                return _context17.abrupt('return', op);
+
+              case 2:
+              case 'end':
+                return _context17.stop();
+            }
+          }
+        }, setOperation, this);
+      })
+    }, {
+      key: 'addOperation',
+      value: regeneratorRuntime.mark(function addOperation(op) {
+        return regeneratorRuntime.wrap(function addOperation$(_context18) {
+          while (1) {
+            switch (_context18.prev = _context18.next) {
+              case 0:
+                return _context18.delegateYield(this.os.put(op), 't0', 1);
+
+              case 1:
+                if (!this.store.y.connector.isDisconnected() && this.store.forwardAppliedOperations) {
+                  // is connected, and this is not going to be send in addOperation
+                  this.store.y.connector.broadcast({
+                    type: 'update',
+                    ops: [op]
+                  });
+                }
+
+              case 2:
+              case 'end':
+                return _context18.stop();
+            }
+          }
+        }, addOperation, this);
+      })
+    }, {
+      key: 'getOperation',
+      value: regeneratorRuntime.mark(function getOperation(id) {
+        return regeneratorRuntime.wrap(function getOperation$(_context19) {
+          while (1) {
+            switch (_context19.prev = _context19.next) {
+              case 0:
+                return _context19.delegateYield(this.os.find(id), 't0', 1);
+
+              case 1:
+                return _context19.abrupt('return', _context19.t0);
+
+              case 2:
+              case 'end':
+                return _context19.stop();
+            }
+          }
+        }, getOperation, this);
+      })
+    }, {
+      key: 'removeOperation',
+      value: regeneratorRuntime.mark(function removeOperation(id) {
+        return regeneratorRuntime.wrap(function removeOperation$(_context20) {
+          while (1) {
+            switch (_context20.prev = _context20.next) {
+              case 0:
+                return _context20.delegateYield(this.os.delete(id), 't0', 1);
+
+              case 1:
+              case 'end':
+                return _context20.stop();
+            }
+          }
+        }, removeOperation, this);
+      })
+    }, {
+      key: 'setState',
+      value: regeneratorRuntime.mark(function setState(state) {
+        var val;
+        return regeneratorRuntime.wrap(function setState$(_context21) {
+          while (1) {
+            switch (_context21.prev = _context21.next) {
+              case 0:
+                val = {
+                  id: [state.user],
+                  clock: state.clock
+                };
+                // TODO: find a way to skip this step.. (after implementing some dbs..)
+
+                return _context21.delegateYield(this.ss.find([state.user]), 't0', 2);
+
+              case 2:
+                if (!_context21.t0) {
+                  _context21.next = 6;
+                  break;
+                }
+
+                return _context21.delegateYield(this.ss.put(val), 't1', 4);
+
+              case 4:
+                _context21.next = 7;
+                break;
+
+              case 6:
+                return _context21.delegateYield(this.ss.put(val), 't2', 7);
+
+              case 7:
+              case 'end':
+                return _context21.stop();
+            }
+          }
+        }, setState, this);
+      })
+    }, {
+      key: 'getState',
+      value: regeneratorRuntime.mark(function getState(user) {
+        var n, clock;
+        return regeneratorRuntime.wrap(function getState$(_context22) {
+          while (1) {
+            switch (_context22.prev = _context22.next) {
+              case 0:
+                return _context22.delegateYield(this.ss.find([user]), 't0', 1);
+
+              case 1:
+                _context22.t1 = n = _context22.t0;
+
+                if (!(_context22.t1 == null)) {
+                  _context22.next = 6;
+                  break;
+                }
+
+                _context22.t2 = null;
+                _context22.next = 7;
+                break;
+
+              case 6:
+                _context22.t2 = n.clock;
+
+              case 7:
+                clock = _context22.t2;
+
+                if (clock == null) {
+                  clock = 0;
+                }
+                return _context22.abrupt('return', {
+                  user: user,
+                  clock: clock
+                });
+
+              case 10:
+              case 'end':
+                return _context22.stop();
+            }
+          }
+        }, getState, this);
+      })
+    }, {
+      key: 'getStateVector',
+      value: regeneratorRuntime.mark(function getStateVector() {
+        var stateVector;
+        return regeneratorRuntime.wrap(function getStateVector$(_context24) {
+          while (1) {
+            switch (_context24.prev = _context24.next) {
+              case 0:
+                stateVector = [];
+                return _context24.delegateYield(this.ss.iterate(this, null, null, regeneratorRuntime.mark(function _callee4(n) {
+                  return regeneratorRuntime.wrap(function _callee4$(_context23) {
+                    while (1) {
+                      switch (_context23.prev = _context23.next) {
+                        case 0:
+                          stateVector.push({
+                            user: n.id[0],
+                            clock: n.clock
+                          });
+
+                        case 1:
+                        case 'end':
+                          return _context23.stop();
+                      }
+                    }
+                  }, _callee4, this);
+                })), 't0', 2);
+
+              case 2:
+                return _context24.abrupt('return', stateVector);
+
+              case 3:
+              case 'end':
+                return _context24.stop();
+            }
+          }
+        }, getStateVector, this);
+      })
+    }, {
+      key: 'getStateSet',
+      value: regeneratorRuntime.mark(function getStateSet() {
+        var ss;
+        return regeneratorRuntime.wrap(function getStateSet$(_context26) {
+          while (1) {
+            switch (_context26.prev = _context26.next) {
+              case 0:
+                ss = {};
+                return _context26.delegateYield(this.ss.iterate(this, null, null, regeneratorRuntime.mark(function _callee5(n) {
+                  return regeneratorRuntime.wrap(function _callee5$(_context25) {
+                    while (1) {
+                      switch (_context25.prev = _context25.next) {
+                        case 0:
+                          ss[n.id[0]] = n.clock;
+
+                        case 1:
+                        case 'end':
+                          return _context25.stop();
+                      }
+                    }
+                  }, _callee5, this);
+                })), 't0', 2);
+
+              case 2:
+                return _context26.abrupt('return', ss);
+
+              case 3:
+              case 'end':
+                return _context26.stop();
+            }
+          }
+        }, getStateSet, this);
+      })
+    }, {
+      key: 'getOperations',
+      value: regeneratorRuntime.mark(function getOperations(startSS) {
+        var ops, endSV, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, endState, user, startPos, res, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, op;
+
+        return regeneratorRuntime.wrap(function getOperations$(_context28) {
+          while (1) {
+            switch (_context28.prev = _context28.next) {
+              case 0:
+                // TODO: use bounds here!
+                if (startSS == null) {
+                  startSS = {};
+                }
+                ops = [];
+                return _context28.delegateYield(this.getStateVector(), 't0', 3);
+
+              case 3:
+                endSV = _context28.t0;
+                _iteratorNormalCompletion = true;
+                _didIteratorError = false;
+                _iteratorError = undefined;
+                _context28.prev = 7;
+                _iterator = endSV[Symbol.iterator]();
+
+              case 9:
+                if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
+                  _context28.next = 19;
+                  break;
+                }
+
+                endState = _step.value;
+                user = endState.user;
+
+                if (!(user === '_')) {
+                  _context28.next = 14;
+                  break;
+                }
+
+                return _context28.abrupt('continue', 16);
+
+              case 14:
+                startPos = startSS[user] || 0;
+                return _context28.delegateYield(this.os.iterate(this, [user, startPos], [user, Number.MAX_VALUE], regeneratorRuntime.mark(function _callee6(op) {
+                  return regeneratorRuntime.wrap(function _callee6$(_context27) {
+                    while (1) {
+                      switch (_context27.prev = _context27.next) {
+                        case 0:
+                          ops.push(op);
+
+                        case 1:
+                        case 'end':
+                          return _context27.stop();
+                      }
+                    }
+                  }, _callee6, this);
+                })), 't1', 16);
+
+              case 16:
+                _iteratorNormalCompletion = true;
+                _context28.next = 9;
+                break;
+
+              case 19:
+                _context28.next = 25;
+                break;
+
+              case 21:
+                _context28.prev = 21;
+                _context28.t2 = _context28['catch'](7);
+                _didIteratorError = true;
+                _iteratorError = _context28.t2;
+
+              case 25:
+                _context28.prev = 25;
+                _context28.prev = 26;
+
+                if (!_iteratorNormalCompletion && _iterator.return) {
+                  _iterator.return();
+                }
+
+              case 28:
+                _context28.prev = 28;
+
+                if (!_didIteratorError) {
+                  _context28.next = 31;
+                  break;
+                }
+
+                throw _iteratorError;
+
+              case 31:
+                return _context28.finish(28);
+
+              case 32:
+                return _context28.finish(25);
+
+              case 33:
+                res = [];
+                _iteratorNormalCompletion2 = true;
+                _didIteratorError2 = false;
+                _iteratorError2 = undefined;
+                _context28.prev = 37;
+                _iterator2 = ops[Symbol.iterator]();
+
+              case 39:
+                if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
+                  _context28.next = 48;
+                  break;
+                }
+
+                op = _step2.value;
+                _context28.t3 = res;
+                return _context28.delegateYield(this.makeOperationReady(startSS, op), 't4', 43);
+
+              case 43:
+                _context28.t5 = _context28.t4;
+
+                _context28.t3.push.call(_context28.t3, _context28.t5);
+
+              case 45:
+                _iteratorNormalCompletion2 = true;
+                _context28.next = 39;
+                break;
+
+              case 48:
+                _context28.next = 54;
+                break;
+
+              case 50:
+                _context28.prev = 50;
+                _context28.t6 = _context28['catch'](37);
+                _didIteratorError2 = true;
+                _iteratorError2 = _context28.t6;
+
+              case 54:
+                _context28.prev = 54;
+                _context28.prev = 55;
+
+                if (!_iteratorNormalCompletion2 && _iterator2.return) {
+                  _iterator2.return();
+                }
+
+              case 57:
+                _context28.prev = 57;
+
+                if (!_didIteratorError2) {
+                  _context28.next = 60;
+                  break;
+                }
+
+                throw _iteratorError2;
+
+              case 60:
+                return _context28.finish(57);
+
+              case 61:
+                return _context28.finish(54);
+
+              case 62:
+                return _context28.abrupt('return', res);
+
+              case 63:
+              case 'end':
+                return _context28.stop();
+            }
+          }
+        }, getOperations, this, [[7, 21, 25, 33], [26,, 28, 32], [37, 50, 54, 62], [55,, 57, 61]]);
+      })
+      /*
+        Here, we make op executable for the receiving user.
+         Notes:
+          startSS: denotes to the SV that the remote user sent
+          currSS:  denotes to the state vector that the user should have if he
+                   applies all already sent operations (increases is each step)
+         We face several problems:
+        * Execute op as is won't work because ops depend on each other
+         -> find a way so that they do not anymore
+        * When changing left, must not go more to the left than the origin
+        * When changing right, you have to consider that other ops may have op
+          as their origin, this means that you must not set one of these ops
+          as the new right (interdependencies of ops)
+        * can't just go to the right until you find the first known operation,
+          With currSS
+            -> interdependency of ops is a problem
+          With startSS
+            -> leads to inconsistencies when two users join at the same time.
+               Then the position depends on the order of execution -> error!
+           Solution:
+          -> re-create originial situation
+            -> set op.left = op.origin (which never changes)
+            -> set op.right
+                 to the first operation that is known (according to startSS)
+                 or to the first operation that has an origin that is not to the
+                 right of op.
+            -> Enforces unique execution order -> happy user
+           Improvements: TODO
+            * Could set left to origin, or the first known operation
+              (startSS or currSS.. ?)
+              -> Could be necessary when I turn GC again.
+              -> Is a bad(ish) idea because it requires more computation
+      */
+
+    }, {
+      key: 'makeOperationReady',
+      value: regeneratorRuntime.mark(function makeOperationReady(startSS, op) {
+        var o, ids, right;
+        return regeneratorRuntime.wrap(function makeOperationReady$(_context29) {
+          while (1) {
+            switch (_context29.prev = _context29.next) {
+              case 0:
+                op = Y.Struct[op.struct].encode(op);
+                op = Y.utils.copyObject(op);
+                o = op;
+                ids = [op.id];
+                // search for the new op.right
+                // it is either the first known op (according to startSS)
+                // or the o that has no origin to the right of op
+                // (this is why we use the ids array)
+
+              case 4:
+                if (!(o.right != null)) {
+                  _context29.next = 13;
+                  break;
+                }
+
+                return _context29.delegateYield(this.getOperation(o.right), 't0', 6);
+
+              case 6:
+                right = _context29.t0;
+
+                if (!(o.right[1] < (startSS[o.right[0]] || 0) || !ids.some(function (id) {
+                  return Y.utils.compareIds(id, right.origin);
+                }))) {
+                  _context29.next = 9;
+                  break;
+                }
+
+                return _context29.abrupt('break', 13);
+
+              case 9:
+                ids.push(o.right);
+                o = right;
+                _context29.next = 4;
+                break;
+
+              case 13:
+                op.right = o.right;
+                op.left = op.origin;
+                return _context29.abrupt('return', op);
+
+              case 16:
+              case 'end':
+                return _context29.stop();
+            }
+          }
+        }, makeOperationReady, this);
+      })
+    }]);
+
+    return Transaction;
+  })();
+
+  Y.Transaction = Transaction;
+};
+
+},{}],8:[function(require,module,exports){
+'use strict';
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 module.exports = function (Y) {
-  class YMap {
-    constructor (os, model, contents, opContents) {
-      this._model = model.id
-      this.os = os
-      this.map = Y.utils.copyObject(model.map)
-      this.contents = contents
-      this.opContents = opContents
-      this.eventHandler = new Y.utils.EventHandler(ops => {
-        var userEvents = []
+  var YMap = (function () {
+    function YMap(os, model, contents, opContents) {
+      var _this = this;
+
+      _classCallCheck(this, YMap);
+
+      this._model = model.id;
+      this.os = os;
+      this.map = Y.utils.copyObject(model.map);
+      this.contents = contents;
+      this.opContents = opContents;
+      this.eventHandler = new Y.utils.EventHandler(function (ops) {
+        var userEvents = [];
         for (var i in ops) {
-          var op = ops[i]
-          var oldValue
+          var op = ops[i];
+          var oldValue;
           // key is the name to use to access (op)content
-          var key = op.struct === 'Delete' ? op.key : op.parentSub
+          var key = op.struct === 'Delete' ? op.key : op.parentSub;
 
           // compute oldValue
-          if (this.opContents[key] != null) {
-            let prevType = this.opContents[key]
-            oldValue = () => {// eslint-disable-line
-              return new Promise((resolve) => {
-                this.os.requestTransaction(function *() {// eslint-disable-line
-                  resolve(yield* this.getType(prevType))
-                })
-              })
-            }
+          if (_this.opContents[key] != null) {
+            (function () {
+              var prevType = _this.opContents[key];
+              oldValue = function () {
+                // eslint-disable-line
+                return new Promise(function (resolve) {
+                  _this.os.requestTransaction(regeneratorRuntime.mark(function _callee() {
+                    return regeneratorRuntime.wrap(function _callee$(_context) {
+                      while (1) {
+                        switch (_context.prev = _context.next) {
+                          case 0:
+                            return _context.delegateYield(this.getType(prevType), 't0', 1);
+
+                          case 1:
+                            _context.t1 = _context.t0;
+                            resolve(_context.t1);
+
+                          case 3:
+                          case 'end':
+                            return _context.stop();
+                        }
+                      }
+                    }, _callee, this);
+                  }));
+                });
+              };
+            })();
           } else {
-            oldValue = this.contents[key]
+            oldValue = _this.contents[key];
           }
           // compute op event
           if (op.struct === 'Insert') {
             if (op.left === null) {
               if (op.opContent != null) {
-                delete this.contents[key]
+                delete _this.contents[key];
                 if (op.deleted) {
-                  delete this.opContents[key]
+                  delete _this.opContents[key];
                 } else {
-                  this.opContents[key] = op.opContent
+                  _this.opContents[key] = op.opContent;
                 }
               } else {
-                delete this.opContents[key]
+                delete _this.opContents[key];
                 if (op.deleted) {
-                  delete this.contents[key]
+                  delete _this.contents[key];
                 } else {
-                  this.contents[key] = op.content
+                  _this.contents[key] = op.content;
                 }
               }
-              this.map[key] = op.id
+              _this.map[key] = op.id;
               var insertEvent = {
                 name: key,
-                object: this
-              }
+                object: _this
+              };
               if (oldValue === undefined) {
-                insertEvent.type = 'add'
+                insertEvent.type = 'add';
               } else {
-                insertEvent.type = 'update'
-                insertEvent.oldValue = oldValue
+                insertEvent.type = 'update';
+                insertEvent.oldValue = oldValue;
               }
-              userEvents.push(insertEvent)
+              userEvents.push(insertEvent);
             }
           } else if (op.struct === 'Delete') {
-            if (Y.utils.compareIds(this.map[key], op.target)) {
-              delete this.opContents[key]
-              delete this.contents[key]
+            if (Y.utils.compareIds(_this.map[key], op.target)) {
+              delete _this.opContents[key];
+              delete _this.contents[key];
               var deleteEvent = {
                 name: key,
-                object: this,
+                object: _this,
                 oldValue: oldValue,
                 type: 'delete'
-              }
-              userEvents.push(deleteEvent)
+              };
+              userEvents.push(deleteEvent);
             }
           } else {
-            throw new Error('Unexpected Operation!')
+            throw new Error('Unexpected Operation!');
           }
         }
-        this.eventHandler.callEventListeners(userEvents)
-      })
+        _this.eventHandler.callEventListeners(userEvents);
+      });
     }
-    get (key) {
-      // return property.
-      // if property does not exist, return null
-      // if property is a type, return a promise
-      if (key == null) {
-        throw new Error('You must specify key!')
-      }
-      if (this.opContents[key] == null) {
-        return this.contents[key]
-      } else {
-        return new Promise((resolve) => {
-          var oid = this.opContents[key]
-          this.os.requestTransaction(function *() {
-            resolve(yield* this.getType(oid))
-          })
-        })
-      }
-    }
-    /*
-      If there is a primitive (not a custom type), then return it.
-      Returns all primitive values, if propertyName is specified!
-      Note: modifying the return value could result in inconsistencies!
-        -- so make sure to copy it first!
-    */
-    getPrimitive (key) {
-      if (key == null) {
-        return Y.utils.copyObject(this.contents)
-      } else {
-        return this.contents[key]
-      }
-    }
-    delete (key) {
-      var right = this.map[key]
-      if (right != null) {
-        var del = {
-          target: right,
-          struct: 'Delete'
-        }
-        var eventHandler = this.eventHandler
-        var modDel = Y.utils.copyObject(del)
-        modDel.key = key
-        eventHandler.awaitAndPrematurelyCall([modDel])
-        this.os.requestTransaction(function *() {
-          yield* this.applyCreatedOperations([del])
-          eventHandler.awaitedDeletes(1)
-        })
-      }
-    }
-    set (key, value) {
-      // set property.
-      // if property is a type, return a promise
-      // if not, apply immediately on this type an call event
 
-      var right = this.map[key] || null
-      var insert = {
-        left: null,
-        right: right,
-        origin: null,
-        parent: this._model,
-        parentSub: key,
-        struct: 'Insert'
-      }
-      return new Promise((resolve) => {
-        if (value instanceof Y.utils.CustomType) {
-          // construct a new type
-          this.os.requestTransaction(function *() {
-            var typeid = yield* value.createType.call(this)
-            var type = yield* this.getType(typeid)
-            insert.opContent = typeid
-            insert.id = this.store.getNextOpId()
-            yield* this.applyCreatedOperations([insert])
-            resolve(type)
-          })
+    _createClass(YMap, [{
+      key: 'get',
+      value: function get(key) {
+        var _this2 = this;
+
+        // return property.
+        // if property does not exist, return null
+        // if property is a type, return a promise
+        if (key == null) {
+          throw new Error('You must specify key!');
+        }
+        if (this.opContents[key] == null) {
+          return this.contents[key];
         } else {
-          insert.content = value
-          insert.id = this.os.getNextOpId()
-          var eventHandler = this.eventHandler
-          eventHandler.awaitAndPrematurelyCall([insert])
+          return new Promise(function (resolve) {
+            var oid = _this2.opContents[key];
+            _this2.os.requestTransaction(regeneratorRuntime.mark(function _callee2() {
+              return regeneratorRuntime.wrap(function _callee2$(_context2) {
+                while (1) {
+                  switch (_context2.prev = _context2.next) {
+                    case 0:
+                      return _context2.delegateYield(this.getType(oid), 't0', 1);
 
-          this.os.requestTransaction(function *() {
-            yield* this.applyCreatedOperations([insert])
-            eventHandler.awaitedInserts(1)
-          })
-          resolve(value)
-        }
-      })
-    }
-    observe (f) {
-      this.eventHandler.addEventListener(f)
-    }
-    unobserve (f) {
-      this.eventHandler.removeEventListener(f)
-    }
-    /*
-      Observe a path.
+                    case 1:
+                      _context2.t1 = _context2.t0;
+                      resolve(_context2.t1);
 
-      E.g.
-      ```
-      o.set('textarea', Y.TextBind)
-      o.observePath(['textarea'], function(t){
-        // is called whenever textarea is replaced
-        t.bind(textarea)
-      })
-
-      returns a Promise that contains a function that removes the observer from the path.
-    */
-    observePath (path, f) {
-      var self = this
-      function observeProperty (events) {
-        // call f whenever path changes
-        for (var i = 0; i < events.length; i++) {
-          var event = events[i]
-          if (event.name === propertyName) {
-            // call this also for delete events!
-            var property = self.get(propertyName)
-            if (property instanceof Promise) {
-              property.then(f)
-            } else {
-              f(property)
-            }
-          }
+                    case 3:
+                    case 'end':
+                      return _context2.stop();
+                  }
+                }
+              }, _callee2, this);
+            }));
+          });
         }
       }
+      /*
+        If there is a primitive (not a custom type), then return it.
+        Returns all primitive values, if propertyName is specified!
+        Note: modifying the return value could result in inconsistencies!
+          -- so make sure to copy it first!
+      */
 
-      if (path.length < 1) {
-        throw new Error('Path must contain at least one element!')
-      } else if (path.length === 1) {
-        var propertyName = path[0]
-        var property = self.get(propertyName)
-        if (property instanceof Promise) {
-          property.then(f)
+    }, {
+      key: 'getPrimitive',
+      value: function getPrimitive(key) {
+        if (key == null) {
+          return Y.utils.copyObject(this.contents);
         } else {
-          f(property)
+          return this.contents[key];
         }
-        this.observe(observeProperty)
-        return Promise.resolve(function () {
-          self.unobserve(f)
-        })
-      } else {
-        var deleteChildObservers
-        var resetObserverPath = function () {
-          var promise = self.get(path[0])
-          if (!promise instanceof Promise) {
-            // its either not defined or a primitive value
-            promise = self.set(path[0], Y.Map)
-          }
-          return promise.then(function (map) {
-            return map.observePath(path.slice(1), f)
-          }).then(function (_deleteChildObservers) {
-            // update deleteChildObservers
-            deleteChildObservers = _deleteChildObservers
-            return Promise.resolve() // Promise does not return anything
-          })
-        }
-        var observer = function (events) {
-          for (var e in events) {
-            var event = events[e]
-            if (event.name === path[0]) {
-              deleteChildObservers()
-              if (event.type === 'add' || event.type === 'update') {
-                resetObserverPath()
+      }
+    }, {
+      key: 'delete',
+      value: function _delete(key) {
+        var right = this.map[key];
+        if (right != null) {
+          var del = {
+            target: right,
+            struct: 'Delete'
+          };
+          var eventHandler = this.eventHandler;
+          var modDel = Y.utils.copyObject(del);
+          modDel.key = key;
+          eventHandler.awaitAndPrematurelyCall([modDel]);
+          this.os.requestTransaction(regeneratorRuntime.mark(function _callee3() {
+            return regeneratorRuntime.wrap(function _callee3$(_context3) {
+              while (1) {
+                switch (_context3.prev = _context3.next) {
+                  case 0:
+                    return _context3.delegateYield(this.applyCreatedOperations([del]), 't0', 1);
+
+                  case 1:
+                    eventHandler.awaitedDeletes(1);
+
+                  case 2:
+                  case 'end':
+                    return _context3.stop();
+                }
+              }
+            }, _callee3, this);
+          }));
+        }
+      }
+    }, {
+      key: 'set',
+      value: function set(key, value) {
+        var _this3 = this;
+
+        // set property.
+        // if property is a type, return a promise
+        // if not, apply immediately on this type an call event
+
+        var right = this.map[key] || null;
+        var insert = {
+          left: null,
+          right: right,
+          origin: null,
+          parent: this._model,
+          parentSub: key,
+          struct: 'Insert'
+        };
+        return new Promise(function (resolve) {
+          if (value instanceof Y.utils.CustomType) {
+            // construct a new type
+            _this3.os.requestTransaction(regeneratorRuntime.mark(function _callee4() {
+              var typeid, type;
+              return regeneratorRuntime.wrap(function _callee4$(_context4) {
+                while (1) {
+                  switch (_context4.prev = _context4.next) {
+                    case 0:
+                      return _context4.delegateYield(value.createType.call(this), 't0', 1);
+
+                    case 1:
+                      typeid = _context4.t0;
+                      return _context4.delegateYield(this.getType(typeid), 't1', 3);
+
+                    case 3:
+                      type = _context4.t1;
+
+                      insert.opContent = typeid;
+                      insert.id = this.store.getNextOpId();
+                      return _context4.delegateYield(this.applyCreatedOperations([insert]), 't2', 7);
+
+                    case 7:
+                      resolve(type);
+
+                    case 8:
+                    case 'end':
+                      return _context4.stop();
+                  }
+                }
+              }, _callee4, this);
+            }));
+          } else {
+            insert.content = value;
+            insert.id = _this3.os.getNextOpId();
+            var eventHandler = _this3.eventHandler;
+            eventHandler.awaitAndPrematurelyCall([insert]);
+
+            _this3.os.requestTransaction(regeneratorRuntime.mark(function _callee5() {
+              return regeneratorRuntime.wrap(function _callee5$(_context5) {
+                while (1) {
+                  switch (_context5.prev = _context5.next) {
+                    case 0:
+                      return _context5.delegateYield(this.applyCreatedOperations([insert]), 't0', 1);
+
+                    case 1:
+                      eventHandler.awaitedInserts(1);
+
+                    case 2:
+                    case 'end':
+                      return _context5.stop();
+                  }
+                }
+              }, _callee5, this);
+            }));
+            resolve(value);
+          }
+        });
+      }
+    }, {
+      key: 'observe',
+      value: function observe(f) {
+        this.eventHandler.addEventListener(f);
+      }
+    }, {
+      key: 'unobserve',
+      value: function unobserve(f) {
+        this.eventHandler.removeEventListener(f);
+      }
+      /*
+        Observe a path.
+         E.g.
+        ```
+        o.set('textarea', Y.TextBind)
+        o.observePath(['textarea'], function(t){
+          // is called whenever textarea is replaced
+          t.bind(textarea)
+        })
+         returns a Promise that contains a function that removes the observer from the path.
+      */
+
+    }, {
+      key: 'observePath',
+      value: function observePath(path, f) {
+        var self = this;
+        function observeProperty(events) {
+          // call f whenever path changes
+          for (var i = 0; i < events.length; i++) {
+            var event = events[i];
+            if (event.name === propertyName) {
+              // call this also for delete events!
+              var property = self.get(propertyName);
+              if (property instanceof Promise) {
+                property.then(f);
+              } else {
+                f(property);
               }
-              // TODO: what about the delete events?
             }
           }
         }
-        self.observe(observer)
-        return resetObserverPath().then(
+
+        if (path.length < 1) {
+          throw new Error('Path must contain at least one element!');
+        } else if (path.length === 1) {
+          var propertyName = path[0];
+          var property = self.get(propertyName);
+          if (property instanceof Promise) {
+            property.then(f);
+          } else {
+            f(property);
+          }
+          this.observe(observeProperty);
+          return Promise.resolve(function () {
+            self.unobserve(f);
+          });
+        } else {
+          var deleteChildObservers;
+          var resetObserverPath = function resetObserverPath() {
+            var promise = self.get(path[0]);
+            if (!promise instanceof Promise) {
+              // its either not defined or a primitive value
+              promise = self.set(path[0], Y.Map);
+            }
+            return promise.then(function (map) {
+              return map.observePath(path.slice(1), f);
+            }).then(function (_deleteChildObservers) {
+              // update deleteChildObservers
+              deleteChildObservers = _deleteChildObservers;
+              return Promise.resolve(); // Promise does not return anything
+            });
+          };
+          var observer = function observer(events) {
+            for (var e in events) {
+              var event = events[e];
+              if (event.name === path[0]) {
+                deleteChildObservers();
+                if (event.type === 'add' || event.type === 'update') {
+                  resetObserverPath();
+                }
+                // TODO: what about the delete events?
+              }
+            }
+          };
+          self.observe(observer);
+          return resetObserverPath().then(
           // this promise contains a function that deletes all the child observers
           // and how to unobserve the observe from this object
           Promise.resolve(function () {
-            deleteChildObservers()
-            self.unobserve(observer)
-          })
-        )
-      }
-    }
-    * _changed (transaction, op) {
-      if (op.struct === 'Delete') {
-        op.key = (yield* transaction.getOperation(op.target)).parentSub
-      }
-      this.eventHandler.receivedOp(op)
-    }
-  }
-  Y.Map = new Y.utils.CustomType({
-    class: YMap,
-    createType: function * YMapCreator () {
-      var modelid = this.store.getNextOpId()
-      var model = {
-        map: {},
-        struct: 'Map',
-        type: 'Map',
-        id: modelid
-      }
-      yield* this.applyCreatedOperations([model])
-      return modelid
-    },
-    initType: function * YMapInitializer (os, model) {
-      var contents = {}
-      var opContents = {}
-      var map = model.map
-      for (var name in map) {
-        var op = yield* this.getOperation(map[name])
-        if (op.opContent != null) {
-          opContents[name] = op.opContent
-        } else {
-          contents[name] = op.content
+            deleteChildObservers();
+            self.unobserve(observer);
+          }));
         }
       }
-      return new YMap(os, model, contents, opContents)
-    }
-  })
-}
+    }, {
+      key: '_changed',
+      value: regeneratorRuntime.mark(function _changed(transaction, op) {
+        return regeneratorRuntime.wrap(function _changed$(_context6) {
+          while (1) {
+            switch (_context6.prev = _context6.next) {
+              case 0:
+                if (!(op.struct === 'Delete')) {
+                  _context6.next = 3;
+                  break;
+                }
 
-},{}],7:[function(require,module,exports){
-'use strict'
+                return _context6.delegateYield(transaction.getOperation(op.target), 't0', 2);
+
+              case 2:
+                op.key = _context6.t0.parentSub;
+
+              case 3:
+                this.eventHandler.receivedOp(op);
+
+              case 4:
+              case 'end':
+                return _context6.stop();
+            }
+          }
+        }, _changed, this);
+      })
+    }]);
+
+    return YMap;
+  })();
+
+  Y.Map = new Y.utils.CustomType({
+    class: YMap,
+    createType: regeneratorRuntime.mark(function YMapCreator() {
+      var modelid, model;
+      return regeneratorRuntime.wrap(function YMapCreator$(_context7) {
+        while (1) {
+          switch (_context7.prev = _context7.next) {
+            case 0:
+              modelid = this.store.getNextOpId();
+              model = {
+                map: {},
+                struct: 'Map',
+                type: 'Map',
+                id: modelid
+              };
+              return _context7.delegateYield(this.applyCreatedOperations([model]), 't0', 3);
+
+            case 3:
+              return _context7.abrupt('return', modelid);
+
+            case 4:
+            case 'end':
+              return _context7.stop();
+          }
+        }
+      }, YMapCreator, this);
+    }),
+    initType: regeneratorRuntime.mark(function YMapInitializer(os, model) {
+      var contents, opContents, map, name, op;
+      return regeneratorRuntime.wrap(function YMapInitializer$(_context8) {
+        while (1) {
+          switch (_context8.prev = _context8.next) {
+            case 0:
+              contents = {};
+              opContents = {};
+              map = model.map;
+              _context8.t0 = regeneratorRuntime.keys(map);
+
+            case 4:
+              if ((_context8.t1 = _context8.t0()).done) {
+                _context8.next = 11;
+                break;
+              }
+
+              name = _context8.t1.value;
+              return _context8.delegateYield(this.getOperation(map[name]), 't2', 7);
+
+            case 7:
+              op = _context8.t2;
+
+              if (op.opContent != null) {
+                opContents[name] = op.opContent;
+              } else {
+                contents[name] = op.content;
+              }
+              _context8.next = 4;
+              break;
+
+            case 11:
+              return _context8.abrupt('return', new YMap(os, model, contents, opContents));
+
+            case 12:
+            case 'end':
+              return _context8.stop();
+          }
+        }
+      }, YMapInitializer, this);
+    })
+  });
+};
+
+},{}],9:[function(require,module,exports){
+'use strict';
 
 /*
   EventHandler is an helper class for constructing custom types.
@@ -2126,302 +4988,372 @@ module.exports = function (Y) {
   database request to finish). EventHandler will help you to make your type
   synchronously.
 */
-module.exports = function (Y) {
-  Y.utils = {}
 
-  class EventHandler {
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+module.exports = function (Y) {
+  Y.utils = {};
+
+  var EventHandler = (function () {
     /*
       onevent: is called when the structure changes.
-
-      Note: "awaiting opertations" is used to denote operations that were
+       Note: "awaiting opertations" is used to denote operations that were
       prematurely called. Events for received operations can not be executed until
       all prematurely called operations were executed ("waiting operations")
     */
-    constructor (onevent) {
-      this.waiting = []
-      this.awaiting = 0
-      this.onevent = onevent
-      this.eventListeners = []
+
+    function EventHandler(onevent) {
+      _classCallCheck(this, EventHandler);
+
+      this.waiting = [];
+      this.awaiting = 0;
+      this.onevent = onevent;
+      this.eventListeners = [];
     }
     /*
       Call this when a new operation arrives. It will be executed right away if
       there are no waiting operations, that you prematurely executed
     */
-    receivedOp (op) {
-      if (this.awaiting <= 0) {
-        this.onevent([op])
-      } else {
-        this.waiting.push(Y.utils.copyObject(op))
-      }
-    }
-    /*
-      You created some operations, and you want the `onevent` function to be
-      called right away. Received operations will not be executed untill all
-      prematurely called operations are executed
-    */
-    awaitAndPrematurelyCall (ops) {
-      this.awaiting++
-      this.onevent(ops)
-    }
-    /*
-      Basic event listener boilerplate...
-      TODO: maybe put this in a different type..
-    */
-    addEventListener (f) {
-      this.eventListeners.push(f)
-    }
-    removeEventListener (f) {
-      this.eventListeners = this.eventListeners.filter(function (g) {
-        return f !== g
-      })
-    }
-    removeAllEventListeners () {
-      this.eventListeners = []
-    }
-    callEventListeners (event) {
-      for (var i in this.eventListeners) {
-        try {
-          this.eventListeners[i](event)
-        } catch (e) {
-          console.log('User events must not throw Errors!') // eslint-disable-line
+
+    _createClass(EventHandler, [{
+      key: 'receivedOp',
+      value: function receivedOp(op) {
+        if (this.awaiting <= 0) {
+          this.onevent([op]);
+        } else {
+          this.waiting.push(Y.utils.copyObject(op));
         }
       }
-    }
-    /*
-      Call this when you successfully awaited the execution of n Insert operations
-    */
-    awaitedInserts (n) {
-      var ops = this.waiting.splice(this.waiting.length - n)
-      for (var oid = 0; oid < ops.length; oid++) {
-        var op = ops[oid]
-        for (var i = this.waiting.length - 1; i >= 0; i--) {
-          let w = this.waiting[i]
-          if (Y.utils.compareIds(op.left, w.id)) {
-            // include the effect of op in w
-            w.right = op.id
-            // exclude the effect of w in op
-            op.left = w.left
-          } else if (Y.utils.compareIds(op.right, w.id)) {
-            // similar..
-            w.left = op.id
-            op.right = w.right
+      /*
+        You created some operations, and you want the `onevent` function to be
+        called right away. Received operations will not be executed untill all
+        prematurely called operations are executed
+      */
+
+    }, {
+      key: 'awaitAndPrematurelyCall',
+      value: function awaitAndPrematurelyCall(ops) {
+        this.awaiting++;
+        this.onevent(ops);
+      }
+      /*
+        Basic event listener boilerplate...
+        TODO: maybe put this in a different type..
+      */
+
+    }, {
+      key: 'addEventListener',
+      value: function addEventListener(f) {
+        this.eventListeners.push(f);
+      }
+    }, {
+      key: 'removeEventListener',
+      value: function removeEventListener(f) {
+        this.eventListeners = this.eventListeners.filter(function (g) {
+          return f !== g;
+        });
+      }
+    }, {
+      key: 'removeAllEventListeners',
+      value: function removeAllEventListeners() {
+        this.eventListeners = [];
+      }
+    }, {
+      key: 'callEventListeners',
+      value: function callEventListeners(event) {
+        for (var i in this.eventListeners) {
+          try {
+            this.eventListeners[i](event);
+          } catch (e) {
+            console.log('User events must not throw Errors!'); // eslint-disable-line
           }
         }
       }
-      this._tryCallEvents()
-    }
-    /*
-      Call this when you successfully awaited the execution of n Delete operations
-    */
-    awaitedDeletes (n, newLeft) {
-      var ops = this.waiting.splice(this.waiting.length - n)
-      for (var j in ops) {
-        var del = ops[j]
-        if (newLeft != null) {
-          for (var i in this.waiting) {
-            let w = this.waiting[i]
-            // We will just care about w.left
-            if (Y.utils.compareIds(del.target, w.left)) {
-              del.left = newLeft
+      /*
+        Call this when you successfully awaited the execution of n Insert operations
+      */
+
+    }, {
+      key: 'awaitedInserts',
+      value: function awaitedInserts(n) {
+        var ops = this.waiting.splice(this.waiting.length - n);
+        for (var oid = 0; oid < ops.length; oid++) {
+          var op = ops[oid];
+          for (var i = this.waiting.length - 1; i >= 0; i--) {
+            var w = this.waiting[i];
+            if (Y.utils.compareIds(op.left, w.id)) {
+              // include the effect of op in w
+              w.right = op.id;
+              // exclude the effect of w in op
+              op.left = w.left;
+            } else if (Y.utils.compareIds(op.right, w.id)) {
+              // similar..
+              w.left = op.id;
+              op.right = w.right;
             }
           }
         }
+        this._tryCallEvents();
       }
-      this._tryCallEvents()
-    }
-    /* (private)
-      Try to execute the events for the waiting operations
-    */
-    _tryCallEvents () {
-      this.awaiting--
-      if (this.awaiting <= 0 && this.waiting.length > 0) {
-        var events = this.waiting
-        this.waiting = []
-        this.onevent(events)
+      /*
+        Call this when you successfully awaited the execution of n Delete operations
+      */
+
+    }, {
+      key: 'awaitedDeletes',
+      value: function awaitedDeletes(n, newLeft) {
+        var ops = this.waiting.splice(this.waiting.length - n);
+        for (var j in ops) {
+          var del = ops[j];
+          if (newLeft != null) {
+            for (var i in this.waiting) {
+              var w = this.waiting[i];
+              // We will just care about w.left
+              if (Y.utils.compareIds(del.target, w.left)) {
+                del.left = newLeft;
+              }
+            }
+          }
+        }
+        this._tryCallEvents();
       }
-    }
-  }
-  Y.utils.EventHandler = EventHandler
+      /* (private)
+        Try to execute the events for the waiting operations
+      */
+
+    }, {
+      key: '_tryCallEvents',
+      value: function _tryCallEvents() {
+        this.awaiting--;
+        if (this.awaiting <= 0 && this.waiting.length > 0) {
+          var events = this.waiting;
+          this.waiting = [];
+          this.onevent(events);
+        }
+      }
+    }]);
+
+    return EventHandler;
+  })();
+
+  Y.utils.EventHandler = EventHandler;
 
   /*
     A wrapper for the definition of a custom type.
     Every custom type must have three properties:
-
-    * createType
+     * createType
       - Defines the model of a newly created custom type and returns the type
     * initType
       - Given a model, creates a custom type
     * class
       - the constructor of the custom type (e.g. in order to inherit from a type)
   */
-  class CustomType { // eslint-disable-line
-    constructor (def) {
-      if (def.createType == null ||
-        def.initType == null ||
-        def.class == null
-      ) {
-        throw new Error('Custom type was not initialized correctly!')
-      }
-      this.createType = def.createType
-      this.initType = def.initType
-      this.class = def.class
+
+  var CustomType = // eslint-disable-line
+  function CustomType(def) {
+    _classCallCheck(this, CustomType);
+
+    if (def.createType == null || def.initType == null || def.class == null) {
+      throw new Error('Custom type was not initialized correctly!');
     }
-  }
-  Y.utils.CustomType = CustomType
+    this.createType = def.createType;
+    this.initType = def.initType;
+    this.class = def.class;
+  };
+
+  Y.utils.CustomType = CustomType;
 
   /*
     Make a flat copy of an object
     (just copy properties)
   */
-  function copyObject (o) {
-    var c = {}
+  function copyObject(o) {
+    var c = {};
     for (var key in o) {
-      c[key] = o[key]
+      c[key] = o[key];
     }
-    return c
+    return c;
   }
-  Y.utils.copyObject = copyObject
+  Y.utils.copyObject = copyObject;
 
   /*
     Defines a smaller relation on Id's
   */
-  function smaller (a, b) {
-    return a[0] < b[0] || (a[0] === b[0] && a[1] < b[1])
+  function smaller(a, b) {
+    return a[0] < b[0] || a[0] === b[0] && a[1] < b[1];
   }
-  Y.utils.smaller = smaller
+  Y.utils.smaller = smaller;
 
-  function compareIds (id1, id2) {
+  function compareIds(id1, id2) {
     if (id1 == null || id2 == null) {
       if (id1 == null && id2 == null) {
-        return true
+        return true;
       }
-      return false
+      return false;
     }
     if (id1[0] === id2[0] && id1[1] === id2[1]) {
-      return true
+      return true;
     } else {
-      return false
+      return false;
     }
   }
-  Y.utils.compareIds = compareIds
-}
+  Y.utils.compareIds = compareIds;
+};
 
-},{}],8:[function(require,module,exports){
+},{}],10:[function(require,module,exports){
 /* @flow */
-'use strict'
+'use strict';
 
-require('./Connector.js')(Y)
-require('./Database.js')(Y)
-require('./Transaction.js')(Y)
-require('./Struct.js')(Y)
-require('./Utils.js')(Y)
-require('./Connectors/Test.js')(Y)
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
 
-var requiringModules = {}
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-module.exports = Y
+require('./Connector.js')(Y);
+require('./Database.js')(Y);
+require('./Transaction.js')(Y);
+require('./Struct.js')(Y);
+require('./Utils.js')(Y);
+require('./Connectors/Test.js')(Y);
+
+var requiringModules = {};
+
+module.exports = Y;
 
 Y.extend = function (name, value) {
-  Y[name] = value
+  Y[name] = value;
   if (requiringModules[name] != null) {
-    requiringModules[name].resolve()
-    delete requiringModules[name]
+    requiringModules[name].resolve();
+    delete requiringModules[name];
   }
-}
+};
 
 Y.requestModules = function (modules) {
-  var promises = []
+  var promises = [];
   for (var i = 0; i < modules.length; i++) {
-    var modulename = 'y-' + modules[i].toLowerCase()
+    var modulename = 'y-' + modules[i].toLowerCase();
     if (Y[modules[i]] == null) {
       if (requiringModules[modules[i]] == null) {
         try {
-          require(modulename)(Y)
+          require(modulename)(Y);
         } catch (e) {
           // module does not exist
           if (typeof window !== 'undefined') {
-            var imported = document.createElement('script')
-            imported.src = Y.sourceDir + '/' + modulename + '/' + modulename + '.js'
-            document.head.appendChild(imported)
-            ;(function () {
-              var modname = modules[i]
-              var promise = new Promise(function (resolve) {
-                requiringModules[modname] = {
-                  resolve: resolve,
-                  promise: promise
-                }
-              })
-              promises.push(promise)
-            })()
+            var imported;
+
+            (function () {
+              imported = document.createElement('script');
+
+              imported.src = Y.sourceDir + '/' + modulename + '/' + modulename + '.js';
+              document.head.appendChild(imported);
+
+              var requireModule = {};
+              requiringModules[modules[i]] = requireModule;
+              requireModule.promise = new Promise(function (resolve) {
+                requireModule.resolve = resolve;
+              });
+              promises.push(requireModule.promise);
+            })();
           } else {
-            throw e
+            throw e;
           }
         }
       } else {
-        promises.push(requiringModules[modules[i]].promise)
+        promises.push(requiringModules[modules[i]].promise);
       }
     }
   }
-  return Promise.all(promises)
-}
+  return Promise.all(promises);
+};
 
-require('./Types/Map.js')(Y)
+require('./Types/Map.js')(Y);
 
-function Y (opts) {
-  opts.types = opts.types != null ? opts.types : []
-  var modules = [opts.db.name, opts.connector.name].concat(opts.types)
-  Y.sourceDir = opts.sourceDir
+function Y(opts) {
+  opts.types = opts.types != null ? opts.types : [];
+  var modules = [opts.db.name, opts.connector.name].concat(opts.types);
+  Y.sourceDir = opts.sourceDir;
   return Y.requestModules(modules).then(function () {
     return new Promise(function (resolve) {
       var yconfig = new YConfig(opts, function () {
         yconfig.db.whenUserIdSet(function () {
-          resolve(yconfig)
-        })
-      })
-    })
-  })
+          resolve(yconfig);
+        });
+      });
+    });
+  });
 }
 
-class YConfig {
-  constructor (opts, callback) {
-    this.db = new Y[opts.db.name](this, opts.db)
-    this.connector = new Y[opts.connector.name](this, opts.connector)
-    this.db.requestTransaction(function * requestTransaction () {
-      // create initial Map type
-      var model = {
-        id: ['_', 0],
-        struct: 'Map',
-        type: 'Map',
-        map: {}
-      }
-      yield* this.store.tryExecute.call(this, model)
-      var root = yield* this.getType(model.id)
-      this.store.y.root = root
-      callback()
-    })
+var YConfig = (function () {
+  function YConfig(opts, callback) {
+    _classCallCheck(this, YConfig);
+
+    this.db = new Y[opts.db.name](this, opts.db);
+    this.connector = new Y[opts.connector.name](this, opts.connector);
+    this.db.requestTransaction(regeneratorRuntime.mark(function requestTransaction() {
+      var model, root;
+      return regeneratorRuntime.wrap(function requestTransaction$(_context) {
+        while (1) {
+          switch (_context.prev = _context.next) {
+            case 0:
+              // create initial Map type
+              model = {
+                id: ['_', 0],
+                struct: 'Map',
+                type: 'Map',
+                map: {}
+              };
+              return _context.delegateYield(this.store.tryExecute.call(this, model), 't0', 2);
+
+            case 2:
+              return _context.delegateYield(this.getType(model.id), 't1', 3);
+
+            case 3:
+              root = _context.t1;
+
+              this.store.y.root = root;
+              callback();
+
+            case 6:
+            case 'end':
+              return _context.stop();
+          }
+        }
+      }, requestTransaction, this);
+    }));
   }
-  isConnected () {
-    return this.connector.isSynced
-  }
-  disconnect () {
-    return this.connector.disconnect()
-  }
-  reconnect () {
-    return this.connector.reconnect()
-  }
-  destroy () {
-    this.disconnect()
-    this.db.destroy()
-    this.connector = null
-    this.db = null
-  }
-}
+
+  _createClass(YConfig, [{
+    key: 'isConnected',
+    value: function isConnected() {
+      return this.connector.isSynced;
+    }
+  }, {
+    key: 'disconnect',
+    value: function disconnect() {
+      return this.connector.disconnect();
+    }
+  }, {
+    key: 'reconnect',
+    value: function reconnect() {
+      return this.connector.reconnect();
+    }
+  }, {
+    key: 'destroy',
+    value: function destroy() {
+      this.disconnect();
+      this.db.destroy();
+      this.connector = null;
+      this.db = null;
+    }
+  }]);
+
+  return YConfig;
+})();
 
 if (typeof window !== 'undefined') {
-  window.Y = Y
+  window.Y = Y;
 }
 
-},{"./Connector.js":1,"./Connectors/Test.js":2,"./Database.js":3,"./Struct.js":4,"./Transaction.js":5,"./Types/Map.js":6,"./Utils.js":7}]},{},[8])
+},{"./Connector.js":3,"./Connectors/Test.js":4,"./Database.js":5,"./Struct.js":6,"./Transaction.js":7,"./Types/Map.js":8,"./Utils.js":9}]},{},[2,10])
 
-
-//# sourceMappingURL=y.js.map
\ No newline at end of file