text: /**
   * yjs - A framework for real-time p2p shared editing on any data
   * @version v12.3.1
   * @link http://y-js.org
   * @license MIT
   */
  (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.yText = f()}})(function(){var define,module,exports;return (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){
  /**
   * This library modifies the diff-patch-match library by Neil Fraser
   * by removing the patch and match functionality and certain advanced
   * options in the diff function. The original license is as follows:
   *
   * ===
   *
   * Diff Match and Patch
   *
   * Copyright 2006 Google Inc.
   * http://code.google.com/p/google-diff-match-patch/
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  /**
   * The data structure representing a diff is an array of tuples:
   * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
   * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
   */
  var DIFF_DELETE = -1;
  var DIFF_INSERT = 1;
  var DIFF_EQUAL = 0;
  
  
  /**
   * Find the differences between two texts.  Simplifies the problem by stripping
   * any common prefix or suffix off the texts before diffing.
   * @param {string} text1 Old string to be diffed.
   * @param {string} text2 New string to be diffed.
   * @param {Int} cursor_pos Expected edit position in text1 (optional)
   * @return {Array} Array of diff tuples.
   */
  function diff_main(text1, text2, cursor_pos) {
    // Check for equality (speedup).
    if (text1 == text2) {
      if (text1) {
        return [[DIFF_EQUAL, text1]];
      }
      return [];
    }
  
    // Check cursor_pos within bounds
    if (cursor_pos < 0 || text1.length < cursor_pos) {
      cursor_pos = null;
    }
  
    // Trim off common prefix (speedup).
    var commonlength = diff_commonPrefix(text1, text2);
    var commonprefix = text1.substring(0, commonlength);
    text1 = text1.substring(commonlength);
    text2 = text2.substring(commonlength);
  
    // Trim off common suffix (speedup).
    commonlength = diff_commonSuffix(text1, text2);
    var commonsuffix = text1.substring(text1.length - commonlength);
    text1 = text1.substring(0, text1.length - commonlength);
    text2 = text2.substring(0, text2.length - commonlength);
  
    // Compute the diff on the middle block.
    var diffs = diff_compute_(text1, text2);
  
    // Restore the prefix and suffix.
    if (commonprefix) {
      diffs.unshift([DIFF_EQUAL, commonprefix]);
    }
    if (commonsuffix) {
      diffs.push([DIFF_EQUAL, commonsuffix]);
    }
    diff_cleanupMerge(diffs);
    if (cursor_pos != null) {
      diffs = fix_cursor(diffs, cursor_pos);
    }
    return diffs;
  };
  
  
  /**
   * Find the differences between two texts.  Assumes that the texts do not
   * have any common prefix or suffix.
   * @param {string} text1 Old string to be diffed.
   * @param {string} text2 New string to be diffed.
   * @return {Array} Array of diff tuples.
   */
  function diff_compute_(text1, text2) {
    var diffs;
  
    if (!text1) {
      // Just add some text (speedup).
      return [[DIFF_INSERT, text2]];
    }
  
    if (!text2) {
      // Just delete some text (speedup).
      return [[DIFF_DELETE, text1]];
    }
  
    var longtext = text1.length > text2.length ? text1 : text2;
    var shorttext = text1.length > text2.length ? text2 : text1;
    var i = longtext.indexOf(shorttext);
    if (i != -1) {
      // Shorter text is inside the longer text (speedup).
      diffs = [[DIFF_INSERT, longtext.substring(0, i)],
               [DIFF_EQUAL, shorttext],
               [DIFF_INSERT, longtext.substring(i + shorttext.length)]];
      // Swap insertions for deletions if diff is reversed.
      if (text1.length > text2.length) {
        diffs[0][0] = diffs[2][0] = DIFF_DELETE;
      }
      return diffs;
    }
  
    if (shorttext.length == 1) {
      // Single character string.
      // After the previous speedup, the character can't be an equality.
      return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
    }
  
    // Check to see if the problem can be split in two.
    var hm = diff_halfMatch_(text1, text2);
    if (hm) {
      // A half-match was found, sort out the return data.
      var text1_a = hm[0];
      var text1_b = hm[1];
      var text2_a = hm[2];
      var text2_b = hm[3];
      var mid_common = hm[4];
      // Send both pairs off for separate processing.
      var diffs_a = diff_main(text1_a, text2_a);
      var diffs_b = diff_main(text1_b, text2_b);
      // Merge the results.
      return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b);
    }
  
    return diff_bisect_(text1, text2);
  };
  
  
  /**
   * Find the 'middle snake' of a diff, split the problem in two
   * and return the recursively constructed diff.
   * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
   * @param {string} text1 Old string to be diffed.
   * @param {string} text2 New string to be diffed.
   * @return {Array} Array of diff tuples.
   * @private
   */
  function diff_bisect_(text1, text2) {
    // Cache the text lengths to prevent multiple calls.
    var text1_length = text1.length;
    var text2_length = text2.length;
    var max_d = Math.ceil((text1_length + text2_length) / 2);
    var v_offset = max_d;
    var v_length = 2 * max_d;
    var v1 = new Array(v_length);
    var v2 = new Array(v_length);
    // Setting all elements to -1 is faster in Chrome & Firefox than mixing
    // integers and undefined.
    for (var x = 0; x < v_length; x++) {
      v1[x] = -1;
      v2[x] = -1;
    }
    v1[v_offset + 1] = 0;
    v2[v_offset + 1] = 0;
    var delta = text1_length - text2_length;
    // If the total number of characters is odd, then the front path will collide
    // with the reverse path.
    var front = (delta % 2 != 0);
    // Offsets for start and end of k loop.
    // Prevents mapping of space beyond the grid.
    var k1start = 0;
    var k1end = 0;
    var k2start = 0;
    var k2end = 0;
    for (var d = 0; d < max_d; d++) {
      // Walk the front path one step.
      for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
        var k1_offset = v_offset + k1;
        var x1;
        if (k1 == -d || (k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1])) {
          x1 = v1[k1_offset + 1];
        } else {
          x1 = v1[k1_offset - 1] + 1;
        }
        var y1 = x1 - k1;
        while (x1 < text1_length && y1 < text2_length &&
               text1.charAt(x1) == text2.charAt(y1)) {
          x1++;
          y1++;
        }
        v1[k1_offset] = x1;
        if (x1 > text1_length) {
          // Ran off the right of the graph.
          k1end += 2;
        } else if (y1 > text2_length) {
          // Ran off the bottom of the graph.
          k1start += 2;
        } else if (front) {
          var k2_offset = v_offset + delta - k1;
          if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) {
            // Mirror x2 onto top-left coordinate system.
            var x2 = text1_length - v2[k2_offset];
            if (x1 >= x2) {
              // Overlap detected.
              return diff_bisectSplit_(text1, text2, x1, y1);
            }
          }
        }
      }
  
      // Walk the reverse path one step.
      for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
        var k2_offset = v_offset + k2;
        var x2;
        if (k2 == -d || (k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1])) {
          x2 = v2[k2_offset + 1];
        } else {
          x2 = v2[k2_offset - 1] + 1;
        }
        var y2 = x2 - k2;
        while (x2 < text1_length && y2 < text2_length &&
               text1.charAt(text1_length - x2 - 1) ==
               text2.charAt(text2_length - y2 - 1)) {
          x2++;
          y2++;
        }
        v2[k2_offset] = x2;
        if (x2 > text1_length) {
          // Ran off the left of the graph.
          k2end += 2;
        } else if (y2 > text2_length) {
          // Ran off the top of the graph.
          k2start += 2;
        } else if (!front) {
          var k1_offset = v_offset + delta - k2;
          if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) {
            var x1 = v1[k1_offset];
            var y1 = v_offset + x1 - k1_offset;
            // Mirror x2 onto top-left coordinate system.
            x2 = text1_length - x2;
            if (x1 >= x2) {
              // Overlap detected.
              return diff_bisectSplit_(text1, text2, x1, y1);
            }
          }
        }
      }
    }
    // Diff took too long and hit the deadline or
    // number of diffs equals number of characters, no commonality at all.
    return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
  };
  
  
  /**
   * Given the location of the 'middle snake', split the diff in two parts
   * and recurse.
   * @param {string} text1 Old string to be diffed.
   * @param {string} text2 New string to be diffed.
   * @param {number} x Index of split point in text1.
   * @param {number} y Index of split point in text2.
   * @return {Array} Array of diff tuples.
   */
  function diff_bisectSplit_(text1, text2, x, y) {
    var text1a = text1.substring(0, x);
    var text2a = text2.substring(0, y);
    var text1b = text1.substring(x);
    var text2b = text2.substring(y);
  
    // Compute both diffs serially.
    var diffs = diff_main(text1a, text2a);
    var diffsb = diff_main(text1b, text2b);
  
    return diffs.concat(diffsb);
  };
  
  
  /**
   * Determine the common prefix of two strings.
   * @param {string} text1 First string.
   * @param {string} text2 Second string.
   * @return {number} The number of characters common to the start of each
   *     string.
   */
  function diff_commonPrefix(text1, text2) {
    // Quick check for common null cases.
    if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) {
      return 0;
    }
    // Binary search.
    // Performance analysis: http://neil.fraser.name/news/2007/10/09/
    var pointermin = 0;
    var pointermax = Math.min(text1.length, text2.length);
    var pointermid = pointermax;
    var pointerstart = 0;
    while (pointermin < pointermid) {
      if (text1.substring(pointerstart, pointermid) ==
          text2.substring(pointerstart, pointermid)) {
        pointermin = pointermid;
        pointerstart = pointermin;
      } else {
        pointermax = pointermid;
      }
      pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
    }
    return pointermid;
  };
  
  
  /**
   * Determine the common suffix of two strings.
   * @param {string} text1 First string.
   * @param {string} text2 Second string.
   * @return {number} The number of characters common to the end of each string.
   */
  function diff_commonSuffix(text1, text2) {
    // Quick check for common null cases.
    if (!text1 || !text2 ||
        text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) {
      return 0;
    }
    // Binary search.
    // Performance analysis: http://neil.fraser.name/news/2007/10/09/
    var pointermin = 0;
    var pointermax = Math.min(text1.length, text2.length);
    var pointermid = pointermax;
    var pointerend = 0;
    while (pointermin < pointermid) {
      if (text1.substring(text1.length - pointermid, text1.length - pointerend) ==
          text2.substring(text2.length - pointermid, text2.length - pointerend)) {
        pointermin = pointermid;
        pointerend = pointermin;
      } else {
        pointermax = pointermid;
      }
      pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
    }
    return pointermid;
  };
  
  
  /**
   * Do the two texts share a substring which is at least half the length of the
   * longer text?
   * This speedup can produce non-minimal diffs.
   * @param {string} text1 First string.
   * @param {string} text2 Second string.
   * @return {Array.<string>} Five element Array, containing the prefix of
   *     text1, the suffix of text1, the prefix of text2, the suffix of
   *     text2 and the common middle.  Or null if there was no match.
   */
  function diff_halfMatch_(text1, text2) {
    var longtext = text1.length > text2.length ? text1 : text2;
    var shorttext = text1.length > text2.length ? text2 : text1;
    if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
      return null;  // Pointless.
    }
  
    /**
     * Does a substring of shorttext exist within longtext such that the substring
     * is at least half the length of longtext?
     * Closure, but does not reference any external variables.
     * @param {string} longtext Longer string.
     * @param {string} shorttext Shorter string.
     * @param {number} i Start index of quarter length substring within longtext.
     * @return {Array.<string>} Five element Array, containing the prefix of
     *     longtext, the suffix of longtext, the prefix of shorttext, the suffix
     *     of shorttext and the common middle.  Or null if there was no match.
     * @private
     */
    function diff_halfMatchI_(longtext, shorttext, i) {
      // Start with a 1/4 length substring at position i as a seed.
      var seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
      var j = -1;
      var best_common = '';
      var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
      while ((j = shorttext.indexOf(seed, j + 1)) != -1) {
        var prefixLength = diff_commonPrefix(longtext.substring(i),
                                             shorttext.substring(j));
        var suffixLength = diff_commonSuffix(longtext.substring(0, i),
                                             shorttext.substring(0, j));
        if (best_common.length < suffixLength + prefixLength) {
          best_common = shorttext.substring(j - suffixLength, j) +
              shorttext.substring(j, j + prefixLength);
          best_longtext_a = longtext.substring(0, i - suffixLength);
          best_longtext_b = longtext.substring(i + prefixLength);
          best_shorttext_a = shorttext.substring(0, j - suffixLength);
          best_shorttext_b = shorttext.substring(j + prefixLength);
        }
      }
      if (best_common.length * 2 >= longtext.length) {
        return [best_longtext_a, best_longtext_b,
                best_shorttext_a, best_shorttext_b, best_common];
      } else {
        return null;
      }
    }
  
    // First check if the second quarter is the seed for a half-match.
    var hm1 = diff_halfMatchI_(longtext, shorttext,
                               Math.ceil(longtext.length / 4));
    // Check again based on the third quarter.
    var hm2 = diff_halfMatchI_(longtext, shorttext,
                               Math.ceil(longtext.length / 2));
    var hm;
    if (!hm1 && !hm2) {
      return null;
    } else if (!hm2) {
      hm = hm1;
    } else if (!hm1) {
      hm = hm2;
    } else {
      // Both matched.  Select the longest.
      hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
    }
  
    // A half-match was found, sort out the return data.
    var text1_a, text1_b, text2_a, text2_b;
    if (text1.length > text2.length) {
      text1_a = hm[0];
      text1_b = hm[1];
      text2_a = hm[2];
      text2_b = hm[3];
    } else {
      text2_a = hm[0];
      text2_b = hm[1];
      text1_a = hm[2];
      text1_b = hm[3];
    }
    var mid_common = hm[4];
    return [text1_a, text1_b, text2_a, text2_b, mid_common];
  };
  
  
  /**
   * Reorder and merge like edit sections.  Merge equalities.
   * Any edit section can move as long as it doesn't cross an equality.
   * @param {Array} diffs Array of diff tuples.
   */
  function diff_cleanupMerge(diffs) {
    diffs.push([DIFF_EQUAL, '']);  // Add a dummy entry at the end.
    var pointer = 0;
    var count_delete = 0;
    var count_insert = 0;
    var text_delete = '';
    var text_insert = '';
    var commonlength;
    while (pointer < diffs.length) {
      switch (diffs[pointer][0]) {
        case DIFF_INSERT:
          count_insert++;
          text_insert += diffs[pointer][1];
          pointer++;
          break;
        case DIFF_DELETE:
          count_delete++;
          text_delete += diffs[pointer][1];
          pointer++;
          break;
        case DIFF_EQUAL:
          // Upon reaching an equality, check for prior redundancies.
          if (count_delete + count_insert > 1) {
            if (count_delete !== 0 && count_insert !== 0) {
              // Factor out any common prefixies.
              commonlength = diff_commonPrefix(text_insert, text_delete);
              if (commonlength !== 0) {
                if ((pointer - count_delete - count_insert) > 0 &&
                    diffs[pointer - count_delete - count_insert - 1][0] ==
                    DIFF_EQUAL) {
                  diffs[pointer - count_delete - count_insert - 1][1] +=
                      text_insert.substring(0, commonlength);
                } else {
                  diffs.splice(0, 0, [DIFF_EQUAL,
                                      text_insert.substring(0, commonlength)]);
                  pointer++;
                }
                text_insert = text_insert.substring(commonlength);
                text_delete = text_delete.substring(commonlength);
              }
              // Factor out any common suffixies.
              commonlength = diff_commonSuffix(text_insert, text_delete);
              if (commonlength !== 0) {
                diffs[pointer][1] = text_insert.substring(text_insert.length -
                    commonlength) + diffs[pointer][1];
                text_insert = text_insert.substring(0, text_insert.length -
                    commonlength);
                text_delete = text_delete.substring(0, text_delete.length -
                    commonlength);
              }
            }
            // Delete the offending records and add the merged ones.
            if (count_delete === 0) {
              diffs.splice(pointer - count_insert,
                  count_delete + count_insert, [DIFF_INSERT, text_insert]);
            } else if (count_insert === 0) {
              diffs.splice(pointer - count_delete,
                  count_delete + count_insert, [DIFF_DELETE, text_delete]);
            } else {
              diffs.splice(pointer - count_delete - count_insert,
                  count_delete + count_insert, [DIFF_DELETE, text_delete],
                  [DIFF_INSERT, text_insert]);
            }
            pointer = pointer - count_delete - count_insert +
                      (count_delete ? 1 : 0) + (count_insert ? 1 : 0) + 1;
          } else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL) {
            // Merge this equality with the previous one.
            diffs[pointer - 1][1] += diffs[pointer][1];
            diffs.splice(pointer, 1);
          } else {
            pointer++;
          }
          count_insert = 0;
          count_delete = 0;
          text_delete = '';
          text_insert = '';
          break;
      }
    }
    if (diffs[diffs.length - 1][1] === '') {
      diffs.pop();  // Remove the dummy entry at the end.
    }
  
    // Second pass: look for single edits surrounded on both sides by equalities
    // which can be shifted sideways to eliminate an equality.
    // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
    var changes = false;
    pointer = 1;
    // Intentionally ignore the first and last element (don't need checking).
    while (pointer < diffs.length - 1) {
      if (diffs[pointer - 1][0] == DIFF_EQUAL &&
          diffs[pointer + 1][0] == DIFF_EQUAL) {
        // This is a single edit surrounded by equalities.
        if (diffs[pointer][1].substring(diffs[pointer][1].length -
            diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) {
          // Shift the edit over the previous equality.
          diffs[pointer][1] = diffs[pointer - 1][1] +
              diffs[pointer][1].substring(0, diffs[pointer][1].length -
                                          diffs[pointer - 1][1].length);
          diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
          diffs.splice(pointer - 1, 1);
          changes = true;
        } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) ==
            diffs[pointer + 1][1]) {
          // Shift the edit over the next equality.
          diffs[pointer - 1][1] += diffs[pointer + 1][1];
          diffs[pointer][1] =
              diffs[pointer][1].substring(diffs[pointer + 1][1].length) +
              diffs[pointer + 1][1];
          diffs.splice(pointer + 1, 1);
          changes = true;
        }
      }
      pointer++;
    }
    // If shifts were made, the diff needs reordering and another shift sweep.
    if (changes) {
      diff_cleanupMerge(diffs);
    }
  };
  
  
  var diff = diff_main;
  diff.INSERT = DIFF_INSERT;
  diff.DELETE = DIFF_DELETE;
  diff.EQUAL = DIFF_EQUAL;
  
  module.exports = diff;
  
  /*
   * Modify a diff such that the cursor position points to the start of a change:
   * E.g.
   *   cursor_normalize_diff([[DIFF_EQUAL, 'abc']], 1)
   *     => [1, [[DIFF_EQUAL, 'a'], [DIFF_EQUAL, 'bc']]]
   *   cursor_normalize_diff([[DIFF_INSERT, 'new'], [DIFF_DELETE, 'xyz']], 2)
   *     => [2, [[DIFF_INSERT, 'new'], [DIFF_DELETE, 'xy'], [DIFF_DELETE, 'z']]]
   *
   * @param {Array} diffs Array of diff tuples
   * @param {Int} cursor_pos Suggested edit position. Must not be out of bounds!
   * @return {Array} A tuple [cursor location in the modified diff, modified diff]
   */
  function cursor_normalize_diff (diffs, cursor_pos) {
    if (cursor_pos === 0) {
      return [DIFF_EQUAL, diffs];
    }
    for (var current_pos = 0, i = 0; i < diffs.length; i++) {
      var d = diffs[i];
      if (d[0] === DIFF_DELETE || d[0] === DIFF_EQUAL) {
        var next_pos = current_pos + d[1].length;
        if (cursor_pos === next_pos) {
          return [i + 1, diffs];
        } else if (cursor_pos < next_pos) {
          // copy to prevent side effects
          diffs = diffs.slice();
          // split d into two diff changes
          var split_pos = cursor_pos - current_pos;
          var d_left = [d[0], d[1].slice(0, split_pos)];
          var d_right = [d[0], d[1].slice(split_pos)];
          diffs.splice(i, 1, d_left, d_right);
          return [i + 1, diffs];
        } else {
          current_pos = next_pos;
        }
      }
    }
    throw new Error('cursor_pos is out of bounds!')
  }
  
  /*
   * Modify a diff such that the edit position is "shifted" to the proposed edit location (cursor_position).
   *
   * Case 1)
   *   Check if a naive shift is possible:
   *     [0, X], [ 1, Y] -> [ 1, Y], [0, X]    (if X + Y === Y + X)
   *     [0, X], [-1, Y] -> [-1, Y], [0, X]    (if X + Y === Y + X) - holds same result
   * Case 2)
   *   Check if the following shifts are possible:
   *     [0, 'pre'], [ 1, 'prefix'] -> [ 1, 'pre'], [0, 'pre'], [ 1, 'fix']
   *     [0, 'pre'], [-1, 'prefix'] -> [-1, 'pre'], [0, 'pre'], [-1, 'fix']
   *         ^            ^
   *         d          d_next
   *
   * @param {Array} diffs Array of diff tuples
   * @param {Int} cursor_pos Suggested edit position. Must not be out of bounds!
   * @return {Array} Array of diff tuples
   */
  function fix_cursor (diffs, cursor_pos) {
    var norm = cursor_normalize_diff(diffs, cursor_pos);
    var ndiffs = norm[1];
    var cursor_pointer = norm[0];
    var d = ndiffs[cursor_pointer];
    var d_next = ndiffs[cursor_pointer + 1];
  
    if (d == null) {
      // Text was deleted from end of original string,
      // cursor is now out of bounds in new string
      return diffs;
    } else if (d[0] !== DIFF_EQUAL) {
      // A modification happened at the cursor location.
      // This is the expected outcome, so we can return the original diff.
      return diffs;
    } else {
      if (d_next != null && d[1] + d_next[1] === d_next[1] + d[1]) {
        // Case 1)
        // It is possible to perform a naive shift
        ndiffs.splice(cursor_pointer, 2, d_next, d)
        return merge_tuples(ndiffs, cursor_pointer, 2)
      } else if (d_next != null && d_next[1].indexOf(d[1]) === 0) {
        // Case 2)
        // d[1] is a prefix of d_next[1]
        // We can assume that d_next[0] !== 0, since d[0] === 0
        // Shift edit locations..
        ndiffs.splice(cursor_pointer, 2, [d_next[0], d[1]], [0, d[1]]);
        var suffix = d_next[1].slice(d[1].length);
        if (suffix.length > 0) {
          ndiffs.splice(cursor_pointer + 2, 0, [d_next[0], suffix]);
        }
        return merge_tuples(ndiffs, cursor_pointer, 3)
      } else {
        // Not possible to perform any modification
        return diffs;
      }
    }
  
  }
  
  /*
   * Try to merge tuples with their neigbors in a given range.
   * E.g. [0, 'a'], [0, 'b'] -> [0, 'ab']
   *
   * @param {Array} diffs Array of diff tuples.
   * @param {Int} start Position of the first element to merge (diffs[start] is also merged with diffs[start - 1]).
   * @param {Int} length Number of consecutive elements to check.
   * @return {Array} Array of merged diff tuples.
   */
  function merge_tuples (diffs, start, length) {
    // Check from (start-1) to (start+length).
    for (var i = start + length - 1; i >= 0 && i >= start - 1; i--) {
      if (i + 1 < diffs.length) {
        var left_d = diffs[i];
        var right_d = diffs[i+1];
        if (left_d[0] === right_d[1]) {
          diffs.splice(i, 2, [left_d[0], left_d[1] + right_d[1]]);
        }
      }
    }
    return diffs;
  }
  
  },{}],2:[function(require,module,exports){
  /* global Y, Element */
  'use strict'
  
  var diff = require('fast-diff')
  var monacoIdentifierTemplate = { major: 0, minor: 0 }
  
  function extend (Y) {
    Y.requestModules(['Array']).then(function () {
      class YText extends Y.Array.typeDefinition['class'] {
        constructor (os, _model, _content) {
          super(os, _model, _content)
          this.textfields = []
          this.aceInstances = []
          this.codeMirrorInstances = []
          this.monacoInstances = []
        }
        toString () {
          return this._content.map(function (c) {
            return c.val
          }).join('')
        }
        insert (pos, content) {
          var arr = content.split('')
          for (var i = 0; i < arr.length; i++) {
            if (/[\uD800-\uDFFF]/.test(arr[i])) {
              // is surrogate pair
              arr[i] = arr[i] + arr[i + 1]
              arr[i + 1] = ''
              i++
            }
          }
          super.insert(pos, arr)
        }
        delete (pos, length) {
          if (length == null) { length = 1 }
          if (typeof length !== 'number') {
            throw new Error('length must be a number!')
          }
          if (typeof pos !== 'number') {
            throw new Error('pos must be a number!')
          }
          if (pos + length > this._content.length || pos < 0 || length < 0) {
            throw new Error('The deletion range exceeds the range of the array!')
          }
          if (length === 0) {
            return
          }
          // This is for the case that part of a surrogate pair is deleted
          // we store surrogate pairs like this: [.., '🐇', '', ..] (string, code)
          if (this._content.length > pos + length && this._content[pos + length].val === '' && this._content[pos + length - 1].val.length === 2) {
            // case one. first part of the surrogate pair is deleted
            let token = this._content[pos + length - 1].val[0]
            super.delete(pos, length + 1)
            super.insert(pos, [token])
          } else if (pos > 0 && this._content[pos].val === '' && this._content[pos - 1].val.length === 2) {
            // case two. second part of the surrogate pair is deleted
            let token = this._content[pos - 1].val[1]
            super.delete(pos - 1, length + 1)
            super.insert(pos - 1, [token])
          } else {
            super.delete(pos, length)
          }
        }
        unbindAll () {
          this.unbindTextareaAll()
          this.unbindAceAll()
          this.unbindCodeMirrorAll()
          this.unbindMonacoAll()
        }
        // Monaco implementation
        unbindMonaco (monacoInstance) {
          var i = this.monacoInstances.findIndex(function (binding) {
            return binding.editor === monacoInstance
          })
          if (i >= 0) {
            var binding = this.monacoInstances[i]
            this.unobserve(binding.yCallback)
            binding.disposeBinding()
            this.monacoInstances.splice(i, 1)
          }
        }
        unbindMonacoAll () {
          for (let i = this.monacoInstances.length - 1; i >= 0; i--) {
            this.unbindMonaco(this.monacoInstances[i].editor)
          }
        }
        bindMonaco (monacoInstance, options) {
          var self = this
          options = options || {}
  
          // this function makes sure that either the
          // monaco event is executed, or the yjs observer is executed
          var token = true
          function mutualExcluse (f) {
            if (token) {
              token = false
              try {
                f()
              } catch (e) {
                token = true
                throw new Error(e)
              }
              token = true
            }
          }
          monacoInstance.setValue(this.toString())
  
          function monacoCallback (event) {
            mutualExcluse(function () {
              // compute start.. (col+row -> index position)
              // We shouldn't compute the offset on the old model..
              //    var start = monacoInstance.model.getOffsetAt({column: event.range.startColumn, lineNumber: event.range.startLineNumber})
              // So we compute the offset using the _content of this type
              for (var i = 0, line = 1; line < event.range.startLineNumber; i++) {
                if (self._content[i].val === '\n') {
                  line++
                }
              }
              var start = i + event.range.startColumn - 1
  
              // apply the delete operation first
              if (event.rangeLength > 0) {
                self.delete(start, event.rangeLength)
              }
              // apply insert operation
              self.insert(start, event.text)
            })
          }
          var disposeBinding = monacoInstance.onDidChangeModelContent(monacoCallback).dispose
  
          function yCallback (event) {
            mutualExcluse(function () {
              let start = monacoInstance.model.getPositionAt(event.index)
              var end, text
              if (event.type === 'insert') {
                end = start
                text = event.values.join('')
              } else if (event.type === 'delete') {
                end = monacoInstance.model.modifyPosition(start, event.length)
                text = ''
              }
              var range = {
                startLineNumber: start.lineNumber,
                startColumn: start.column,
                endLineNumber: end.lineNumber,
                endColumn: end.column
              }
              var id = {
                major: monacoIdentifierTemplate.major,
                minor: monacoIdentifierTemplate.minor++
              }
              monacoInstance.executeEdits('Yjs', [{
                id: id,
                range: range,
                text: text,
                forceMoveMarkers: true
              }])
            })
          }
          this.observe(yCallback)
          this.monacoInstances.push({
            editor: monacoInstance,
            yCallback: yCallback,
            monacoCallback: monacoCallback,
            disposeBinding: disposeBinding
          })
        }
        // CodeMirror implementation..
        unbindCodeMirror (codeMirrorInstance) {
          var i = this.codeMirrorInstances.findIndex(function (binding) {
            return binding.editor === codeMirrorInstance
          })
          if (i >= 0) {
            var binding = this.codeMirrorInstances[i]
            this.unobserve(binding.yCallback)
            binding.editor.off('changes', binding.codeMirrorCallback)
            this.codeMirrorInstances.splice(i, 1)
          }
        }
        unbindCodeMirrorAll () {
          for (let i = this.codeMirrorInstances.length - 1; i >= 0; i--) {
            this.unbindCodeMirror(this.codeMirrorInstances[i].editor)
          }
        }
        bindCodeMirror (codeMirrorInstance, options) {
          var self = this
          options = options || {}
  
          // this function makes sure that either the
          // codemirror event is executed, or the yjs observer is executed
          var token = true
          function mutualExcluse (f) {
            if (token) {
              token = false
              try {
                f()
              } catch (e) {
                token = true
                throw new Error(e)
              }
              token = true
            }
          }
          codeMirrorInstance.setValue(this.toString())
  
          function codeMirrorCallback (cm, deltas) {
            mutualExcluse(function () {
              for (var i = 0; i < deltas.length; i++) {
                var delta = deltas[i]
                var start = codeMirrorInstance.indexFromPos(delta.from)
                // apply the delete operation first
                if (delta.removed.length > 0) {
                  var delLength = 0
                  for (var j = 0; j < delta.removed.length; j++) {
                    delLength += delta.removed[j].length
                  }
                  // "enter" is also a character in our case
                  delLength += delta.removed.length - 1
                  self.delete(start, delLength)
                }
                // apply insert operation
                self.insert(start, delta.text.join('\n'))
              }
            })
          }
          codeMirrorInstance.on('changes', codeMirrorCallback)
  
          function yCallback (event) {
            mutualExcluse(function () {
              let from = codeMirrorInstance.posFromIndex(event.index)
              if (event.type === 'insert') {
                let to = from
                codeMirrorInstance.replaceRange(event.values.join(''), from, to)
              } else if (event.type === 'delete') {
                let to = codeMirrorInstance.posFromIndex(event.index + event.length)
                codeMirrorInstance.replaceRange('', from, to)
              }
            })
          }
          this.observe(yCallback)
          this.codeMirrorInstances.push({
            editor: codeMirrorInstance,
            yCallback: yCallback,
            codeMirrorCallback: codeMirrorCallback
          })
        }
        unbindAce (aceInstance) {
          var i = this.aceInstances.findIndex(function (binding) {
            return binding.editor === aceInstance
          })
          if (i >= 0) {
            var binding = this.aceInstances[i]
            this.unobserve(binding.yCallback)
            binding.editor.off('change', binding.aceCallback)
            this.aceInstances.splice(i, 1)
          }
        }
        unbindAceAll () {
          for (let i = this.aceInstances.length - 1; i >= 0; i--) {
            this.unbindAce(this.aceInstances[i].editor)
          }
        }
        bindAce (aceInstance, options) {
          var self = this
          options = options || {}
  
          // this function makes sure that either the
          // ace event is executed, or the yjs observer is executed
          var token = true
          function mutualExcluse (f) {
            if (token) {
              token = false
              try {
                f()
              } catch (e) {
                token = true
                throw new Error(e)
              }
              token = true
            }
          }
          aceInstance.setValue(this.toString())
  
          function aceCallback (delta) {
            mutualExcluse(function () {
              var start
              var length
  
              var aceDocument = aceInstance.getSession().getDocument()
              if (delta.action === 'insert') {
                start = aceDocument.positionToIndex(delta.start, 0)
                self.insert(start, delta.lines.join('\n'))
              } else if (delta.action === 'remove') {
                start = aceDocument.positionToIndex(delta.start, 0)
                length = delta.lines.join('\n').length
                self.delete(start, length)
              }
            })
          }
          aceInstance.on('change', aceCallback)
  
          aceInstance.selection.clearSelection()
  
          // We don't that ace is a global variable
          // see #2
          var aceClass
          if (typeof ace !== 'undefined' && options.aceClass == null) {
            aceClass = ace // eslint-disable-line
          } else {
            aceClass = options.aceClass
          }
          var aceRequire = options.aceRequire || aceClass.require
          var Range = aceRequire('ace/range').Range
  
          function yCallback (event) {
            var aceDocument = aceInstance.getSession().getDocument()
            mutualExcluse(function () {
              if (event.type === 'insert') {
                let start = aceDocument.indexToPosition(event.index, 0)
                aceDocument.insert(start, event.values.join(''))
              } else if (event.type === 'delete') {
                let start = aceDocument.indexToPosition(event.index, 0)
                let end = aceDocument.indexToPosition(event.index + event.length, 0)
                var range = new Range(start.row, start.column, end.row, end.column)
                aceDocument.remove(range)
              }
            })
          }
          this.observe(yCallback)
          this.aceInstances.push({
            editor: aceInstance,
            yCallback: yCallback,
            aceCallback: aceCallback
          })
        }
        bind () {
          var e = arguments[0]
          if (e instanceof Element) {
            this.bindTextarea.apply(this, arguments)
          } else if (e != null && e.session != null && e.getSession != null && e.setValue != null) {
            this.bindAce.apply(this, arguments)
          } else if (e != null && e.posFromIndex != null && e.replaceRange != null) {
            this.bindCodeMirror.apply(this, arguments)
          } else if (e != null && e.onDidChangeModelContent != null) {
            this.bindMonaco.apply(this, arguments)
          } else {
            console.error('Cannot bind, unsupported editor!')
          }
        }
        unbindTextarea (textarea) {
          var i = this.textfields.findIndex(function (binding) {
            return binding.editor === textarea
          })
          if (i >= 0) {
            var binding = this.textfields[i]
            this.unobserve(binding.yCallback)
            var e = binding.editor
            e.removeEventListener('input', binding.eventListener)
            this.textfields.splice(i, 1)
          }
        }
        unbindTextareaAll () {
          for (let i = this.textfields.length - 1; i >= 0; i--) {
            this.unbindTextarea(this.textfields[i].editor)
          }
        }
        bindTextarea (textfield, domRoot) {
          domRoot = domRoot || window; // eslint-disable-line
          if (domRoot.getSelection == null) {
            domRoot = window; // eslint-disable-line
          }
  
          // don't duplicate!
          for (var t = 0; t < this.textfields.length; t++) {
            if (this.textfields[t].editor === textfield) {
              return
            }
          }
          // this function makes sure that either the
          // textfieldt event is executed, or the yjs observer is executed
          var token = true
          function mutualExcluse (f) {
            if (token) {
              token = false
              try {
                f()
              } catch (e) {
                token = true
                throw new Error(e)
              }
              token = true
            }
          }
  
          var self = this
          textfield.value = this.toString()
  
          var createRange, writeRange, writeContent, getContent
          if (textfield.selectionStart != null && textfield.setSelectionRange != null) {
            createRange = function (fix) {
              var left = textfield.selectionStart
              var right = textfield.selectionEnd
              if (fix != null) {
                left = fix(left)
                right = fix(right)
              }
              return {
                left: left,
                right: right
              }
            }
            writeRange = function (range) {
              writeContent(self.toString())
              textfield.setSelectionRange(range.left, range.right)
            }
            writeContent = function (content) {
              textfield.value = content
            }
            getContent = function () {
              return textfield.value
            }
          } else {
            createRange = function (fix) {
              var range = {}
              var s = domRoot.getSelection()
              var clength = textfield.textContent.length
              range.left = Math.min(s.anchorOffset, clength)
              range.right = Math.min(s.focusOffset, clength)
              if (fix != null) {
                range.left = fix(range.left)
                range.right = fix(range.right)
              }
              var editedElement = s.focusNode
              if (editedElement === textfield || editedElement === textfield.childNodes[0]) {
                range.isReal = true
              } else {
                range.isReal = false
              }
              return range
            }
  
            writeRange = function (range) {
              writeContent(self.toString())
              var textnode = textfield.childNodes[0]
              if (range.isReal && textnode != null) {
                if (range.left < 0) {
                  range.left = 0
                }
                range.right = Math.max(range.left, range.right)
                if (range.right > textnode.length) {
                  range.right = textnode.length
                }
                range.left = Math.min(range.left, range.right)
                var r = document.createRange(); // eslint-disable-line
                r.setStart(textnode, range.left)
                r.setEnd(textnode, range.right)
                var s = domRoot.getSelection(); // eslint-disable-line
                s.removeAllRanges()
                s.addRange(r)
              }
            }
            writeContent = function (content) {
              textfield.innerText = content
              /*
              var contentArray = content.replace(new RegExp('\n', 'g'), ' ').split(' '); // eslint-disable-line
              textfield.innerText = ''
              for (var i = 0; i < contentArray.length; i++) {
                var c = contentArray[i]
                textfield.innerText += c
                if (i !== contentArray.length - 1) {
                  textfield.innerHTML += '&nbsp;'
                }
              }
              */
            }
            getContent = function () {
              return textfield.innerText
            }
          }
          writeContent(this.toString())
  
          function yCallback (event) {
            mutualExcluse(() => {
              var oPos, fix
              if (event.type === 'insert') {
                oPos = event.index
                fix = function (cursor) { // eslint-disable-line
                  if (cursor <= oPos) {
                    return cursor
                  } else {
                    cursor += 1
                    return cursor
                  }
                }
                var r = createRange(fix)
                writeRange(r)
              } else if (event.type === 'delete') {
                oPos = event.index
                fix = function (cursor) { // eslint-disable-line
                  if (cursor < oPos) {
                    return cursor
                  } else {
                    cursor -= 1
                    return cursor
                  }
                }
                r = createRange(fix)
                writeRange(r)
              }
            })
          }
          this.observe(yCallback)
  
          var textfieldObserver = function textfieldObserver () {
            mutualExcluse(function () {
              var r = createRange(function (x) { return x })
              var oldContent = self.toString()
              var content = getContent()
              var diffs = diff(oldContent, content, r.left)
              var pos = 0
              for (var i = 0; i < diffs.length; i++) {
                var d = diffs[i]
                if (d[0] === 0) { // EQUAL
                  pos += d[1].length
                } else if (d[0] === -1) { // DELETE
                  self.delete(pos, d[1].length)
                } else { // INSERT
                  self.insert(pos, d[1])
                  pos += d[1].length
                }
              }
            })
          }
          textfield.addEventListener('input', textfieldObserver)
          this.textfields.push({
            editor: textfield,
            yCallback: yCallback,
            eventListener: textfieldObserver
          })
        }
        _destroy () {
          this.unbindAll()
          this.textfields = null
          this.aceInstances = null
          super._destroy()
        }
      }
      Y.extend('Text', new Y.utils.CustomTypeDefinition({
        name: 'Text',
        class: YText,
        struct: 'List',
        initType: function * YTextInitializer (os, model) {
          var _content = []
          yield * Y.Struct.List.map.call(this, model, function (op) {
            if (op.hasOwnProperty('opContent')) {
              throw new Error('Text must not contain types!')
            } else {
              op.content.forEach(function (c, i) {
                _content.push({
                  id: [op.id[0], op.id[1] + i],
                  val: op.content[i]
                })
              })
            }
          })
          return new YText(os, model.id, _content)
        },
        createType: function YTextCreator (os, model) {
          return new YText(os, model.id, [])
        }
      }))
    })
  }
  
  module.exports = extend
  if (typeof Y !== 'undefined') {
    extend(Y)
  }
  
  },{"fast-diff":1}]},{},[2])(2)
  });
  
  