Вход Регистрация
Файл: sngine-v2.8/Script/includes/assets/js/plugins/codemirror/lib/codemirror.js
Строк: 17278
<?php
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE

// This is CodeMirror (https://codemirror.net), a code editor
// implemented in JavaScript on top of the browser's DOM.
//
// You can find some technical background for some of the code below
// at http://marijnhaverbeke.nl/blog/#cm-internals .

(function (global, factory) {
  
typeof exports === 'object' && typeof module !== 'undefined' module.exports factory() :
  
typeof define === 'function' && define.amd define(factory) :
  (global = global || 
self, global.CodeMirror factory());
}(
this, (function () { 'use strict';

  
// Kludges for bugs and behavior differences that can't be feature
  // detected are enabled based on userAgent etc sniffing.
  
var userAgent navigator.userAgent;
  var 
platform navigator.platform;

  var 
gecko = /gecko/d/i.test(userAgent);
  var 
ie_upto10 = /MSIE d/.test(userAgent);
  var 
ie_11up = /Trident/(?:[7-9]|d{2,})..*rv:(d+)/.exec(userAgent);
  var 
edge = /Edge/(d+)/.exec(userAgent);
  var 
ie ie_upto10 || ie_11up || edge;
  var 
ie_version ie && (ie_upto10 document.documentMode || : +(edge || ie_11up)[1]);
  var 
webkit = !edge && /WebKit//.test(userAgent);
  
var qtwebkit webkit && /Qt/d+.d+/.test(userAgent);
  var 
chrome = !edge && /Chrome//.test(userAgent);
  
var presto = /Opera//.test(userAgent);
  
var safari = /Apple Computer/.test(navigator.vendor);
  var 
mac_geMountainLion = /Mac OS X 1dD([8-9]|dd)D/.test(userAgent);
  var 
phantom = /PhantomJS/.test(userAgent);

  var 
ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile/w+/.test(userAgent);
  var 
android = /Android/.test(userAgent);
  
// This is woefully incomplete. Suggestions for alternative methods welcome.
  
var mobile ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
  var 
mac ios || /Mac/.test(platform);
  var 
chromeOS = /bCrOSb/.test(userAgent);
  var 
windows = /win/i.test(platform);

  var 
presto_version presto && userAgent.match(/Version/(d*.d*)/);
  if (
presto_version) { presto_version Number(presto_version[1]); }
  if (
presto_version && presto_version >= 15) { presto falsewebkit true; }
  
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
  
var flipCtrlCmd mac && (qtwebkit || presto && (presto_version == null || presto_version 12.11));
  var 
captureRightClick gecko || (ie && ie_version >= 9);

  function 
classTest(cls) { return new RegExp("(^|\s)" cls "(?:$|\s)\s*") }

  var 
rmClass = function(nodecls) {
    var 
current node.className;
    var 
match classTest(cls).exec(current);
    if (
match) {
      var 
after current.slice(match.index match[0].length);
      
node.className current.slice(0match.index) + (after match[1] + after "");
    }
  };

  function 
removeChildren(e) {
    for (var 
count e.childNodes.lengthcount 0; --count)
      { 
e.removeChild(e.firstChild); }
    return 
e
  
}

  function 
removeChildrenAndAdd(parente) {
    return 
removeChildren(parent).appendChild(e)
  }

  function 
elt(tagcontentclassNamestyle) {
    var 
document.createElement(tag);
    if (
className) { e.className className; }
    if (
style) { e.style.cssText style; }
    if (
typeof content == "string") { e.appendChild(document.createTextNode(content)); }
    else if (
content) { for (var 0content.length; ++i) { e.appendChild(content[i]); } }
    return 
e
  
}
  
// wrapper for elt, which removes the elt from the accessibility tree
  
function eltP(tagcontentclassNamestyle) {
    var 
elt(tagcontentclassNamestyle);
    
e.setAttribute("role""presentation");
    return 
e
  
}

  var 
range;
  if (
document.createRange) { range = function(nodestartendendNode) {
    var 
document.createRange();
    
r.setEnd(endNode || nodeend);
    
r.setStart(nodestart);
    return 
r
  
}; }
  else { 
range = function(nodestartend) {
    var 
document.body.createTextRange();
    try { 
r.moveToElementText(node.parentNode); }
    catch(
e) { return }
    
r.collapse(true);
    
r.moveEnd("character"end);
    
r.moveStart("character"start);
    return 
r
  
}; }

  function 
contains(parentchild) {
    if (
child.nodeType == 3// Android browser always returns false when child is a textnode
      
child child.parentNode; }
    if (
parent.contains)
      { return 
parent.contains(child) }
    do {
      if (
child.nodeType == 11) { child child.host; }
      if (
child == parent) { return true }
    } while (
child child.parentNode)
  }

  function 
activeElt() {
    
// IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
    // IE < 10 will throw when accessed while the page is loading or in an iframe.
    // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
    
var activeElement;
    try {
      
activeElement document.activeElement;
    } catch(
e) {
      
activeElement document.body || null;
    }
    while (
activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
      { 
activeElement activeElement.shadowRoot.activeElement; }
    return 
activeElement
  
}

  function 
addClass(nodecls) {
    var 
current node.className;
    if (!
classTest(cls).test(current)) { node.className += (current " " "") + cls; }
  }
  function 
joinClasses(ab) {
    var as = 
a.split(" ");
    for (var 
0< as.lengthi++)
      { if (as[
i] && !classTest(as[i]).test(b)) { += " " + as[i]; } }
    return 
b
  
}

  var 
selectInput = function(node) { node.select(); };
  if (
ios// Mobile Safari apparently has a bug where select() is broken.
    
selectInput = function(node) { node.selectionStart 0node.selectionEnd node.value.length; }; }
  else if (
ie// Suppress mysterious IE10 errors
    
selectInput = function(node) { try { node.select(); } catch(_e) {} }; }

  function 
bind(f) {
    var 
args = Array.prototype.slice.call(arguments1);
    return function(){return 
f.apply(nullargs)}
  }

  function 
copyObj(objtargetoverwrite) {
    if (!
target) { target = {}; }
    for (var 
prop in obj)
      { if (
obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
        { 
target[prop] = obj[prop]; } }
    return 
target
  
}

  
// Counts the column offset in a string, taking tabs into account.
  // Used mostly to find indentation.
  
function countColumn(stringendtabSizestartIndexstartValue) {
    if (
end == null) {
      
end string.search(/[^su00a0]/);
      if (
end == -1) { end string.length; }
    }
    for (var 
startIndex || 0startValue || 0;;) {
      var 
nextTab string.indexOf("t"i);
      if (
nextTab || nextTab >= end)
        { return 
+ (end i) }
      
+= nextTab i;
      
+= tabSize - (tabSize);
      
nextTab 1;
    }
  }

  var 
Delayed = function() {
    
this.id null;
    
this.null;
    
this.time 0;
    
this.handler bind(this.onTimeoutthis);
  };
  
Delayed.prototype.onTimeout = function (self) {
    
self.id 0;
    if (
self.time <= +new Date) {
      
self.f();
    } else {
      
setTimeout(self.handlerself.time - +new Date);
    }
  };
  
Delayed.prototype.set = function (msf) {
    
this.f;
    var 
time = +new Date ms;
    if (!
this.id || time this.time) {
      
clearTimeout(this.id);
      
this.id setTimeout(this.handlerms);
      
this.time time;
    }
  };

  function 
indexOf(array, elt) {
    for (var 
0< array.length; ++i)
      { if (array[
i] == elt) { return } }
    return -
1
  
}

  
// Number of pixels added to scroller and sizer to hide scrollbar
  
var scrollerGap 50;

  
// Returned or thrown by various protocols to signal 'I'm not
  // handling this'.
  
var Pass = {toString: function(){return "CodeMirror.Pass"}};

  
// Reused option objects for setSelection & friends
  
var sel_dontScroll = {scrollfalse}, sel_mouse = {origin"*mouse"}, sel_move = {origin"+move"};

  
// The inverse of countColumn -- find the offset that corresponds to
  // a particular column.
  
function findColumn(stringgoaltabSize) {
    for (var 
pos 0col 0;;) {
      var 
nextTab string.indexOf("t"pos);
      if (
nextTab == -1) { nextTab string.length; }
      var 
skipped nextTab pos;
      if (
nextTab == string.length || col skipped >= goal)
        { return 
pos Math.min(skippedgoal col) }
      
col += nextTab pos;
      
col += tabSize - (col tabSize);
      
pos nextTab 1;
      if (
col >= goal) { return pos }
    }
  }

  var 
spaceStrs = [""];
  function 
spaceStr(n) {
    while (
spaceStrs.length <= n)
      { 
spaceStrs.push(lst(spaceStrs) + " "); }
    return 
spaceStrs[n]
  }

  function 
lst(arr) { return arr[arr.length-1] }

  function 
map(array, f) {
    var 
out = [];
    for (var 
0< array.lengthi++) { out[i] = f(array[i], i); }
    return 
out
  
}

  function 
insertSorted(array, valuescore) {
    var 
pos 0priority score(value);
    while (
pos < array.length && score(array[pos]) <= priority) { pos++; }
    array.
splice(pos0value);
  }

  function 
nothing() {}

  function 
createObj(baseprops) {
    var 
inst;
    if (
Object.create) {
      
inst Object.create(base);
    } else {
      
nothing.prototype base;
      
inst = new nothing();
    }
    if (
props) { copyObj(propsinst); }
    return 
inst
  
}

  var 
nonASCIISingleCaseWordChar = /[u00dfu0587u0590-u05f4u0600-u06ffu3040-u309fu30a0-u30ffu3400-u4db5u4e00-u9fccuac00-ud7af]/;
  function 
isWordCharBasic(ch) {
    return /
w/.test(ch) || ch "x80" &&
      (
ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
  }
  function 
isWordChar(chhelper) {
    if (!
helper) { return isWordCharBasic(ch) }
    if (
helper.source.indexOf("\w") > -&& isWordCharBasic(ch)) { return true }
    return 
helper.test(ch)
  }

  function 
isEmpty(obj) {
    for (var 
n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
    return 
true
  
}

  
// Extending unicode characters. A series of a non-extending char +
  // any number of extending chars is treated as a single unit as far
  // as editing and measuring is concerned. This is not fully correct,
  // since some scripts/fonts/browsers also treat other configurations
  // of code points as a group.
  
var extendingChars = /[u0300-u036fu0483-u0489u0591-u05bdu05bfu05c1u05c2u05c4u05c5u05c7u0610-u061au064b-u065eu0670u06d6-u06dcu06de-u06e4u06e7u06e8u06ea-u06edu0711u0730-u074au07a6-u07b0u07eb-u07f3u0816-u0819u081b-u0823u0825-u0827u0829-u082du0900-u0902u093cu0941-u0948u094du0951-u0955u0962u0963u0981u09bcu09beu09c1-u09c4u09cdu09d7u09e2u09e3u0a01u0a02u0a3cu0a41u0a42u0a47u0a48u0a4b-u0a4du0a51u0a70u0a71u0a75u0a81u0a82u0abcu0ac1-u0ac5u0ac7u0ac8u0acdu0ae2u0ae3u0b01u0b3cu0b3eu0b3fu0b41-u0b44u0b4du0b56u0b57u0b62u0b63u0b82u0bbeu0bc0u0bcdu0bd7u0c3e-u0c40u0c46-u0c48u0c4a-u0c4du0c55u0c56u0c62u0c63u0cbcu0cbfu0cc2u0cc6u0cccu0ccdu0cd5u0cd6u0ce2u0ce3u0d3eu0d41-u0d44u0d4du0d57u0d62u0d63u0dcau0dcfu0dd2-u0dd4u0dd6u0ddfu0e31u0e34-u0e3au0e47-u0e4eu0eb1u0eb4-u0eb9u0ebbu0ebcu0ec8-u0ecdu0f18u0f19u0f35u0f37u0f39u0f71-u0f7eu0f80-u0f84u0f86u0f87u0f90-u0f97u0f99-u0fbcu0fc6u102d-u1030u1032-u1037u1039u103au103du103eu1058u1059u105e-u1060u1071-u1074u1082u1085u1086u108du109du135fu1712-u1714u1732-u1734u1752u1753u1772u1773u17b7-u17bdu17c6u17c9-u17d3u17ddu180b-u180du18a9u1920-u1922u1927u1928u1932u1939-u193bu1a17u1a18u1a56u1a58-u1a5eu1a60u1a62u1a65-u1a6cu1a73-u1a7cu1a7fu1b00-u1b03u1b34u1b36-u1b3au1b3cu1b42u1b6b-u1b73u1b80u1b81u1ba2-u1ba5u1ba8u1ba9u1c2c-u1c33u1c36u1c37u1cd0-u1cd2u1cd4-u1ce0u1ce2-u1ce8u1cedu1dc0-u1de6u1dfd-u1dffu200cu200du20d0-u20f0u2cef-u2cf1u2de0-u2dffu302a-u302fu3099u309aua66f-ua672ua67cua67dua6f0ua6f1ua802ua806ua80bua825ua826ua8c4ua8e0-ua8f1ua926-ua92dua947-ua951ua980-ua982ua9b3ua9b6-ua9b9ua9bcuaa29-uaa2euaa31uaa32uaa35uaa36uaa43uaa4cuaab0uaab2-uaab4uaab7uaab8uaabeuaabfuaac1uabe5uabe8uabedudc00-udfffufb1eufe00-ufe0fufe20-ufe26uff9euff9f]/;
  function 
isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }

  
// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
  
function skipExtendingChars(strposdir) {
    while ((
dir pos pos str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
    return 
pos
  
}

  
// Returns the value from the range [`from`; `to`] that satisfies
  // `pred` and is closest to `from`. Assumes that at least `to`
  // satisfies `pred`. Supports `from` being greater than `to`.
  
function findFirst(predfromto) {
    
// At any point we are certain `to` satisfies `pred`, don't know
    // whether `from` does.
    
var dir from to ? -1;
    for (;;) {
      if (
from == to) { return from }
      var 
midF = (from to) / 2mid dir Math.ceil(midF) : Math.floor(midF);
      if (
mid == from) { return pred(mid) ? from to }
      if (
pred(mid)) { to mid; }
      else { 
from mid dir; }
    }
  }

  
// BIDI HELPERS

  
function iterateBidiSections(orderfromtof) {
    if (!
order) { return f(fromto"ltr"0) }
    var 
found false;
    for (var 
0order.length; ++i) {
      var 
part order[i];
      if (
part.from to && part.to from || from == to && part.to == from) {
        
f(Math.max(part.fromfrom), Math.min(part.toto), part.level == "rtl" "ltr"i);
        
found true;
      }
    }
    if (!
found) { f(fromto"ltr"); }
  }

  var 
bidiOther null;
  function 
getBidiPartAt(orderchsticky) {
    var 
found;
    
bidiOther null;
    for (var 
0order.length; ++i) {
      var 
cur order[i];
      if (
cur.from ch && cur.to ch) { return }
      if (
cur.to == ch) {
        if (
cur.from != cur.to && sticky == "before") { found i; }
        else { 
bidiOther i; }
      }
      if (
cur.from == ch) {
        if (
cur.from != cur.to && sticky != "before") { found i; }
        else { 
bidiOther i; }
      }
    }
    return 
found != null found bidiOther
  
}

  
// Bidirectional ordering algorithm
  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
  // that this (partially) implements.

  // One-char codes used for character types:
  // L (L):   Left-to-Right
  // R (R):   Right-to-Left
  // r (AL):  Right-to-Left Arabic
  // 1 (EN):  European Number
  // + (ES):  European Number Separator
  // % (ET):  European Number Terminator
  // n (AN):  Arabic Number
  // , (CS):  Common Number Separator
  // m (NSM): Non-Spacing Mark
  // b (BN):  Boundary Neutral
  // s (B):   Paragraph Separator
  // t (S):   Segment Separator
  // w (WS):  Whitespace
  // N (ON):  Other Neutrals

  // Returns null if characters are ordered as they appear
  // (left-to-right), or an array of sections ({from, to, level}
  // objects) in the order in which they occur visually.
  
var bidiOrdering = (function() {
    
// Character types for codepoints 0 to 0xff
    
var lowTypes "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
    
// Character types for codepoints 0x600 to 0x6f9
    
var arabicTypes "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
    function 
charType(code) {
      if (
code <= 0xf7) { return lowTypes.charAt(code) }
      else if (
0x590 <= code && code <= 0x5f4) { return "R" }
      else if (
0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code 0x600) }
      else if (
0x6ee <= code && code <= 0x8ac) { return "r" }
      else if (
0x2000 <= code && code <= 0x200b) { return "w" }
      else if (
code == 0x200c) { return "b" }
      else { return 
"L" }
    }

    var 
bidiRE = /[u0590-u05f4u0600-u06ffu0700-u08ac]/;
    var 
isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;

    function 
BidiSpan(levelfromto) {
      
this.level level;
      
this.from fromthis.to to;
    }

    return function(
strdirection) {
      var 
outerType direction == "ltr" "L" "R";

      if (
str.length == || direction == "ltr" && !bidiRE.test(str)) { return false }
      var 
len str.lengthtypes = [];
      for (var 
0len; ++i)
        { 
types.push(charType(str.charCodeAt(i))); }

      
// W1. Examine each non-spacing mark (NSM) in the level run, and
      // change the type of the NSM to the type of the previous
      // character. If the NSM is at the start of the level run, it will
      // get the type of sor.
      
for (var i$0prev outerTypei$len; ++i$1) {
        var 
type types[i$1];
        if (
type == "m") { types[i$1] = prev; }
        else { 
prev type; }
      }

      
// W2. Search backwards from each instance of a European number
      // until the first strong type (R, L, AL, or sor) is found. If an
      // AL is found, change the type of the European number to Arabic
      // number.
      // W3. Change all ALs to R.
      
for (var i$0cur outerTypei$len; ++i$2) {
        var 
type$types[i$2];
        if (
type$== "1" && cur == "r") { types[i$2] = "n"; }
        else if (
isStrong.test(type$1)) { cur type$1; if (type$== "r") { types[i$2] = "R"; } }
      }

      
// W4. A single European separator between two European numbers
      // changes to a European number. A single common separator between
      // two numbers of the same type changes to that type.
      
for (var i$1prev$types[0]; i$len 1; ++i$3) {
        var 
type$types[i$3];
        if (
type$== "+" && prev$== "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
        else if (
type$== "," && prev$== types[i$3+1] &&
                 (
prev$== "1" || prev$== "n")) { types[i$3] = prev$1; }
        
prev$type$2;
      }

      
// W5. A sequence of European terminators adjacent to European
      // numbers changes to all European numbers.
      // W6. Otherwise, separators and terminators change to Other
      // Neutral.
      
for (var i$0i$len; ++i$4) {
        var 
type$types[i$4];
        if (
type$== ",") { types[i$4] = "N"; }
        else if (
type$== "%") {
          var 
end = (void 0);
          for (
end i$1end len && types[end] == "%"; ++end) {}
          var 
replace = (i$&& types[i$4-1] == "!") || (end len && types[end] == "1") ? "1" "N";
          for (var 
i$4end; ++j) { types[j] = replace; }
          
i$end 1;
        }
      }

      
// W7. Search backwards from each instance of a European number
      // until the first strong type (R, L, or sor) is found. If an L is
      // found, then change the type of the European number to L.
      
for (var i$0cur$outerTypei$len; ++i$5) {
        var 
type$types[i$5];
        if (
cur$== "L" && type$== "1") { types[i$5] = "L"; }
        else if (
isStrong.test(type$4)) { cur$type$4; }
      }

      
// N1. A sequence of neutrals takes the direction of the
      // surrounding strong text if the text on both sides has the same
      // direction. European and Arabic numbers act as if they were R in
      // terms of their influence on neutrals. Start-of-level-run (sor)
      // and end-of-level-run (eor) are used at level run boundaries.
      // N2. Any remaining neutrals take the embedding direction.
      
for (var i$0i$len; ++i$6) {
        if (
isNeutral.test(types[i$6])) {
          var 
end$= (void 0);
          for (
end$i$1end$len && isNeutral.test(types[end$1]); ++end$1) {}
          var 
before = (i$types[i$6-1] : outerType) == "L";
          var 
after = (end$len types[end$1] : outerType) == "L";
          var 
replace$before == after ? (before "L" "R") : outerType;
          for (var 
j$i$6j$end$1; ++j$1) { types[j$1] = replace$1; }
          
i$end$1;
        }
      }

      
// Here we depart from the documented algorithm, in order to avoid
      // building up an actual levels array. Since there are only three
      // levels (0, 1, 2) in an implementation that doesn't take
      // explicit embedding into account, we can build up the order on
      // the fly, without following the level-based algorithm.
      
var order = [], m;
      for (var 
i$0i$len;) {
        if (
countsAsLeft.test(types[i$7])) {
          var 
start i$7;
          for (++
i$7i$len && countsAsLeft.test(types[i$7]); ++i$7) {}
          
order.push(new BidiSpan(0starti$7));
        } else {
          var 
pos i$7at order.lengthisRTL direction == "rtl" 0;
          for (++
i$7i$len && types[i$7] != "L"; ++i$7) {}
          for (var 
j$posj$i$7;) {
            if (
countsAsNum.test(types[j$2])) {
              if (
pos j$2) { order.splice(at0, new BidiSpan(1posj$2)); at += isRTL; }
              var 
nstart j$2;
              for (++
j$2j$i$&& countsAsNum.test(types[j$2]); ++j$2) {}
              
order.splice(at0, new BidiSpan(2nstartj$2));
              
at += isRTL;
              
pos j$2;
            } else { ++
j$2; }
          }
          if (
pos i$7) { order.splice(at0, new BidiSpan(1posi$7)); }
        }
      }
      if (
direction == "ltr") {
        if (
order[0].level == && (str.match(/^s+/))) {
          
order[0].from m[0].length;
          
order.unshift(new BidiSpan(00m[0].length));
        }
        if (
lst(order).level == && (str.match(/s+$/))) {
          
lst(order).to -= m[0].length;
          
order.push(new BidiSpan(0len m[0].lengthlen));
        }
      }

      return 
direction == "rtl" order.reverse() : order
    
}
  })();

  
// Get the bidi ordering for the given line (and cache it). Returns
  // false for lines that are fully left-to-right, and an array of
  // BidiSpan objects otherwise.
  
function getOrder(linedirection) {
    var 
order line.order;
    if (
order == null) { order line.order bidiOrdering(line.textdirection); }
    return 
order
  
}

  
// EVENT HANDLING

  // Lightweight event framework. on/off also work on DOM nodes,
  // registering native DOM handlers.

  
var noHandlers = [];

  var 
on = function(emittertypef) {
    if (
emitter.addEventListener) {
      
emitter.addEventListener(typeffalse);
    } else if (
emitter.attachEvent) {
      
emitter.attachEvent("on" typef);
    } else {
      var 
map emitter._handlers || (emitter._handlers = {});
      
map[type] = (map[type] || noHandlers).concat(f);
    }
  };

  function 
getHandlers(emittertype) {
    return 
emitter._handlers && emitter._handlers[type] || noHandlers
  
}

  function 
off(emittertypef) {
    if (
emitter.removeEventListener) {
      
emitter.removeEventListener(typeffalse);
    } else if (
emitter.detachEvent) {
      
emitter.detachEvent("on" typef);
    } else {
      var 
map emitter._handlersarr map && map[type];
      if (
arr) {
        var 
index indexOf(arrf);
        if (
index > -1)
          { 
map[type] = arr.slice(0index).concat(arr.slice(index 1)); }
      }
    }
  }

  function 
signal(emittertype /*, values...*/) {
    var 
handlers getHandlers(emittertype);
    if (!
handlers.length) { return }
    var 
args = Array.prototype.slice.call(arguments2);
    for (var 
0handlers.length; ++i) { handlers[i].apply(nullargs); }
  }

  
// The DOM events that CodeMirror handles can be overridden by
  // registering a (non-DOM) handler on the editor for the event name,
  // and preventDefault-ing the event in that handler.
  
function signalDOMEvent(cmeoverride) {
    if (
typeof e == "string")
      { 
= {typeepreventDefault: function() { this.defaultPrevented true; }}; }
    
signal(cmoverride || e.typecme);
    return 
e_defaultPrevented(e) || e.codemirrorIgnore
  
}

  function 
signalCursorActivity(cm) {
    var 
arr cm._handlers && cm._handlers.cursorActivity;
    if (!
arr) { return }
    var 
set cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
    for (var 
0arr.length; ++i) { if (indexOf(setarr[i]) == -1)
      { 
set.push(arr[i]); } }
  }

  function 
hasHandler(emittertype) {
    return 
getHandlers(emittertype).length 0
  
}

  
// Add on and off methods to a constructor's prototype, to make
  // registering events on such objects more convenient.
  
function eventMixin(ctor) {
    
ctor.prototype.on = function(typef) {on(thistypef);};
    
ctor.prototype.off = function(typef) {off(thistypef);};
  }

  
// Due to the fact that we still support jurassic IE versions, some
  // compatibility wrappers are needed.

  
function e_preventDefault(e) {
    if (
e.preventDefault) { e.preventDefault(); }
    else { 
e.returnValue false; }
  }
  function 
e_stopPropagation(e) {
    if (
e.stopPropagation) { e.stopPropagation(); }
    else { 
e.cancelBubble true; }
  }
  function 
e_defaultPrevented(e) {
    return 
e.defaultPrevented != null e.defaultPrevented e.returnValue == false
  
}
  function 
e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}

  function 
e_target(e) {return e.target || e.srcElement}
  function 
e_button(e) {
    var 
e.which;
    if (
== null) {
      if (
e.button 1) { 1; }
      else if (
e.button 2) { 3; }
      else if (
e.button 4) { 2; }
    }
    if (
mac && e.ctrlKey && == 1) { 3; }
    return 
b
  
}

  
// Detect drag-and-drop
  
var dragAndDrop = function() {
    
// There is *some* kind of drag-and-drop support in IE6-8, but I
    // couldn't get it to work yet.
    
if (ie && ie_version 9) { return false }
    var 
div elt('div');
    return 
"draggable" in div || "dragDrop" in div
  
}();

  var 
zwspSupported;
  function 
zeroWidthElement(measure) {
    if (
zwspSupported == null) {
      var 
test elt("span""u200b");
      
removeChildrenAndAdd(measureelt("span", [testdocument.createTextNode("x")]));
      if (
measure.firstChild.offsetHeight != 0)
        { 
zwspSupported test.offsetWidth <= && test.offsetHeight && !(ie && ie_version 8); }
    }
    var 
node zwspSupported elt("span""u200b") :
      
elt("span""u00a0"null"display: inline-block; width: 1px; margin-right: -1px");
    
node.setAttribute("cm-text""");
    return 
node
  
}

  
// Feature-detect IE's crummy client rect reporting for bidi text
  
var badBidiRects;
  function 
hasBadBidiRects(measure) {
    if (
badBidiRects != null) { return badBidiRects }
    var 
txt removeChildrenAndAdd(measuredocument.createTextNode("Au062eA"));
    var 
r0 range(txt01).getBoundingClientRect();
    var 
r1 range(txt12).getBoundingClientRect();
    
removeChildren(measure);
    if (!
r0 || r0.left == r0.right) { return false // Safari returns null in some cases (#2780)
    
return badBidiRects = (r1.right r0.right 3)
  }

  
// See if "".split is the broken IE version, if so, provide an
  // alternative way to split lines.
  
var splitLinesAuto "nnb".split(/n/).length != ? function (string) {
    var 
pos 0result = [], string.length;
    while (
pos <= l) {
      var 
nl string.indexOf("n"pos);
      if (
nl == -1) { nl string.length; }
      var 
line string.slice(posstring.charAt(nl 1) == "r" nl nl);
      var 
rt line.indexOf("r");
      if (
rt != -1) {
        
result.push(line.slice(0rt));
        
pos += rt 1;
      } else {
        
result.push(line);
        
pos nl 1;
      }
    }
    return 
result
  
} : function (string) { return string.split(/rn?|n/); };

  var 
hasSelection window.getSelection ? function (te) {
    try { return 
te.selectionStart != te.selectionEnd }
    catch(
e) { return false }
  } : function (
te) {
    var 
range;
    try {
range te.ownerDocument.selection.createRange();}
    catch(
e) {}
    if (!
range || range.parentElement() != te) { return false }
    return 
range.compareEndPoints("StartToEnd"range) != 0
  
};

  var 
hasCopyEvent = (function () {
    var 
elt("div");
    if (
"oncopy" in e) { return true }
    
e.setAttribute("oncopy""return;");
    return 
typeof e.oncopy == "function"
  
})();

  var 
badZoomedRects null;
  function 
hasBadZoomedRects(measure) {
    if (
badZoomedRects != null) { return badZoomedRects }
    var 
node removeChildrenAndAdd(measureelt("span""x"));
    var 
normal node.getBoundingClientRect();
    var 
fromRange range(node01).getBoundingClientRect();
    return 
badZoomedRects Math.abs(normal.left fromRange.left) > 1
  
}

  
// Known modes, by name and by MIME
  
var modes = {}, mimeModes = {};

  
// Extra arguments are stored as the mode's dependencies, which is
  // used by (legacy) mechanisms like loadmode.js to automatically
  // load a mode. (Preferred mechanism is the require/define calls.)
  
function defineMode(namemode) {
    if (
arguments.length 2)
      { 
mode.dependencies = Array.prototype.slice.call(arguments2); }
    
modes[name] = mode;
  }

  function 
defineMIME(mimespec) {
    
mimeModes[mime] = spec;
  }

  
// Given a MIME type, a {name, ...options} config object, or a name
  // string, return a mode config object.
  
function resolveMode(spec) {
    if (
typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
      
spec mimeModes[spec];
    } else if (
spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
      var 
found mimeModes[spec.name];
      if (
typeof found == "string") { found = {namefound}; }
      
spec createObj(foundspec);
      
spec.name found.name;
    } else if (
typeof spec == "string" && /^[w-]+/[w-]++xml$/.test(spec)) {
      return 
resolveMode("application/xml")
    } else if (
typeof spec == "string" && /^[w-]+/[w-]++json$/.test(spec)) {
      return 
resolveMode("application/json")
    }
    if (
typeof spec == "string") { return {namespec} }
    else { return 
spec || {name"null"} }
  }

  
// Given a mode spec (anything that resolveMode accepts), find and
  // initialize an actual mode object.
  
function getMode(optionsspec) {
    
spec resolveMode(spec);
    var 
mfactory modes[spec.name];
    if (!
mfactory) { return getMode(options"text/plain") }
    var 
modeObj mfactory(optionsspec);
    if (
modeExtensions.hasOwnProperty(spec.name)) {
      var 
exts modeExtensions[spec.name];
      for (var 
prop in exts) {
        if (!
exts.hasOwnProperty(prop)) { continue }
        if (
modeObj.hasOwnProperty(prop)) { modeObj["_" prop] = modeObj[prop]; }
        
modeObj[prop] = exts[prop];
      }
    }
    
modeObj.name spec.name;
    if (
spec.helperType) { modeObj.helperType spec.helperType; }
    if (
spec.modeProps) { for (var prop$1 in spec.modeProps)
      { 
modeObj[prop$1] = spec.modeProps[prop$1]; } }

    return 
modeObj
  
}

  
// This can be used to attach properties to mode objects from
  // outside the actual mode definition.
  
var modeExtensions = {};
  function 
extendMode(modeproperties) {
    var 
exts modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
    
copyObj(propertiesexts);
  }

  function 
copyState(modestate) {
    if (
state === true) { return state }
    if (
mode.copyState) { return mode.copyState(state) }
    var 
nstate = {};
    for (var 
n in state) {
      var 
val state[n];
      if (
val instanceof Array) { val val.concat([]); }
      
nstate[n] = val;
    }
    return 
nstate
  
}

  
// Given a mode and a state (for that mode), find the inner mode and
  // state at the position that the state refers to.
  
function innerMode(modestate) {
    var 
info;
    while (
mode.innerMode) {
      
info mode.innerMode(state);
      if (!
info || info.mode == mode) { break }
      
state info.state;
      
mode info.mode;
    }
    return 
info || {modemodestatestate}
  }

  function 
startState(modea1a2) {
    return 
mode.startState mode.startState(a1a2) : true
  
}

  
// STRING STREAM

  // Fed to the mode parsers, provides helper functions to make
  // parsers more succinct.

  
var StringStream = function(stringtabSizelineOracle) {
    
this.pos this.start 0;
    
this.string string;
    
this.tabSize tabSize || 8;
    
this.lastColumnPos this.lastColumnValue 0;
    
this.lineStart 0;
    
this.lineOracle lineOracle;
  };

  
StringStream.prototype.eol = function () {return this.pos >= this.string.length};
  
StringStream.prototype.sol = function () {return this.pos == this.lineStart};
  
StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
  
StringStream.prototype.next = function () {
    if (
this.pos this.string.length)
      { return 
this.string.charAt(this.pos++) }
  };
  
StringStream.prototype.eat = function (match) {
    var 
ch this.string.charAt(this.pos);
    var 
ok;
    if (
typeof match == "string") { ok ch == match; }
    else { 
ok ch && (match.test match.test(ch) : match(ch)); }
    if (
ok) {++this.pos; return ch}
  };
  
StringStream.prototype.eatWhile = function (match) {
    var 
start this.pos;
    while (
this.eat(match)){}
    return 
this.pos start
  
};
  
StringStream.prototype.eatSpace = function () {
    var 
start this.pos;
    while (/[
su00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; }
    return 
this.pos start
  
};
  
StringStream.prototype.skipToEnd = function () {this.pos this.string.length;};
  
StringStream.prototype.skipTo = function (ch) {
    var 
found this.string.indexOf(chthis.pos);
    if (
found > -1) {this.pos found; return true}
  };
  
StringStream.prototype.backUp = function (n) {this.pos -= n;};
  
StringStream.prototype.column = function () {
    if (
this.lastColumnPos this.start) {
      
this.lastColumnValue countColumn(this.stringthis.startthis.tabSizethis.lastColumnPosthis.lastColumnValue);
      
this.lastColumnPos this.start;
    }
    return 
this.lastColumnValue - (this.lineStart countColumn(this.stringthis.lineStartthis.tabSize) : 0)
  };
  
StringStream.prototype.indentation = function () {
    return 
countColumn(this.stringnullthis.tabSize) -
      (
this.lineStart countColumn(this.stringthis.lineStartthis.tabSize) : 0)
  };
  
StringStream.prototype.match = function (patternconsumecaseInsensitive) {
    if (
typeof pattern == "string") {
      var 
cased = function (str) { return caseInsensitive str.toLowerCase() : str; };
      var 
substr this.string.substr(this.pospattern.length);
      if (
cased(substr) == cased(pattern)) {
        if (
consume !== false) { this.pos += pattern.length; }
        return 
true
      
}
    } else {
      var 
match this.string.slice(this.pos).match(pattern);
      if (
match && match.index 0) { return null }
      if (
match && consume !== false) { this.pos += match[0].length; }
      return 
match
    
}
  };
  
StringStream.prototype.current = function (){return this.string.slice(this.startthis.pos)};
  
StringStream.prototype.hideFirstChars = function (ninner) {
    
this.lineStart += n;
    try { return 
inner() }
    finally { 
this.lineStart -= n; }
  };
  
StringStream.prototype.lookAhead = function (n) {
    var 
oracle this.lineOracle;
    return 
oracle && oracle.lookAhead(n)
  };
  
StringStream.prototype.baseToken = function () {
    var 
oracle this.lineOracle;
    return 
oracle && oracle.baseToken(this.pos)
  };

  
// Find the line object corresponding to the given line number.
  
function getLine(docn) {
    
-= doc.first;
    if (
|| >= doc.size) { throw new Error("There is no line " + (doc.first) + " in the document.") }
    var 
chunk doc;
    while (!
chunk.lines) {
      for (var 
0;; ++i) {
        var 
child chunk.children[i], sz child.chunkSize();
        if (
sz) { chunk child; break }
        
-= sz;
      }
    }
    return 
chunk.lines[n]
  }

  
// Get the part of a document between two positions, as an array of
  // strings.
  
function getBetween(docstartend) {
    var 
out = [], start.line;
    
doc.iter(start.lineend.line 1, function (line) {
      var 
text line.text;
      if (
== end.line) { text text.slice(0end.ch); }
      if (
== start.line) { text text.slice(start.ch); }
      
out.push(text);
      ++
n;
    });
    return 
out
  
}
  
// Get the lines between from and to, as array of strings.
  
function getLines(docfromto) {
    var 
out = [];
    
doc.iter(fromto, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
    
return out
  
}

  
// Update the height of a line, propagating the height change
  // upwards to parent nodes.
  
function updateLineHeight(lineheight) {
    var 
diff height line.height;
    if (
diff) { for (var linenn.parent) { n.height += diff; } }
  }

  
// Given a line object, find its line number by walking up through
  // its parent links.
  
function lineNo(line) {
    if (
line.parent == null) { return null }
    var 
cur line.parentno indexOf(cur.linesline);
    for (var 
chunk cur.parentchunkcur chunkchunk chunk.parent) {
      for (var 
0;; ++i) {
        if (
chunk.children[i] == cur) { break }
        
no += chunk.children[i].chunkSize();
      }
    }
    return 
no cur.first
  
}

  
// Find the line at the given vertical position, using the height
  // information in the document tree.
  
function lineAtHeight(chunkh) {
    var 
chunk.first;
    
outer: do {
      for (var 
i$0i$chunk.children.length; ++i$1) {
        var 
child chunk.children[i$1], ch child.height;
        if (
ch) { chunk child; continue outer }
        
-= ch;
        
+= child.chunkSize();
      }
      return 
n
    
} while (!chunk.lines)
    var 
0;
    for (; 
chunk.lines.length; ++i) {
      var 
line chunk.lines[i], lh line.height;
      if (
lh) { break }
      
-= lh;
    }
    return 
i
  
}

  function 
isLine(docl) {return >= doc.first && doc.first doc.size}

  function 
lineNumberFor(optionsi) {
    return 
String(options.lineNumberFormatter(options.firstLineNumber))
  }

  
// A Pos instance represents a position within the text.
  
function Pos(linechsticky) {
    if ( 
sticky === void 0 sticky null;

    if (!(
this instanceof Pos)) { return new Pos(linechsticky) }
    
this.line line;
    
this.ch ch;
    
this.sticky sticky;
  }

  
// Compare two positions, return 0 if they are the same, a negative
  // number when a is less, and a positive number otherwise.
  
function cmp(ab) { return a.line b.line || a.ch b.ch }

  function 
equalCursorPos(ab) { return a.sticky == b.sticky && cmp(ab) == }

  function 
copyPos(x) {return Pos(x.linex.ch)}
  function 
maxPos(ab) { return cmp(ab) < }
  function 
minPos(ab) { return cmp(ab) < }

  
// Most of the external API clips given positions to make sure they
  // actually exist within the document.
  
function clipLine(docn) {return Math.max(doc.firstMath.min(ndoc.first doc.size 1))}
  function 
clipPos(docpos) {
    if (
pos.line doc.first) { return Pos(doc.first0) }
    var 
last doc.first doc.size 1;
    if (
pos.line last) { return Pos(lastgetLine(doclast).text.length) }
    return 
clipToLen(posgetLine(docpos.line).text.length)
  }
  function 
clipToLen(poslinelen) {
    var 
ch pos.ch;
    if (
ch == null || ch linelen) { return Pos(pos.linelinelen) }
    else if (
ch 0) { return Pos(pos.line0) }
    else { return 
pos }
  }
  function 
clipPosArray(doc, array) {
    var 
out = [];
    for (var 
0< array.lengthi++) { out[i] = clipPos(doc, array[i]); }
    return 
out
  
}

  var 
SavedContext = function(statelookAhead) {
    
this.state state;
    
this.lookAhead lookAhead;
  };

  var 
Context = function(docstatelinelookAhead) {
    
this.state state;
    
this.doc doc;
    
this.line line;
    
this.maxLookAhead lookAhead || 0;
    
this.baseTokens null;
    
this.baseTokenPos 1;
  };

  
Context.prototype.lookAhead = function (n) {
    var 
line this.doc.getLine(this.line n);
    if (
line != null && this.maxLookAhead) { this.maxLookAhead n; }
    return 
line
  
};

  
Context.prototype.baseToken = function (n) {
    if (!
this.baseTokens) { return null }
    while (
this.baseTokens[this.baseTokenPos] <= n)
      { 
this.baseTokenPos += 2; }
    var 
type this.baseTokens[this.baseTokenPos 1];
    return {
typetype && type.replace(/( |^)overlay .*/, ""),
            
sizethis.baseTokens[this.baseTokenPos] - n}
  };

  
Context.prototype.nextLine = function () {
    
this.line++;
    if (
this.maxLookAhead 0) { this.maxLookAhead--; }
  };

  
Context.fromSaved = function (docsavedline) {
    if (
saved instanceof SavedContext)
      { return new 
Context(doccopyState(doc.modesaved.state), linesaved.lookAhead) }
    else
      { return new 
Context(doccopyState(doc.modesaved), line) }
  };

  
Context.prototype.save = function (copy) {
    var 
state copy !== false copyState(this.doc.modethis.state) : this.state;
    return 
this.maxLookAhead ? new SavedContext(statethis.maxLookAhead) : state
  
};


  
// Compute a style array (an array starting with a mode generation
  // -- for invalidation -- followed by pairs of end positions and
  // style strings), which is used to highlight the tokens on the
  // line.
  
function highlightLine(cmlinecontextforceToEnd) {
    
// A styles array always starts with a number identifying the
    // mode/overlays that it is based on (for easy invalidation).
    
var st = [cm.state.modeGen], lineClasses = {};
    
// Compute the base array of styles
    
runMode(cmline.textcm.doc.modecontext, function (endstyle) { return st.push(endstyle); },
            
lineClassesforceToEnd);
    var 
state context.state;

    
// Run overlays, adjust style array.
    
var loop = function ( ) {
      
context.baseTokens st;
      var 
overlay cm.state.overlays[o], 1at 0;
      
context.state true;
      
runMode(cmline.textoverlay.modecontext, function (endstyle) {
        var 
start i;
        
// Ensure there's a token end at the current position, and that i points at it
        
while (at end) {
          var 
i_end st[i];
          if (
i_end end)
            { 
st.splice(i1endst[i+1], i_end); }
          
+= 2;
          
at Math.min(endi_end);
        }
        if (!
style) { return }
        if (
overlay.opaque) {
          
st.splice(startstartend"overlay " style);
          
start 2;
        } else {
          for (; 
start istart += 2) {
            var 
cur st[start+1];
            
st[start+1] = (cur cur " " "") + "overlay " style;
          }
        }
      }, 
lineClasses);
      
context.state state;
      
context.baseTokens null;
      
context.baseTokenPos 1;
    };

    for (var 
0cm.state.overlays.length; ++oloop);

    return {
stylesstclasseslineClasses.bgClass || lineClasses.textClass lineClasses null}
  }

  function 
getLineStyles(cmlineupdateFrontier) {
    if (!
line.styles || line.styles[0] != cm.state.modeGen) {
      var 
context getContextBefore(cmlineNo(line));
      var 
resetState line.text.length cm.options.maxHighlightLength && copyState(cm.doc.modecontext.state);
      var 
result highlightLine(cmlinecontext);
      if (
resetState) { context.state resetState; }
      
line.stateAfter context.save(!resetState);
      
line.styles result.styles;
      if (
result.classes) { line.styleClasses result.classes; }
      else if (
line.styleClasses) { line.styleClasses null; }
      if (
updateFrontier === cm.doc.highlightFrontier)
        { 
cm.doc.modeFrontier Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
    }
    return 
line.styles
  
}

  function 
getContextBefore(cmnprecise) {
    var 
doc cm.docdisplay cm.display;
    if (!
doc.mode.startState) { return new Context(doctruen) }
    var 
start findStartLine(cmnprecise);
    var 
saved start doc.first && getLine(docstart 1).stateAfter;
    var 
context saved Context.fromSaved(docsavedstart) : new Context(docstartState(doc.mode), start);

    
doc.iter(startn, function (line) {
      
processLine(cmline.textcontext);
      var 
pos context.line;
      
line.stateAfter pos == || pos == || pos >= display.viewFrom && pos display.viewTo context.save() : null;
      
context.nextLine();
    });
    if (
precise) { doc.modeFrontier context.line; }
    return 
context
  
}

  
// Lightweight form of highlight -- proceed over this line and
  // update state, but don't save a style array. Used for lines that
  // aren't currently visible.
  
function processLine(cmtextcontextstartAt) {
    var 
mode cm.doc.mode;
    var 
stream = new StringStream(textcm.options.tabSizecontext);
    
stream.start stream.pos startAt || 0;
    if (
text == "") { callBlankLine(modecontext.state); }
    while (!
stream.eol()) {
      
readToken(modestreamcontext.state);
      
stream.start stream.pos;
    }
  }

  function 
callBlankLine(modestate) {
    if (
mode.blankLine) { return mode.blankLine(state) }
    if (!
mode.innerMode) { return }
    var 
inner innerMode(modestate);
    if (
inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
  }

  function 
readToken(modestreamstateinner) {
    for (var 
010i++) {
      if (
inner) { inner[0] = innerMode(modestate).mode; }
      var 
style mode.token(streamstate);
      if (
stream.pos stream.start) { return style }
    }
    throw new 
Error("Mode " mode.name " failed to advance stream.")
  }

  var 
Token = function(streamtypestate) {
    
this.start stream.startthis.end stream.pos;
    
this.string stream.current();
    
this.type type || null;
    
this.state state;
  };

  
// Utility for getTokenAt and getLineTokens
  
function takeToken(cmpospreciseasArray) {
    var 
doc cm.docmode doc.modestyle;
    
pos clipPos(docpos);
    var 
line getLine(docpos.line), context getContextBefore(cmpos.lineprecise);
    var 
stream = new StringStream(line.textcm.options.tabSizecontext), tokens;
    if (
asArray) { tokens = []; }
    while ((
asArray || stream.pos pos.ch) && !stream.eol()) {
      
stream.start stream.pos;
      
style readToken(modestreamcontext.state);
      if (
asArray) { tokens.push(new Token(streamstylecopyState(doc.modecontext.state))); }
    }
    return 
asArray tokens : new Token(streamstylecontext.state)
  }

  function 
extractLineClasses(typeoutput) {
    if (
type) { for (;;) {
      var 
lineClass type.match(/(?:^|s+)line-(background-)?(S+)/);
      if (!
lineClass) { break }
      
type type.slice(0lineClass.index) + type.slice(lineClass.index lineClass[0].length);
      var 
prop lineClass[1] ? "bgClass" "textClass";
      if (
output[prop] == null)
        { 
output[prop] = lineClass[2]; }
      else if (!(new 
RegExp("(?:^|\s)" lineClass[2] + "(?:$|\s)")).test(output[prop]))
        { 
output[prop] += " " lineClass[2]; }
    } }
    return 
type
  
}

  
// Run the given mode's parser over a line, calling f for each token.
  
function runMode(cmtextmodecontextflineClassesforceToEnd) {
    var 
flattenSpans mode.flattenSpans;
    if (
flattenSpans == null) { flattenSpans cm.options.flattenSpans; }
    var 
curStart 0curStyle null;
    var 
stream = new StringStream(textcm.options.tabSizecontext), style;
    var 
inner cm.options.addModeClass && [null];
    if (
text == "") { extractLineClasses(callBlankLine(modecontext.state), lineClasses); }
    while (!
stream.eol()) {
      if (
stream.pos cm.options.maxHighlightLength) {
        
flattenSpans false;
        if (
forceToEnd) { processLine(cmtextcontextstream.pos); }
        
stream.pos text.length;
        
style null;
      } else {
        
style extractLineClasses(readToken(modestreamcontext.stateinner), lineClasses);
      }
      if (
inner) {
        var 
mName inner[0].name;
        if (
mName) { style "m-" + (style mName " " style mName); }
      }
      if (!
flattenSpans || curStyle != style) {
        while (
curStart stream.start) {
          
curStart Math.min(stream.startcurStart 5000);
          
f(curStartcurStyle);
        }
        
curStyle style;
      }
      
stream.start stream.pos;
    }
    while (
curStart stream.pos) {
      
// Webkit seems to refuse to render text nodes longer than 57444
      // characters, and returns inaccurate measurements in nodes
      // starting around 5000 chars.
      
var pos Math.min(stream.poscurStart 5000);
      
f(poscurStyle);
      
curStart pos;
    }
  }

  
// Finds the line to start with when starting a parse. Tries to
  // find a line with a stateAfter, so that it can start with a
  // valid state. If that fails, it returns the line with the
  // smallest indentation, which tends to need the least context to
  // parse correctly.
  
function findStartLine(cmnprecise) {
    var 
minindentminlinedoc cm.doc;
    var 
lim precise ? -- (cm.doc.mode.innerMode 1000 100);
    for (var 
search nsearch lim; --search) {
      if (
search <= doc.first) { return doc.first }
      var 
line getLine(docsearch 1), after line.stateAfter;
      if (
after && (!precise || search + (after instanceof SavedContext after.lookAhead 0) <= doc.modeFrontier))
        { return 
search }
      var 
indented countColumn(line.textnullcm.options.tabSize);
      if (
minline == null || minindent indented) {
        
minline search 1;
        
minindent indented;
      }
    }
    return 
minline
  
}

  function 
retreatFrontier(docn) {
    
doc.modeFrontier Math.min(doc.modeFrontiern);
    if (
doc.highlightFrontier 10) { return }
    var 
start doc.first;
    for (var 
line 1line startline--) {
      var 
saved getLine(docline).stateAfter;
      
// change is on 3
      // state on line 1 looked ahead 2 -- so saw 3
      // test 1 + 2 < 3 should cover this
      
if (saved && (!(saved instanceof SavedContext) || line saved.lookAhead n)) {
        
start line 1;
        break
      }
    }
    
doc.highlightFrontier Math.min(doc.highlightFrontierstart);
  }

  
// Optimize some code when these features are not used.
  
var sawReadOnlySpans falsesawCollapsedSpans false;

  function 
seeReadOnlySpans() {
    
sawReadOnlySpans true;
  }

  function 
seeCollapsedSpans() {
    
sawCollapsedSpans true;
  }

  
// TEXTMARKER SPANS

  
function MarkedSpan(markerfromto) {
    
this.marker marker;
    
this.from fromthis.to to;
  }

  
// Search an array of spans for a span matching the given marker.
  
function getMarkedSpanFor(spansmarker) {
    if (
spans) { for (var 0spans.length; ++i) {
      var 
span spans[i];
      if (
span.marker == marker) { return span }
    } }
  }
  
// Remove a span from an array, returning undefined if no spans are
  // left (we don't store arrays for lines without spans).
  
function removeMarkedSpan(spansspan) {
    var 
r;
    for (var 
0spans.length; ++i)
      { if (
spans[i] != span) { (|| (= [])).push(spans[i]); } }
    return 
r
  
}
  
// Add a span to a line.
  
function addMarkedSpan(linespan) {
    
line.markedSpans line.markedSpans line.markedSpans.concat([span]) : [span];
    
span.marker.attachLine(line);
  }

  
// Used for the algorithm that adjusts markers for a change in the
  // document. These functions cut an array of spans at a given
  // character position, returning an array of remaining chunks (or
  // undefined if nothing remains).
  
function markedSpansBefore(oldstartChisInsert) {
    var 
nw;
    if (
old) { for (var 0old.length; ++i) {
      var 
span old[i], marker span.marker;
      var 
startsBefore span.from == null || (marker.inclusiveLeft span.from <= startCh span.from startCh);
      if (
startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
        var 
endsAfter span.to == null || (marker.inclusiveRight span.to >= startCh span.to startCh)
        ;(
nw || (nw = [])).push(new MarkedSpan(markerspan.fromendsAfter null span.to));
      }
    } }
    return 
nw
  
}
  function 
markedSpansAfter(oldendChisInsert) {
    var 
nw;
    if (
old) { for (var 0old.length; ++i) {
      var 
span old[i], marker span.marker;
      var 
endsAfter span.to == null || (marker.inclusiveRight span.to >= endCh span.to endCh);
      if (
endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
        var 
startsBefore span.from == null || (marker.inclusiveLeft span.from <= endCh span.from endCh)
        ;(
nw || (nw = [])).push(new MarkedSpan(markerstartsBefore null span.from endCh,
                                              
span.to == null null span.to endCh));
      }
    } }
    return 
nw
  
}

  
// Given a change object, compute the new set of marker spans that
  // cover the line in which the change took place. Removes spans
  // entirely within the change, reconnects spans belonging to the
  // same marker that appear on both sides of the change, and cuts off
  // spans partially within the change. Returns an array of span
  // arrays with one element for each line in (after) the change.
  
function stretchSpansOverChange(docchange) {
    if (
change.full) { return null }
    var 
oldFirst isLine(docchange.from.line) && getLine(docchange.from.line).markedSpans;
    var 
oldLast isLine(docchange.to.line) && getLine(docchange.to.line).markedSpans;
    if (!
oldFirst && !oldLast) { return null }

    var 
startCh change.from.chendCh change.to.chisInsert cmp(change.fromchange.to) == 0;
    
// Get the spans that 'stick out' on both sides
    
var first markedSpansBefore(oldFirststartChisInsert);
    var 
last markedSpansAfter(oldLastendChisInsert);

    
// Next, merge those two ends
    
var sameLine change.text.length == 1offset lst(change.text).length + (sameLine startCh 0);
    if (
first) {
      
// Fix up .to properties of first
      
for (var 0first.length; ++i) {
        var 
span first[i];
        if (
span.to == null) {
          var 
found getMarkedSpanFor(lastspan.marker);
          if (!
found) { span.to startCh; }
          else if (
sameLine) { span.to found.to == null null found.to offset; }
        }
      }
    }
    if (
last) {
      
// Fix up .from in last (or move them into first in case of sameLine)
      
for (var i$0i$last.length; ++i$1) {
        var 
span$last[i$1];
        if (
span$1.to != null) { span$1.to += offset; }
        if (
span$1.from == null) {
          var 
found$getMarkedSpanFor(firstspan$1.marker);
          if (!
found$1) {
            
span$1.from offset;
            if (
sameLine) { (first || (first = [])).push(span$1); }
          }
        } else {
          
span$1.from += offset;
          if (
sameLine) { (first || (first = [])).push(span$1); }
        }
      }
    }
    
// Make sure we didn't create any zero-length spans
    
if (first) { first clearEmptySpans(first); }
    if (
last && last != first) { last clearEmptySpans(last); }

    var 
newMarkers = [first];
    if (!
sameLine) {
      
// Fill gap with whole-line-spans
      
var gap change.text.length 2gapMarkers;
      if (
gap && first)
        { for (var 
i$0i$first.length; ++i$2)
          { if (
first[i$2].to == null)
            { (
gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].markernullnull)); } } }
      for (var 
i$0i$gap; ++i$3)
        { 
newMarkers.push(gapMarkers); }
      
newMarkers.push(last);
    }
    return 
newMarkers
  
}

  
// Remove spans that are empty and don't have a clearWhenEmpty
  // option of false.
  
function clearEmptySpans(spans) {
    for (var 
0spans.length; ++i) {
      var 
span spans[i];
      if (
span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
        { 
spans.splice(i--, 1); }
    }
    if (!
spans.length) { return null }
    return 
spans
  
}

  
// Used to 'clip' out readOnly ranges when making a change.
  
function removeReadOnlyRanges(docfromto) {
    var 
markers null;
    
doc.iter(from.lineto.line 1, function (line) {
      if (
line.markedSpans) { for (var 0line.markedSpans.length; ++i) {
        var 
mark line.markedSpans[i].marker;
        if (
mark.readOnly && (!markers || indexOf(markersmark) == -1))
          { (
markers || (markers = [])).push(mark); }
      } }
    });
    if (!
markers) { return null }
    var 
parts = [{fromfromtoto}];
    for (var 
0markers.length; ++i) {
      var 
mk markers[i], mk.find(0);
      for (var 
0parts.length; ++j) {
        var 
parts[j];
        if (
cmp(p.tom.from) < || cmp(p.fromm.to) > 0) { continue }
        var 
newParts = [j1], dfrom cmp(p.fromm.from), dto cmp(p.tom.to);
        if (
dfrom || !mk.inclusiveLeft && !dfrom)
          { 
newParts.push({fromp.fromtom.from}); }
        if (
dto || !mk.inclusiveRight && !dto)
          { 
newParts.push({fromm.totop.to}); }
        
parts.splice.apply(partsnewParts);
        
+= newParts.length 3;
      }
    }
    return 
parts
  
}

  
// Connect or disconnect spans from a line.
  
function detachMarkedSpans(line) {
    var 
spans line.markedSpans;
    if (!
spans) { return }
    for (var 
0spans.length; ++i)
      { 
spans[i].marker.detachLine(line); }
    
line.markedSpans null;
  }
  function 
attachMarkedSpans(linespans) {
    if (!
spans) { return }
    for (var 
0spans.length; ++i)
      { 
spans[i].marker.attachLine(line); }
    
line.markedSpans spans;
  }

  
// Helpers used when computing which overlapping collapsed span
  // counts as the larger one.
  
function extraLeft(marker) { return marker.inclusiveLeft ? -}
  function 
extraRight(marker) { return marker.inclusiveRight }

  
// Returns a number indicating which of two overlapping collapsed
  // spans is larger (and thus includes the other). Falls back to
  // comparing ids when the spans cover exactly the same range.
  
function compareCollapsedMarkers(ab) {
    var 
lenDiff a.lines.length b.lines.length;
    if (
lenDiff != 0) { return lenDiff }
    var 
aPos a.find(), bPos b.find();
    var 
fromCmp cmp(aPos.frombPos.from) || extraLeft(a) - extraLeft(b);
    if (
fromCmp) { return -fromCmp }
    var 
toCmp cmp(aPos.tobPos.to) || extraRight(a) - extraRight(b);
    if (
toCmp) { return toCmp }
    return 
b.id a.id
  
}

  
// Find out whether a line ends or starts in a collapsed span. If
  // so, return the marker for that span.
  
function collapsedSpanAtSide(linestart) {
    var 
sps sawCollapsedSpans && line.markedSpansfound;
    if (
sps) { for (var sp = (void 0), 0sps.length; ++i) {
      
sp sps[i];
      if (
sp.marker.collapsed && (start sp.from sp.to) == null &&
          (!
found || compareCollapsedMarkers(foundsp.marker) < 0))
        { 
found sp.marker; }
    } }
    return 
found
  
}
  function 
collapsedSpanAtStart(line) { return collapsedSpanAtSide(linetrue) }
  function 
collapsedSpanAtEnd(line) { return collapsedSpanAtSide(linefalse) }

  function 
collapsedSpanAround(linech) {
    var 
sps sawCollapsedSpans && line.markedSpansfound;
    if (
sps) { for (var 0sps.length; ++i) {
      var 
sp sps[i];
      if (
sp.marker.collapsed && (sp.from == null || sp.from ch) && (sp.to == null || sp.to ch) &&
          (!
found || compareCollapsedMarkers(foundsp.marker) < 0)) { found sp.marker; }
    } }
    return 
found
  
}

  
// Test whether there exists a collapsed span that partially
  // overlaps (covers the start or end, but not both) of a new span.
  // Such overlap is not allowed.
  
function conflictingCollapsedRange(doclineNofromtomarker) {
    var 
line getLine(doclineNo);
    var 
sps sawCollapsedSpans && line.markedSpans;
    if (
sps) { for (var 0sps.length; ++i) {
      var 
sp sps[i];
      if (!
sp.marker.collapsed) { continue }
      var 
found sp.marker.find(0);
      var 
fromCmp cmp(found.fromfrom) || extraLeft(sp.marker) - extraLeft(marker);
      var 
toCmp cmp(found.toto) || extraRight(sp.marker) - extraRight(marker);
      if (
fromCmp >= && toCmp <= || fromCmp <= && toCmp >= 0) { continue }
      if (
fromCmp <= && (sp.marker.inclusiveRight && marker.inclusiveLeft cmp(found.tofrom) >= cmp(found.tofrom) > 0) ||
          
fromCmp >= && (sp.marker.inclusiveRight && marker.inclusiveLeft cmp(found.fromto) <= cmp(found.fromto) < 0))
        { return 
true }
    } }
  }

  
// A visual line is a line as drawn on the screen. Folding, for
  // example, can cause multiple logical lines to appear on the same
  // visual line. This finds the start of the visual line that the
  // given line is part of (usually that is the line itself).
  
function visualLine(line) {
    var 
merged;
    while (
merged collapsedSpanAtStart(line))
      { 
line merged.find(-1true).line; }
    return 
line
  
}

  function 
visualLineEnd(line) {
    var 
merged;
    while (
merged collapsedSpanAtEnd(line))
      { 
line merged.find(1true).line; }
    return 
line
  
}

  
// Returns an array of logical lines that continue the visual line
  // started by the argument, or undefined if there are no such lines.
  
function visualLineContinued(line) {
    var 
mergedlines;
    while (
merged collapsedSpanAtEnd(line)) {
      
line merged.find(1true).line
      
;(lines || (lines = [])).push(line);
    }
    return 
lines
  
}

  
// Get the line number of the start of the visual line that the
  // given line number is part of.
  
function visualLineNo(doclineN) {
    var 
line getLine(doclineN), vis visualLine(line);
    if (
line == vis) { return lineN }
    return 
lineNo(vis)
  }

  
// Get the line number of the start of the next visual line after
  // the given line.
  
function visualLineEndNo(doclineN) {
    if (
lineN doc.lastLine()) { return lineN }
    var 
line getLine(doclineN), merged;
    if (!
lineIsHidden(docline)) { return lineN }
    while (
merged collapsedSpanAtEnd(line))
      { 
line merged.find(1true).line; }
    return 
lineNo(line) + 1
  
}

  
// Compute whether a line is hidden. Lines count as hidden when they
  // are part of a visual line that starts with another line, or when
  // they are entirely covered by collapsed, non-widget span.
  
function lineIsHidden(docline) {
    var 
sps sawCollapsedSpans && line.markedSpans;
    if (
sps) { for (var sp = (void 0), 0sps.length; ++i) {
      
sp sps[i];
      if (!
sp.marker.collapsed) { continue }
      if (
sp.from == null) { return true }
      if (
sp.marker.widgetNode) { continue }
      if (
sp.from == && sp.marker.inclusiveLeft && lineIsHiddenInner(doclinesp))
        { return 
true }
    } }
  }
  function 
lineIsHiddenInner(doclinespan) {
    if (
span.to == null) {
      var 
end span.marker.find(1true);
      return 
lineIsHiddenInner(docend.linegetMarkedSpanFor(end.line.markedSpansspan.marker))
    }
    if (
span.marker.inclusiveRight && span.to == line.text.length)
      { return 
true }
    for (var 
sp = (void 0), 0line.markedSpans.length; ++i) {
      
sp line.markedSpans[i];
      if (
sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
          (
sp.to == null || sp.to != span.from) &&
          (
sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
          
lineIsHiddenInner(doclinesp)) { return true }
    }
  }

  
// Find the height above the given line.
  
function heightAtLine(lineObj) {
    
lineObj visualLine(lineObj);

    var 
0chunk lineObj.parent;
    for (var 
0chunk.lines.length; ++i) {
      var 
line chunk.lines[i];
      if (
line == lineObj) { break }
      else { 
+= line.height; }
    }
    for (var 
chunk.parentpchunk pchunk.parent) {
      for (var 
i$0i$p.children.length; ++i$1) {
        var 
cur p.children[i$1];
        if (
cur == chunk) { break }
        else { 
+= cur.height; }
      }
    }
    return 
h
  
}

  
// Compute the character length of a line, taking into account
  // collapsed ranges (see markText) that might hide parts, and join
  // other lines onto it.
  
function lineLength(line) {
    if (
line.height == 0) { return }
    var 
len line.text.lengthmergedcur line;
    while (
merged collapsedSpanAtStart(cur)) {
      var 
found merged.find(0true);
      
cur found.from.line;
      
len += found.from.ch found.to.ch;
    }
    
cur line;
    while (
merged collapsedSpanAtEnd(cur)) {
      var 
found$merged.find(0true);
      
len -= cur.text.length found$1.from.ch;
      
cur found$1.to.line;
      
len += cur.text.length found$1.to.ch;
    }
    return 
len
  
}

  
// Find the longest line in the document.
  
function findMaxLine(cm) {
    var 
cm.displaydoc cm.doc;
    
d.maxLine getLine(docdoc.first);
    
d.maxLineLength lineLength(d.maxLine);
    
d.maxLineChanged true;
    
doc.iter(function (line) {
      var 
len lineLength(line);
      if (
len d.maxLineLength) {
        
d.maxLineLength len;
        
d.maxLine line;
      }
    });
  }

  
// LINE DATA STRUCTURE

  // Line objects. These hold state related to a line, including
  // highlighting info (the styles array).
  
var Line = function(textmarkedSpansestimateHeight) {
    
this.text text;
    
attachMarkedSpans(thismarkedSpans);
    
this.height estimateHeight estimateHeight(this) : 1;
  };

  
Line.prototype.lineNo = function () { return lineNo(this) };
  
eventMixin(Line);

  
// Change the content (text, markers) of a line. Automatically
  // invalidates cached information and tries to re-estimate the
  // line's height.
  
function updateLine(linetextmarkedSpansestimateHeight) {
    
line.text text;
    if (
line.stateAfter) { line.stateAfter null; }
    if (
line.styles) { line.styles null; }
    if (
line.order != null) { line.order null; }
    
detachMarkedSpans(line);
    
attachMarkedSpans(linemarkedSpans);
    var 
estHeight estimateHeight estimateHeight(line) : 1;
    if (
estHeight != line.height) { updateLineHeight(lineestHeight); }
  }

  
// Detach a line from the document tree and its markers.
  
function cleanUpLine(line) {
    
line.parent null;
    
detachMarkedSpans(line);
  }

  
// Convert a style as returned by a mode (either null, or a string
  // containing one or more styles) to a CSS style. This is cached,
  // and also looks for line-wide styles.
  
var styleToClassCache = {}, styleToClassCacheWithMode = {};
  function 
interpretTokenStyle(styleoptions) {
    if (!
style || /^s*$/.test(style)) { return null }
    var 
cache options.addModeClass styleToClassCacheWithMode styleToClassCache;
    return 
cache[style] ||
      (
cache[style] = style.replace(/S+/g"cm-$&"))
  }

  
// Render the DOM representation of the text of a line. Also builds
  // up a 'line map', which points at the DOM nodes that represent
  // specific stretches of text, and is used by the measuring code.
  // The returned object contains the DOM node, this map, and
  // information about line-wide styles that were set by the mode.
  
function buildLineContent(cmlineView) {
    
// The padding-right forces the element to have a 'border', which
    // is needed on Webkit to be able to get line-level bounding
    // rectangles for it (in measureChar).
    
var content eltP("span"nullnullwebkit "padding-right: .1px" null);
    var 
builder = {preeltP("pre", [content], "CodeMirror-line"), contentcontent,
                   
col0pos0cmcm,
                   
trailingSpacefalse,
                   
splitSpacescm.getOption("lineWrapping")};
    
lineView.measure = {};

    
// Iterate over the logical lines that make up this visual line.
    
for (var 0<= (lineView.rest lineView.rest.length 0); i++) {
      var 
line lineView.rest[1] : lineView.lineorder = (void 0);
      
builder.pos 0;
      
builder.addToken buildToken;
      
// Optionally wire in some hacks into the token-rendering
      // algorithm, to deal with browser quirks.
      
if (hasBadBidiRects(cm.display.measure) && (order getOrder(linecm.doc.direction)))
        { 
builder.addToken buildTokenBadBidi(builder.addTokenorder); }
      
builder.map = [];
      var 
allowFrontierUpdate lineView != cm.display.externalMeasured && lineNo(line);
      
insertLineContent(linebuildergetLineStyles(cmlineallowFrontierUpdate));
      if (
line.styleClasses) {
        if (
line.styleClasses.bgClass)
          { 
builder.bgClass joinClasses(line.styleClasses.bgClassbuilder.bgClass || ""); }
        if (
line.styleClasses.textClass)
          { 
builder.textClass joinClasses(line.styleClasses.textClassbuilder.textClass || ""); }
      }

      
// Ensure at least a single node is present, for measuring.
      
if (builder.map.length == 0)
        { 
builder.map.push(00builder.content.appendChild(zeroWidthElement(cm.display.measure))); }

      
// Store the map and a cache object for the current logical line
      
if (== 0) {
        
lineView.measure.map builder.map;
        
lineView.measure.cache = {};
      } else {
  (
lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
        ;(
lineView.measure.caches || (lineView.measure.caches = [])).push({});
      }
    }

    
// See issue #2901
    
if (webkit) {
      var 
last builder.content.lastChild;
      if (/
bcm-tabb/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
        { 
builder.content.className "cm-tab-wrap-hack"; }
    }

    
signal(cm"renderLine"cmlineView.linebuilder.pre);
    if (
builder.pre.className)
      { 
builder.textClass joinClasses(builder.pre.classNamebuilder.textClass || ""); }

    return 
builder
  
}

  function 
defaultSpecialCharPlaceholder(ch) {
    var 
token elt("span""u2022""cm-invalidchar");
    
token.title "\u" ch.charCodeAt(0).toString(16);
    
token.setAttribute("aria-label"token.title);
    return 
token
  
}

  
// Build up the DOM representation for a single token, and add it to
  // the line map. Takes care to render special characters separately.
  
function buildToken(buildertextstylestartStyleendStylecssattributes) {
    if (!
text) { return }
    var 
displayText builder.splitSpaces splitSpaces(textbuilder.trailingSpace) : text;
    var 
special builder.cm.state.specialCharsmustWrap false;
    var 
content;
    if (!
special.test(text)) {
      
builder.col += text.length;
      
content document.createTextNode(displayText);
      
builder.map.push(builder.posbuilder.pos text.lengthcontent);
      if (
ie && ie_version 9) { mustWrap true; }
      
builder.pos += text.length;
    } else {
      
content document.createDocumentFragment();
      var 
pos 0;
      while (
true) {
        
special.lastIndex pos;
        var 
special.exec(text);
        var 
skipped m.index pos text.length pos;
        if (
skipped) {
          var 
txt document.createTextNode(displayText.slice(pospos skipped));
          if (
ie && ie_version 9) { content.appendChild(elt("span", [txt])); }
          else { 
content.appendChild(txt); }
          
builder.map.push(builder.posbuilder.pos skippedtxt);
          
builder.col += skipped;
          
builder.pos += skipped;
        }
        if (!
m) { break }
        
pos += skipped 1;
        var 
txt$= (void 0);
        if (
m[0] == "t") {
          var 
tabSize builder.cm.options.tabSizetabWidth tabSize builder.col tabSize;
          
txt$content.appendChild(elt("span"spaceStr(tabWidth), "cm-tab"));
          
txt$1.setAttribute("role""presentation");
          
txt$1.setAttribute("cm-text""t");
          
builder.col += tabWidth;
        } else if (
m[0] == "r" || m[0] == "n") {
          
txt$content.appendChild(elt("span"m[0] == "r" "u240d" "u2424""cm-invalidchar"));
          
txt$1.setAttribute("cm-text"m[0]);
          
builder.col += 1;
        } else {
          
txt$builder.cm.options.specialCharPlaceholder(m[0]);
          
txt$1.setAttribute("cm-text"m[0]);
          if (
ie && ie_version 9) { content.appendChild(elt("span", [txt$1])); }
          else { 
content.appendChild(txt$1); }
          
builder.col += 1;
        }
        
builder.map.push(builder.posbuilder.pos 1txt$1);
        
builder.pos++;
      }
    }
    
builder.trailingSpace displayText.charCodeAt(text.length 1) == 32;
    if (
style || startStyle || endStyle || mustWrap || css) {
      var 
fullStyle style || "";
      if (
startStyle) { fullStyle += startStyle; }
      if (
endStyle) { fullStyle += endStyle; }
      var 
token elt("span", [content], fullStylecss);
      if (
attributes) {
        for (var 
attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class")
          { 
token.setAttribute(attrattributes[attr]); } }
      }
      return 
builder.content.appendChild(token)
    }
    
builder.content.appendChild(content);
  }

  
// Change some spaces to NBSP to prevent the browser from collapsing
  // trailing spaces at the end of a line when rendering text (issue #1362).
  
function splitSpaces(texttrailingBefore) {
    if (
text.length && !/  /.test(text)) { return text }
    var 
spaceBefore trailingBeforeresult "";
    for (var 
0text.lengthi++) {
      var 
ch text.charAt(i);
      if (
ch == " " && spaceBefore && (== text.length || text.charCodeAt(1) == 32))
        { 
ch "u00a0"; }
      
result += ch;
      
spaceBefore ch == " ";
    }
    return 
result
  
}

  
// Work around nonsense dimensions being reported for stretches of
  // right-to-left text.
  
function buildTokenBadBidi(innerorder) {
    return function (
buildertextstylestartStyleendStylecssattributes) {
      
style style style " cm-force-border" "cm-force-border";
      var 
start builder.posend start text.length;
      for (;;) {
        
// Find the part that overlaps with the start of this text
        
var part = (void 0);
        for (var 
0order.lengthi++) {
          
part order[i];
          if (
part.to start && part.from <= start) { break }
        }
        if (
part.to >= end) { return inner(buildertextstylestartStyleendStylecssattributes) }
        
inner(buildertext.slice(0part.to start), stylestartStylenullcssattributes);
        
startStyle null;
        
text text.slice(part.to start);
        
start part.to;
      }
    }
  }

  function 
buildCollapsedSpan(buildersizemarkerignoreWidget) {
    var 
widget = !ignoreWidget && marker.widgetNode;
    if (
widget) { builder.map.push(builder.posbuilder.pos sizewidget); }
    if (!
ignoreWidget && builder.cm.display.input.needsContentAttribute) {
      if (!
widget)
        { 
widget builder.content.appendChild(document.createElement("span")); }
      
widget.setAttribute("cm-marker"marker.id);
    }
    if (
widget) {
      
builder.cm.display.input.setUneditable(widget);
      
builder.content.appendChild(widget);
    }
    
builder.pos += size;
    
builder.trailingSpace false;
  }

  
// Outputs a number of spans to make up a line, taking highlighting
  // and marked text into account.
  
function insertLineContent(linebuilderstyles) {
    var 
spans line.markedSpansallText line.textat 0;
    if (!
spans) {
      for (var 
i$1i$styles.lengthi$1+=2)
        { 
builder.addToken(builderallText.slice(atat styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
      return
    }

    var 
len allText.lengthpos 01text ""stylecss;
    var 
nextChange 0spanStylespanEndStylespanStartStylecollapsedattributes;
    for (;;) {
      if (
nextChange == pos) { // Update current marker set
        
spanStyle spanEndStyle spanStartStyle css "";
        
attributes null;
        
collapsed nullnextChange Infinity;
        var 
foundBookmarks = [], endStyles = (void 0);
        for (var 
0spans.length; ++j) {
          var 
sp spans[j], sp.marker;
          if (
m.type == "bookmark" && sp.from == pos && m.widgetNode) {
            
foundBookmarks.push(m);
          } else if (
sp.from <= pos && (sp.to == null || sp.to pos || m.collapsed && sp.to == pos && sp.from == pos)) {
            if (
sp.to != null && sp.to != pos && nextChange sp.to) {
              
nextChange sp.to;
              
spanEndStyle "";
            }
            if (
m.className) { spanStyle += " " m.className; }
            if (
m.css) { css = (css css ";" "") + m.css; }
            if (
m.startStyle && sp.from == pos) { spanStartStyle += " " m.startStyle; }
            if (
m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStylesp.to); }
            
// support for the old title property
            // https://github.com/codemirror/CodeMirror/pull/5673
            
if (m.title) { (attributes || (attributes = {})).title m.title; }
            if (
m.attributes) {
              for (var 
attr in m.attributes)
                { (
attributes || (attributes = {}))[attr] = m.attributes[attr]; }
            }
            if (
m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.markerm) < 0))
              { 
collapsed sp; }
          } else if (
sp.from pos && nextChange sp.from) {
            
nextChange sp.from;
          }
        }
        if (
endStyles) { for (var j$0j$endStyles.lengthj$+= 2)
          { if (
endStyles[j$1] == nextChange) { spanEndStyle += " " endStyles[j$1]; } } }

        if (!
collapsed || collapsed.from == pos) { for (var j$0j$foundBookmarks.length; ++j$2)
          { 
buildCollapsedSpan(builder0foundBookmarks[j$2]); } }
        if (
collapsed && (collapsed.from || 0) == pos) {
          
buildCollapsedSpan(builder, (collapsed.to == null len collapsed.to) - pos,
                             
collapsed.markercollapsed.from == null);
          if (
collapsed.to == null) { return }
          if (
collapsed.to == pos) { collapsed false; }
        }
      }
      if (
pos >= len) { break }

      var 
upto Math.min(lennextChange);
      while (
true) {
        if (
text) {
          var 
end pos text.length;
          if (!
collapsed) {
            var 
tokenText end upto text.slice(0upto pos) : text;
            
builder.addToken(buildertokenTextstyle style spanStyle spanStyle,
                             
spanStartStylepos tokenText.length == nextChange spanEndStyle ""cssattributes);
          }
          if (
end >= upto) {text text.slice(upto pos); pos upto; break}
          
pos end;
          
spanStartStyle "";
        }
        
text allText.slice(atat styles[i++]);
        
style interpretTokenStyle(styles[i++], builder.cm.options);
      }
    }
  }


  
// These objects are used to represent the visible (currently drawn)
  // part of the document. A LineView may correspond to multiple
  // logical lines, if those are connected by collapsed ranges.
  
function LineView(doclinelineN) {
    
// The starting line
    
this.line line;
    
// Continuing lines, if any
    
this.rest visualLineContinued(line);
    
// Number of logical lines in this visual line
    
this.size this.rest lineNo(lst(this.rest)) - lineN 1;
    
this.node this.text null;
    
this.hidden lineIsHidden(docline);
  }

  
// Create a range of LineView objects for the given lines.
  
function buildViewArray(cmfromto) {
    var array = [], 
nextPos;
    for (var 
pos frompos topos nextPos) {
      var 
view = new LineView(cm.docgetLine(cm.docpos), pos);
      
nextPos pos view.size;
      array.
push(view);
    }
    return array
  }

  var 
operationGroup null;

  function 
pushOperation(op) {
    if (
operationGroup) {
      
operationGroup.ops.push(op);
    } else {
      
op.ownsGroup operationGroup = {
        
ops: [op],
        
delayedCallbacks: []
      };
    }
  }

  function 
fireCallbacksForOps(group) {
    
// Calls delayed callbacks and cursorActivity handlers until no
    // new ones appear
    
var callbacks group.delayedCallbacks0;
    do {
      for (; 
callbacks.lengthi++)
        { 
callbacks[i].call(null); }
      for (var 
0group.ops.lengthj++) {
        var 
op group.ops[j];
        if (
op.cursorActivityHandlers)
          { while (
op.cursorActivityCalled op.cursorActivityHandlers.length)
            { 
op.cursorActivityHandlers[op.cursorActivityCalled++].call(nullop.cm); } }
      }
    } while (
callbacks.length)
  }

  function 
finishOperation(opendCb) {
    var 
group op.ownsGroup;
    if (!
group) { return }

    try { 
fireCallbacksForOps(group); }
    finally {
      
operationGroup null;
      
endCb(group);
    }
  }

  var 
orphanDelayedCallbacks null;

  
// Often, we want to signal events at a point where we are in the
  // middle of some work, but don't want the handler to start calling
  // other methods on the editor, which might be in an inconsistent
  // state or simply not expect any other events to happen.
  // signalLater looks whether there are any handlers, and schedules
  // them to be executed when the last operation ends, or, if no
  // operation is active, when a timeout fires.
  
function signalLater(emittertype /*, values...*/) {
    var 
arr getHandlers(emittertype);
    if (!
arr.length) { return }
    var 
args = Array.prototype.slice.call(arguments2), list;
    if (
operationGroup) {
      list = 
operationGroup.delayedCallbacks;
    } else if (
orphanDelayedCallbacks) {
      list = 
orphanDelayedCallbacks;
    } else {
      list = 
orphanDelayedCallbacks = [];
      
setTimeout(fireOrphanDelayed0);
    }
    var 
loop = function ( ) {
      list.
push(function () { return arr[i].apply(nullargs); });
    };

    for (var 
0arr.length; ++i)
      
loop);
  }

  function 
fireOrphanDelayed() {
    var 
delayed orphanDelayedCallbacks;
    
orphanDelayedCallbacks null;
    for (var 
0delayed.length; ++i) { delayed[i](); }
  }

  
// When an aspect of a line changes, a string is added to
  // lineView.changes. This updates the relevant part of the line's
  // DOM structure.
  
function updateLineForChanges(cmlineViewlineNdims) {
    for (var 
0lineView.changes.lengthj++) {
      var 
type lineView.changes[j];
      if (
type == "text") { updateLineText(cmlineView); }
      else if (
type == "gutter") { updateLineGutter(cmlineViewlineNdims); }
      else if (
type == "class") { updateLineClasses(cmlineView); }
      else if (
type == "widget") { updateLineWidgets(cmlineViewdims); }
    }
    
lineView.changes null;
  }

  
// Lines with gutter elements, widgets or a background class need to
  // be wrapped, and have the extra elements added to the wrapper div
  
function ensureLineWrapped(lineView) {
    if (
lineView.node == lineView.text) {
      
lineView.node elt("div"nullnull"position: relative");
      if (
lineView.text.parentNode)
        { 
lineView.text.parentNode.replaceChild(lineView.nodelineView.text); }
      
lineView.node.appendChild(lineView.text);
      if (
ie && ie_version 8) { lineView.node.style.zIndex 2; }
    }
    return 
lineView.node
  
}

  function 
updateLineBackground(cmlineView) {
    var 
cls lineView.bgClass lineView.bgClass " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
    if (
cls) { cls += " CodeMirror-linebackground"; }
    if (
lineView.background) {
      if (
cls) { lineView.background.className cls; }
      else { 
lineView.background.parentNode.removeChild(lineView.background); lineView.background null; }
    } else if (
cls) {
      var 
wrap ensureLineWrapped(lineView);
      
lineView.background wrap.insertBefore(elt("div"nullcls), wrap.firstChild);
      
cm.display.input.setUneditable(lineView.background);
    }
  }

  
// Wrapper around buildLineContent which will reuse the structure
  // in display.externalMeasured when possible.
  
function getLineContent(cmlineView) {
    var 
ext cm.display.externalMeasured;
    if (
ext && ext.line == lineView.line) {
      
cm.display.externalMeasured null;
      
lineView.measure ext.measure;
      return 
ext.built
    
}
    return 
buildLineContent(cmlineView)
  }

  
// Redraw the line's text. Interacts with the background and text
  // classes because the mode may output tokens that influence these
  // classes.
  
function updateLineText(cmlineView) {
    var 
cls lineView.text.className;
    var 
built getLineContent(cmlineView);
    if (
lineView.text == lineView.node) { lineView.node built.pre; }
    
lineView.text.parentNode.replaceChild(built.prelineView.text);
    
lineView.text built.pre;
    if (
built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
      
lineView.bgClass built.bgClass;
      
lineView.textClass built.textClass;
      
updateLineClasses(cmlineView);
    } else if (
cls) {
      
lineView.text.className cls;
    }
  }

  function 
updateLineClasses(cmlineView) {
    
updateLineBackground(cmlineView);
    if (
lineView.line.wrapClass)
      { 
ensureLineWrapped(lineView).className lineView.line.wrapClass; }
    else if (
lineView.node != lineView.text)
      { 
lineView.node.className ""; }
    var 
textClass lineView.textClass lineView.textClass " " + (lineView.line.textClass || "") : lineView.line.textClass;
    
lineView.text.className textClass || "";
  }

  function 
updateLineGutter(cmlineViewlineNdims) {
    if (
lineView.gutter) {
      
lineView.node.removeChild(lineView.gutter);
      
lineView.gutter null;
    }
    if (
lineView.gutterBackground) {
      
lineView.node.removeChild(lineView.gutterBackground);
      
lineView.gutterBackground null;
    }
    if (
lineView.line.gutterClass) {
      var 
wrap ensureLineWrapped(lineView);
      
lineView.gutterBackground elt("div"null"CodeMirror-gutter-background " lineView.line.gutterClass,
                                      (
"left: " + (cm.options.fixedGutter dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
      
cm.display.input.setUneditable(lineView.gutterBackground);
      
wrap.insertBefore(lineView.gutterBackgroundlineView.text);
    }
    var 
markers lineView.line.gutterMarkers;
    if (
cm.options.lineNumbers || markers) {
      var 
wrap$ensureLineWrapped(lineView);
      var 
gutterWrap lineView.gutter elt("div"null"CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter dims.fixedPos : -dims.gutterTotalWidth) + "px"));
      
cm.display.input.setUneditable(gutterWrap);
      
wrap$1.insertBefore(gutterWraplineView.text);
      if (
lineView.line.gutterClass)
        { 
gutterWrap.className += " " lineView.line.gutterClass; }
      if (
cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
        { 
lineView.lineNumber gutterWrap.appendChild(
          
elt("div"lineNumberFor(cm.optionslineN),
              
"CodeMirror-linenumber CodeMirror-gutter-elt",
              (
"left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
      if (
markers) { for (var 0cm.display.gutterSpecs.length; ++k) {
        var 
id cm.display.gutterSpecs[k].classNamefound markers.hasOwnProperty(id) && markers[id];
        if (
found)
          { 
gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
                                     (
"left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
      } }
    }
  }

  function 
updateLineWidgets(cmlineViewdims) {
    if (
lineView.alignable) { lineView.alignable null; }
    var 
isWidget classTest("CodeMirror-linewidget");
    for (var 
node lineView.node.firstChildnext = (void 0); nodenode next) {
      
next node.nextSibling;
      if (
isWidget.test(node.className)) { lineView.node.removeChild(node); }
    }
    
insertLineWidgets(cmlineViewdims);
  }

  
// Build a line's DOM representation from scratch
  
function buildLineElement(cmlineViewlineNdims) {
    var 
built getLineContent(cmlineView);
    
lineView.text lineView.node built.pre;
    if (
built.bgClass) { lineView.bgClass built.bgClass; }
    if (
built.textClass) { lineView.textClass built.textClass; }

    
updateLineClasses(cmlineView);
    
updateLineGutter(cmlineViewlineNdims);
    
insertLineWidgets(cmlineViewdims);
    return 
lineView.node
  
}

  
// A lineView may contain multiple logical lines (when merged by
  // collapsed spans). The widgets for all of them need to be drawn.
  
function insertLineWidgets(cmlineViewdims) {
    
insertLineWidgetsFor(cmlineView.linelineViewdimstrue);
    if (
lineView.rest) { for (var 0lineView.rest.lengthi++)
      { 
insertLineWidgetsFor(cmlineView.rest[i], lineViewdimsfalse); } }
  }

  function 
insertLineWidgetsFor(cmlinelineViewdimsallowAbove) {
    if (!
line.widgets) { return }
    var 
wrap ensureLineWrapped(lineView);
    for (var 
0ws line.widgetsws.length; ++i) {
      var 
widget ws[i], node elt("div", [widget.node], "CodeMirror-linewidget" + (widget.className " " widget.className ""));
      if (!
widget.handleMouseEvents) { node.setAttribute("cm-ignore-events""true"); }
      
positionLineWidget(widgetnodelineViewdims);
      
cm.display.input.setUneditable(node);
      if (
allowAbove && widget.above)
        { 
wrap.insertBefore(nodelineView.gutter || lineView.text); }
      else
        { 
wrap.appendChild(node); }
      
signalLater(widget"redraw");
    }
  }

  function 
positionLineWidget(widgetnodelineViewdims) {
    if (
widget.noHScroll) {
  (
lineView.alignable || (lineView.alignable = [])).push(node);
      var 
width dims.wrapperWidth;
      
node.style.left dims.fixedPos "px";
      if (!
widget.coverGutter) {
        
width -= dims.gutterTotalWidth;
        
node.style.paddingLeft dims.gutterTotalWidth "px";
      }
      
node.style.width width "px";
    }
    if (
widget.coverGutter) {
      
node.style.zIndex 5;
      
node.style.position "relative";
      if (!
widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth "px"; }
    }
  }

  function 
widgetHeight(widget) {
    if (
widget.height != null) { return widget.height }
    var 
cm widget.doc.cm;
    if (!
cm) { return }
    if (!
contains(document.bodywidget.node)) {
      var 
parentStyle "position: relative;";
      if (
widget.coverGutter)
        { 
parentStyle += "margin-left: -" cm.display.gutters.offsetWidth "px;"; }
      if (
widget.noHScroll)
        { 
parentStyle += "width: " cm.display.wrapper.clientWidth "px;"; }
      
removeChildrenAndAdd(cm.display.measureelt("div", [widget.node], nullparentStyle));
    }
    return 
widget.height widget.node.parentNode.offsetHeight
  
}

  
// Return true when the given mouse event happened in a widget
  
function eventInWidget(displaye) {
    for (var 
e_target(e); != display.wrappern.parentNode) {
      if (!
|| (n.nodeType == && n.getAttribute("cm-ignore-events") == "true") ||
          (
n.parentNode == display.sizer && != display.mover))
        { return 
true }
    }
  }

  
// POSITION MEASUREMENT

  
function paddingTop(display) {return display.lineSpace.offsetTop}
  function 
paddingVert(display) {return display.mover.offsetHeight display.lineSpace.offsetHeight}
  function 
paddingH(display) {
    if (
display.cachedPaddingH) { return display.cachedPaddingH }
    var 
removeChildrenAndAdd(display.measureelt("pre""x""CodeMirror-line-like"));
    var 
style window.getComputedStyle window.getComputedStyle(e) : e.currentStyle;
    var 
data = {leftparseInt(style.paddingLeft), rightparseInt(style.paddingRight)};
    if (!
isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH data; }
    return 
data
  
}

  function 
scrollGap(cm) { return scrollerGap cm.display.nativeBarWidth }
  function 
displayWidth(cm) {
    return 
cm.display.scroller.clientWidth scrollGap(cm) - cm.display.barWidth
  
}
  function 
displayHeight(cm) {
    return 
cm.display.scroller.clientHeight scrollGap(cm) - cm.display.barHeight
  
}

  
// Ensure the lineView.wrapping.heights array is populated. This is
  // an array of bottom offsets for the lines that make up a drawn
  // line. When lineWrapping is on, there might be more than one
  // height.
  
function ensureLineHeights(cmlineViewrect) {
    var 
wrapping cm.options.lineWrapping;
    var 
curWidth wrapping && displayWidth(cm);
    if (!
lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
      var 
heights lineView.measure.heights = [];
      if (
wrapping) {
        
lineView.measure.width curWidth;
        var 
rects lineView.text.firstChild.getClientRects();
        for (var 
0rects.length 1i++) {
          var 
cur rects[i], next rects[1];
          if (
Math.abs(cur.bottom next.bottom) > 2)
            { 
heights.push((cur.bottom next.top) / rect.top); }
        }
      }
      
heights.push(rect.bottom rect.top);
    }
  }

  
// Find a line map (mapping character offsets to text nodes) and a
  // measurement cache for the given line number. (A line view might
  // contain multiple lines when collapsed ranges are present.)
  
function mapFromLineView(lineViewlinelineN) {
    if (
lineView.line == line)
      { return {
maplineView.measure.mapcachelineView.measure.cache} }
    for (var 
0lineView.rest.lengthi++)
      { if (
lineView.rest[i] == line)
        { return {
maplineView.measure.maps[i], cachelineView.measure.caches[i]} } }
    for (var 
i$0i$lineView.rest.lengthi$1++)
      { if (
lineNo(lineView.rest[i$1]) > lineN)
        { return {
maplineView.measure.maps[i$1], cachelineView.measure.caches[i$1], beforetrue} } }
  }

  
// Render a line into the hidden node display.externalMeasured. Used
  // when measurement is needed for a line that's not in the viewport.
  
function updateExternalMeasurement(cmline) {
    
line visualLine(line);
    var 
lineN lineNo(line);
    var 
view cm.display.externalMeasured = new LineView(cm.doclinelineN);
    
view.lineN lineN;
    var 
built view.built buildLineContent(cmview);
    
view.text built.pre;
    
removeChildrenAndAdd(cm.display.lineMeasurebuilt.pre);
    return 
view
  
}

  
// Get a {top, bottom, left, right} box (in line-local coordinates)
  // for a given character.
  
function measureChar(cmlinechbias) {
    return 
measureCharPrepared(cmprepareMeasureForLine(cmline), chbias)
  }

  
// Find a line view that corresponds to the given line number.
  
function findViewForLine(cmlineN) {
    if (
lineN >= cm.display.viewFrom && lineN cm.display.viewTo)
      { return 
cm.display.view[findViewIndex(cmlineN)] }
    var 
ext cm.display.externalMeasured;
    if (
ext && lineN >= ext.lineN && lineN ext.lineN ext.size)
      { return 
ext }
  }

  
// Measurement can be split in two steps, the set-up work that
  // applies to the whole line, and the measurement of the actual
  // character. Functions like coordsChar, that need to do a lot of
  // measurements in a row, can thus ensure that the set-up work is
  // only done once.
  
function prepareMeasureForLine(cmline) {
    var 
lineN lineNo(line);
    var 
view findViewForLine(cmlineN);
    if (
view && !view.text) {
      
view null;
    } else if (
view && view.changes) {
      
updateLineForChanges(cmviewlineNgetDimensions(cm));
      
cm.curOp.forceUpdate true;
    }
    if (!
view)
      { 
view updateExternalMeasurement(cmline); }

    var 
info mapFromLineView(viewlinelineN);
    return {
      
linelineviewviewrectnull,
      
mapinfo.mapcacheinfo.cachebeforeinfo.before,
      
hasHeightsfalse
    
}
  }

  
// Given a prepared measurement object, measures the position of an
  // actual character (or fetches it from the cache).
  
function measureCharPrepared(cmpreparedchbiasvarHeight) {
    if (
prepared.before) { ch = -1; }
    var 
key ch + (bias || ""), found;
    if (
prepared.cache.hasOwnProperty(key)) {
      
found prepared.cache[key];
    } else {
      if (!
prepared.rect)
        { 
prepared.rect prepared.view.text.getBoundingClientRect(); }
      if (!
prepared.hasHeights) {
        
ensureLineHeights(cmprepared.viewprepared.rect);
        
prepared.hasHeights true;
      }
      
found measureCharInner(cmpreparedchbias);
      if (!
found.bogus) { prepared.cache[key] = found; }
    }
    return {
leftfound.leftrightfound.right,
            
topvarHeight found.rtop found.top,
            
bottomvarHeight found.rbottom found.bottom}
  }

  var 
nullRect = {left0right0top0bottom0};

  function 
nodeAndOffsetInLineMap(mapchbias) {
    var 
nodestartendcollapsemStartmEnd;
    
// First, search the line map for the text node corresponding to,
    // or closest to, the target character.
    
for (var 0map.length+= 3) {
      
mStart map[i];
      
mEnd map[1];
      if (
ch mStart) {
        
start 0end 1;
        
collapse "left";
      } else if (
ch mEnd) {
        
start ch mStart;
        
end start 1;
      } else if (
== map.length || ch == mEnd && map[3] > ch) {
        
end mEnd mStart;
        
start end 1;
        if (
ch >= mEnd) { collapse "right"; }
      }
      if (
start != null) {
        
node map[2];
        if (
mStart == mEnd && bias == (node.insertLeft "left" "right"))
          { 
collapse bias; }
        if (
bias == "left" && start == 0)
          { while (
&& map[2] == map[3] && map[1].insertLeft) {
            
node map[(-= 3) + 2];
            
collapse "left";
          } }
        if (
bias == "right" && start == mEnd mStart)
          { while (
map.length && map[3] == map[4] && !map[5].insertLeft) {
            
node map[(+= 3) + 2];
            
collapse "right";
          } }
        break
      }
    }
    return {
nodenodestartstartendendcollapsecollapsecoverStartmStartcoverEndmEnd}
  }

  function 
getUsefulRect(rectsbias) {
    var 
rect nullRect;
    if (
bias == "left") { for (var 0rects.lengthi++) {
      if ((
rect rects[i]).left != rect.right) { break }
    } } else { for (var 
i$rects.length 1i$>= 0i$1--) {
      if ((
rect rects[i$1]).left != rect.right) { break }
    } }
    return 
rect
  
}

  function 
measureCharInner(cmpreparedchbias) {
    var 
place nodeAndOffsetInLineMap(prepared.mapchbias);
    var 
node place.nodestart place.startend place.endcollapse place.collapse;

    var 
rect;
    if (
node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
      
for (var i$0i$4i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
        
while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart start))) { --start; }
        while (
place.coverStart end place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart end))) { ++end; }
        if (
ie && ie_version && start == && end == place.coverEnd place.coverStart)
          { 
rect node.parentNode.getBoundingClientRect(); }
        else
          { 
rect getUsefulRect(range(nodestartend).getClientRects(), bias); }
        if (
rect.left || rect.right || start == 0) { break }
        
end start;
        
start start 1;
        
collapse "right";
      }
      if (
ie && ie_version 11) { rect maybeUpdateRectForZooming(cm.display.measurerect); }
    } else { 
// If it is a widget, simply get the box for the whole widget.
      
if (start 0) { collapse bias "right"; }
      var 
rects;
      if (
cm.options.lineWrapping && (rects node.getClientRects()).length 1)
        { 
rect rects[bias == "right" rects.length 0]; }
      else
        { 
rect node.getBoundingClientRect(); }
    }
    if (
ie && ie_version && !start && (!rect || !rect.left && !rect.right)) {
      var 
rSpan node.parentNode.getClientRects()[0];
      if (
rSpan)
        { 
rect = {leftrSpan.leftrightrSpan.left charWidth(cm.display), toprSpan.topbottomrSpan.bottom}; }
      else
        { 
rect nullRect; }
    }

    var 
rtop rect.top prepared.rect.toprbot rect.bottom prepared.rect.top;
    var 
mid = (rtop rbot) / 2;
    var 
heights prepared.view.measure.heights;
    var 
0;
    for (; 
heights.length 1i++)
      { if (
mid heights[i]) { break } }
    var 
top heights[1] : 0bot heights[i];
    var 
result = {left: (collapse == "right" rect.right rect.left) - prepared.rect.left,
                  
right: (collapse == "left" rect.left rect.right) - prepared.rect.left,
                  
toptopbottombot};
    if (!
rect.left && !rect.right) { result.bogus true; }
    if (!
cm.options.singleCursorHeightPerLine) { result.rtop rtopresult.rbottom rbot; }

    return 
result
  
}

  
// Work around problem with bounding client rects on ranges being
  // returned incorrectly when zoomed on IE10 and below.
  
function maybeUpdateRectForZooming(measurerect) {
    if (!
window.screen || screen.logicalXDPI == null ||
        
screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
      { return 
rect }
    var 
scaleX screen.logicalXDPI screen.deviceXDPI;
    var 
scaleY screen.logicalYDPI screen.deviceYDPI;
    return {
leftrect.left scaleXrightrect.right scaleX,
            
toprect.top scaleYbottomrect.bottom scaleY}
  }

  function 
clearLineMeasurementCacheFor(lineView) {
    if (
lineView.measure) {
      
lineView.measure.cache = {};
      
lineView.measure.heights null;
      if (
lineView.rest) { for (var 0lineView.rest.lengthi++)
        { 
lineView.measure.caches[i] = {}; } }
    }
  }

  function 
clearLineMeasurementCache(cm) {
    
cm.display.externalMeasure null;
    
removeChildren(cm.display.lineMeasure);
    for (var 
0cm.display.view.lengthi++)
      { 
clearLineMeasurementCacheFor(cm.display.view[i]); }
  }

  function 
clearCaches(cm) {
    
clearLineMeasurementCache(cm);
    
cm.display.cachedCharWidth cm.display.cachedTextHeight cm.display.cachedPaddingH null;
    if (!
cm.options.lineWrapping) { cm.display.maxLineChanged true; }
    
cm.display.lineNumChars null;
  }

  function 
pageScrollX() {
    
// Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
    // which causes page_Offset and bounding client rects to use
    // different reference viewports and invalidate our calculations.
    
if (chrome && android) { return -(document.body.getBoundingClientRect().left parseInt(getComputedStyle(document.body).marginLeft)) }
    return 
window.pageXOffset || (document.documentElement || document.body).scrollLeft
  
}
  function 
pageScrollY() {
    if (
chrome && android) { return -(document.body.getBoundingClientRect().top parseInt(getComputedStyle(document.body).marginTop)) }
    return 
window.pageYOffset || (document.documentElement || document.body).scrollTop
  
}

  function 
widgetTopHeight(lineObj) {
    var 
height 0;
    if (
lineObj.widgets) { for (var 0lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
      { 
height += widgetHeight(lineObj.widgets[i]); } } }
    return 
height
  
}

  
// Converts a {top, bottom, left, right} box from line-local
  // coordinates into another coordinate system. Context may be one of
  // "line", "div" (display.lineDiv), "local"./null (editor), "window",
  // or "page".
  
function intoCoordSystem(cmlineObjrectcontextincludeWidgets) {
    if (!
includeWidgets) {
      var 
height widgetTopHeight(lineObj);
      
rect.top += heightrect.bottom += height;
    }
    if (
context == "line") { return rect }
    if (!
context) { context "local"; }
    var 
yOff heightAtLine(lineObj);
    if (
context == "local") { yOff += paddingTop(cm.display); }
    else { 
yOff -= cm.display.viewOffset; }
    if (
context == "page" || context == "window") {
      var 
lOff cm.display.lineSpace.getBoundingClientRect();
      
yOff += lOff.top + (context == "window" pageScrollY());
      var 
xOff lOff.left + (context == "window" pageScrollX());
      
rect.left += xOffrect.right += xOff;
    }
    
rect.top += yOffrect.bottom += yOff;
    return 
rect
  
}

  
// Coverts a box from "div" coords to another coordinate system.
  // Context may be "window", "page", "div", or "local"./null.
  
function fromCoordSystem(cmcoordscontext) {
    if (
context == "div") { return coords }
    var 
left coords.lefttop coords.top;
    
// First move into "page" coordinate system
    
if (context == "page") {
      
left -= pageScrollX();
      
top -= pageScrollY();
    } else if (
context == "local" || !context) {
      var 
localBox cm.display.sizer.getBoundingClientRect();
      
left += localBox.left;
      
top += localBox.top;
    }

    var 
lineSpaceBox cm.display.lineSpace.getBoundingClientRect();
    return {
leftleft lineSpaceBox.lefttoptop lineSpaceBox.top}
  }

  function 
charCoords(cmposcontextlineObjbias) {
    if (!
lineObj) { lineObj getLine(cm.docpos.line); }
    return 
intoCoordSystem(cmlineObjmeasureChar(cmlineObjpos.chbias), context)
  }

  
// Returns a box for a given cursor position, which may have an
  // 'other' property containing the position of the secondary cursor
  // on a bidi boundary.
  // A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
  // and after `char - 1` in writing order of `char - 1`
  // A cursor Pos(line, char, "after") is on the same visual line as `char`
  // and before `char` in writing order of `char`
  // Examples (upper-case letters are RTL, lower-case are LTR):
  //     Pos(0, 1, ...)
  //     before   after
  // ab     a|b     a|b
  // aB     a|B     aB|
  // Ab     |Ab     A|b
  // AB     B|A     B|A
  // Every position after the last character on a line is considered to stick
  // to the last character on the line.
  
function cursorCoords(cmposcontextlineObjpreparedMeasurevarHeight) {
    
lineObj lineObj || getLine(cm.docpos.line);
    if (!
preparedMeasure) { preparedMeasure prepareMeasureForLine(cmlineObj); }
    function 
get(chright) {
      var 
measureCharPrepared(cmpreparedMeasurechright "right" "left"varHeight);
      if (
right) { m.left m.right; } else { m.right m.left; }
      return 
intoCoordSystem(cmlineObjmcontext)
    }
    var 
order getOrder(lineObjcm.doc.direction), ch pos.chsticky pos.sticky;
    if (
ch >= lineObj.text.length) {
      
ch lineObj.text.length;
      
sticky "before";
    } else if (
ch <= 0) {
      
ch 0;
      
sticky "after";
    }
    if (!
order) { return get(sticky == "before" ch chsticky == "before") }

    function 
getBidi(chpartPosinvert) {
      var 
part order[partPos], right part.level == 1;
      return 
get(invert ch chright != invert)
    }
    var 
partPos getBidiPartAt(orderchsticky);
    var 
other bidiOther;
    var 
val getBidi(chpartPossticky == "before");
    if (
other != null) { val.other getBidi(chothersticky != "before"); }
    return 
val
  
}

  
// Used to cheaply estimate the coordinates for a position. Used for
  // intermediate scroll updates.
  
function estimateCoords(cmpos) {
    var 
left 0;
    
pos clipPos(cm.docpos);
    if (!
cm.options.lineWrapping) { left charWidth(cm.display) * pos.ch; }
    var 
lineObj getLine(cm.docpos.line);
    var 
top heightAtLine(lineObj) + paddingTop(cm.display);
    return {
leftleftrightlefttoptopbottomtop lineObj.height}
  }

  
// Positions returned by coordsChar contain some extra information.
  // xRel is the relative x position of the input coordinates compared
  // to the found position (so xRel > 0 means the coordinates are to
  // the right of the character position, for example). When outside
  // is true, that means the coordinates lie outside the line's
  // vertical range.
  
function PosWithInfo(linechstickyoutsidexRel) {
    var 
pos Pos(linechsticky);
    
pos.xRel xRel;
    if (
outside) { pos.outside outside; }
    return 
pos
  
}

  
// Compute the character position closest to the given coordinates.
  // Input must be lineSpace-local ("div" coordinate system).
  
function coordsChar(cmxy) {
    var 
doc cm.doc;
    
+= cm.display.viewOffset;
    if (
0) { return PosWithInfo(doc.first0null, -1, -1) }
    var 
lineN lineAtHeight(docy), last doc.first doc.size 1;
    if (
lineN last)
      { return 
PosWithInfo(doc.first doc.size 1getLine(doclast).text.lengthnull11) }
    if (
0) { 0; }

    var 
lineObj getLine(doclineN);
    for (;;) {
      var 
found coordsCharInner(cmlineObjlineNxy);
      var 
collapsed collapsedSpanAround(lineObjfound.ch + (found.xRel || found.outside 0));
      if (!
collapsed) { return found }
      var 
rangeEnd collapsed.find(1);
      if (
rangeEnd.line == lineN) { return rangeEnd }
      
lineObj getLine(doclineN rangeEnd.line);
    }
  }

  function 
wrappedLineExtent(cmlineObjpreparedMeasurey) {
    
-= widgetTopHeight(lineObj);
    var 
end lineObj.text.length;
    var 
begin findFirst(function (ch) { return measureCharPrepared(cmpreparedMeasurech 1).bottom <= y; }, end0);
    
end findFirst(function (ch) { return measureCharPrepared(cmpreparedMeasurech).top y; }, beginend);
    return {
beginbeginendend}
  }

  function 
wrappedLineExtentChar(cmlineObjpreparedMeasuretarget) {
    if (!
preparedMeasure) { preparedMeasure prepareMeasureForLine(cmlineObj); }
    var 
targetTop intoCoordSystem(cmlineObjmeasureCharPrepared(cmpreparedMeasuretarget), "line").top;
    return 
wrappedLineExtent(cmlineObjpreparedMeasuretargetTop)
  }

  
// Returns true if the given side of a box is after the given
  // coordinates, in top-to-bottom, left-to-right order.
  
function boxIsAfter(boxxyleft) {
    return 
box.bottom <= false box.top true : (left box.left box.right) > x
  
}

  function 
coordsCharInner(cmlineObjlineNoxy) {
    
// Move y into line-local coordinate space
    
-= heightAtLine(lineObj);
    var 
preparedMeasure prepareMeasureForLine(cmlineObj);
    
// When directly calling `measureCharPrepared`, we have to adjust
    // for the widgets at this line.
    
var widgetHeight widgetTopHeight(lineObj);
    var 
begin 0end lineObj.text.lengthltr true;

    var 
order getOrder(lineObjcm.doc.direction);
    
// If the line isn't plain left-to-right text, first figure out
    // which bidi section the coordinates fall into.
    
if (order) {
      var 
part = (cm.options.lineWrapping coordsBidiPartWrapped coordsBidiPart)
                   (
cmlineObjlineNopreparedMeasureorderxy);
      
ltr part.level != 1;
      
// The awkward -1 offsets are needed because findFirst (called
      // on these below) will treat its first bound as inclusive,
      // second as exclusive, but we want to actually address the
      // characters in the part's range
      
begin ltr part.from part.to 1;
      
end ltr part.to part.from 1;
    }

    
// A binary search to find the first character whose bounding box
    // starts after the coordinates. If we run across any whose box wrap
    // the coordinates, store that.
    
var chAround nullboxAround null;
    var 
ch findFirst(function (ch) {
      var 
box measureCharPrepared(cmpreparedMeasurech);
      
box.top += widgetHeightbox.bottom += widgetHeight;
      if (!
boxIsAfter(boxxyfalse)) { return false }
      if (
box.top <= && box.left <= x) {
        
chAround ch;
        
boxAround box;
      }
      return 
true
    
}, beginend);

    var 
baseXstickyoutside false;
    
// If a box around the coordinates was found, use that
    
if (boxAround) {
      
// Distinguish coordinates nearer to the left or right side of the box
      
var atLeft boxAround.left boxAround.right xatStart atLeft == ltr;
      
ch chAround + (atStart 1);
      
sticky atStart "after" "before";
      
baseX atLeft boxAround.left boxAround.right;
    } else {
      
// (Adjust for extended bound, if necessary.)
      
if (!ltr && (ch == end || ch == begin)) { ch++; }
      
// To determine which side to associate with, get the box to the
      // left of the character and compare it's vertical position to the
      // coordinates
      
sticky ch == "after" ch == lineObj.text.length "before" :
        (
measureCharPrepared(cmpreparedMeasurech - (ltr 0)).bottom widgetHeight <= y) == ltr ?
        
"after" "before";
      
// Now get accurate coordinates for this place, in order to get a
      // base X position
      
var coords cursorCoords(cmPos(lineNochsticky), "line"lineObjpreparedMeasure);
      
baseX coords.left;
      
outside coords.top ? ->= coords.bottom 0;
    }

    
ch skipExtendingChars(lineObj.textch1);
    return 
PosWithInfo(lineNochstickyoutsidebaseX)
  }

  function 
coordsBidiPart(cmlineObjlineNopreparedMeasureorderxy) {
    
// Bidi parts are sorted left-to-right, and in a non-line-wrapping
    // situation, we can take this ordering to correspond to the visual
    // ordering. This finds the first part whose end is after the given
    // coordinates.
    
var index findFirst(function (i) {
      var 
part order[i], ltr part.level != 1;
      return 
boxIsAfter(cursorCoords(cmPos(lineNoltr part.to part.fromltr "before" "after"),
                                     
"line"lineObjpreparedMeasure), xytrue)
    }, 
0order.length 1);
    var 
part order[index];
    
// If this isn't the first part, the part's start is also after
    // the coordinates, and the coordinates aren't on the same line as
    // that start, move one part back.
    
if (index 0) {
      var 
ltr part.level != 1;
      var 
start cursorCoords(cmPos(lineNoltr part.from part.toltr "after" "before"),
                               
"line"lineObjpreparedMeasure);
      if (
boxIsAfter(startxytrue) && start.top y)
        { 
part order[index 1]; }
    }
    return 
part
  
}

  function 
coordsBidiPartWrapped(cmlineObj_lineNopreparedMeasureorderxy) {
    
// In a wrapped line, rtl text on wrapping boundaries can do things
    // that don't correspond to the ordering in our `order` array at
    // all, so a binary search doesn't work, and we want to return a
    // part that only spans one line so that the binary search in
    // coordsCharInner is safe. As such, we first find the extent of the
    // wrapped line, and then do a flat search in which we discard any
    // spans that aren't on the line.
    
var ref wrappedLineExtent(cmlineObjpreparedMeasurey);
    var 
begin ref.begin;
    var 
end ref.end;
    if (/
s/.test(lineObj.text.charAt(end 1))) { end--; }
    var 
part nullclosestDist null;
    for (var 
0order.lengthi++) {
      var 
order[i];
      if (
p.from >= end || p.to <= begin) { continue }
      var 
ltr p.level != 1;
      var 
endX measureCharPrepared(cmpreparedMeasureltr Math.min(endp.to) - Math.max(beginp.from)).right;
      
// Weigh against spans ending before this, so that they are only
      // picked if nothing ends after
      
var dist endX endX 1e9 endX x;
      if (!
part || closestDist dist) {
        
part p;
        
closestDist dist;
      }
    }
    if (!
part) { part order[order.length 1]; }
    
// Clip the part to the wrapped line.
    
if (part.from begin) { part = {frombegintopart.tolevelpart.level}; }
    if (
part.to end) { part = {frompart.fromtoendlevelpart.level}; }
    return 
part
  
}

  var 
measureText;
  
// Compute the default text height.
  
function textHeight(display) {
    if (
display.cachedTextHeight != null) { return display.cachedTextHeight }
    if (
measureText == null) {
      
measureText elt("pre"null"CodeMirror-line-like");
      
// Measure a bunch of lines, for browsers that compute
      // fractional heights.
      
for (var 049; ++i) {
        
measureText.appendChild(document.createTextNode("x"));
        
measureText.appendChild(elt("br"));
      }
      
measureText.appendChild(document.createTextNode("x"));
    }
    
removeChildrenAndAdd(display.measuremeasureText);
    var 
height measureText.offsetHeight 50;
    if (
height 3) { display.cachedTextHeight height; }
    
removeChildren(display.measure);
    return 
height || 1
  
}

  
// Compute the default character width.
  
function charWidth(display) {
    if (
display.cachedCharWidth != null) { return display.cachedCharWidth }
    var 
anchor elt("span""xxxxxxxxxx");
    var 
pre elt("pre", [anchor], "CodeMirror-line-like");
    
removeChildrenAndAdd(display.measurepre);
    var 
rect anchor.getBoundingClientRect(), width = (rect.right rect.left) / 10;
    if (
width 2) { display.cachedCharWidth width; }
    return 
width || 10
  
}

  
// Do a bulk-read of the DOM positions and sizes needed to draw the
  // view, so that we don't interleave reading and writing to the DOM.
  
function getDimensions(cm) {
    var 
cm.displayleft = {}, width = {};
    var 
gutterLeft d.gutters.clientLeft;
    for (var 
d.gutters.firstChild0nn.nextSibling, ++i) {
      var 
id cm.display.gutterSpecs[i].className;
      
left[id] = n.offsetLeft n.clientLeft gutterLeft;
      
width[id] = n.clientWidth;
    }
    return {
fixedPoscompensateForHScroll(d),
            
gutterTotalWidthd.gutters.offsetWidth,
            
gutterLeftleft,
            
gutterWidthwidth,
            
wrapperWidthd.wrapper.clientWidth}
  }

  
// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
  // but using getBoundingClientRect to get a sub-pixel-accurate
  // result.
  
function compensateForHScroll(display) {
    return 
display.scroller.getBoundingClientRect().left display.sizer.getBoundingClientRect().left
  
}

  
// Returns a function that estimates the height of a line, to use as
  // first approximation until the line becomes visible (and is thus
  // properly measurable).
  
function estimateHeight(cm) {
    var 
th textHeight(cm.display), wrapping cm.options.lineWrapping;
    var 
perLine wrapping && Math.max(5cm.display.scroller.clientWidth charWidth(cm.display) - 3);
    return function (
line) {
      if (
lineIsHidden(cm.docline)) { return }

      var 
widgetsHeight 0;
      if (
line.widgets) { for (var 0line.widgets.lengthi++) {
        if (
line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
      } }

      if (
wrapping)
        { return 
widgetsHeight + (Math.ceil(line.text.length perLine) || 1) * th }
      else
        { return 
widgetsHeight th }
    }
  }

  function 
estimateLineHeights(cm) {
    var 
doc cm.docest estimateHeight(cm);
    
doc.iter(function (line) {
      var 
estHeight est(line);
      if (
estHeight != line.height) { updateLineHeight(lineestHeight); }
    });
  }

  
// Given a mouse event, find the corresponding position. If liberal
  // is false, it checks whether a gutter or scrollbar was clicked,
  // and returns null if it was. forRect is used by rectangular
  // selections, and tries to estimate a character position even for
  // coordinates beyond the right of the text.
  
function posFromMouse(cmeliberalforRect) {
    var 
display cm.display;
    if (!
liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }

    var 
xyspace display.lineSpace.getBoundingClientRect();
    
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
    
try { e.clientX space.lefte.clientY space.top; }
    catch (
e) { return null }
    var 
coords coordsChar(cmxy), line;
    if (
forRect && coords.xRel && (line getLine(cm.doccoords.line).text).length == coords.ch) {
      var 
colDiff countColumn(lineline.lengthcm.options.tabSize) - line.length;
      
coords Pos(coords.lineMath.max(0Math.round((paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
    }
    return 
coords
  
}

  
// Find the view element corresponding to a given line. Return null
  // when the line isn't visible.
  
function findViewIndex(cmn) {
    if (
>= cm.display.viewTo) { return null }
    
-= cm.display.viewFrom;
    if (
0) { return null }
    var 
view cm.display.view;
    for (var 
0view.lengthi++) {
      
-= view[i].size;
      if (
0) { return }
    }
  }

  
// Updates the display.view data structure for a given change to the
  // document. From and to are in pre-change coordinates. Lendiff is
  // the amount of lines added or subtracted by the change. This is
  // used for changes that span multiple lines, or change the way
  // lines are divided into visual lines. regLineChange (below)
  // registers single-line changes.
  
function regChange(cmfromtolendiff) {
    if (
from == null) { from cm.doc.first; }
    if (
to == null) { to cm.doc.first cm.doc.size; }
    if (!
lendiff) { lendiff 0; }

    var 
display cm.display;
    if (
lendiff && to display.viewTo &&
        (
display.updateLineNumbers == null || display.updateLineNumbers from))
      { 
display.updateLineNumbers from; }

    
cm.curOp.viewChanged true;

    if (
from >= display.viewTo) { // Change after
      
if (sawCollapsedSpans && visualLineNo(cm.docfrom) < display.viewTo)
        { 
resetView(cm); }
    } else if (
to <= display.viewFrom) { // Change before
      
if (sawCollapsedSpans && visualLineEndNo(cm.docto lendiff) > display.viewFrom) {
        
resetView(cm);
      } else {
        
display.viewFrom += lendiff;
        
display.viewTo += lendiff;
      }
    } else if (
from <= display.viewFrom && to >= display.viewTo) { // Full overlap
      
resetView(cm);
    } else if (
from <= display.viewFrom) { // Top overlap
      
var cut viewCuttingPoint(cmtoto lendiff1);
      if (
cut) {
        
display.view display.view.slice(cut.index);
        
display.viewFrom cut.lineN;
        
display.viewTo += lendiff;
      } else {
        
resetView(cm);
      }
    } else if (
to >= display.viewTo) { // Bottom overlap
      
var cut$viewCuttingPoint(cmfromfrom, -1);
      if (
cut$1) {
        
display.view display.view.slice(0cut$1.index);
        
display.viewTo cut$1.lineN;
      } else {
        
resetView(cm);
      }
    } else { 
// Gap in the middle
      
var cutTop viewCuttingPoint(cmfromfrom, -1);
      var 
cutBot viewCuttingPoint(cmtoto lendiff1);
      if (
cutTop && cutBot) {
        
display.view display.view.slice(0cutTop.index)
          .
concat(buildViewArray(cmcutTop.lineNcutBot.lineN))
          .
concat(display.view.slice(cutBot.index));
        
display.viewTo += lendiff;
      } else {
        
resetView(cm);
      }
    }

    var 
ext display.externalMeasured;
    if (
ext) {
      if (
to ext.lineN)
        { 
ext.lineN += lendiff; }
      else if (
from ext.lineN ext.size)
        { 
display.externalMeasured null; }
    }
  }

  
// Register a change to a single line. Type must be one of "text",
  // "gutter", "class", "widget"
  
function regLineChange(cmlinetype) {
    
cm.curOp.viewChanged true;
    var 
display cm.displayext cm.display.externalMeasured;
    if (
ext && line >= ext.lineN && line ext.lineN ext.size)
      { 
display.externalMeasured null; }

    if (
line display.viewFrom || line >= display.viewTo) { return }
    var 
lineView display.view[findViewIndex(cmline)];
    if (
lineView.node == null) { return }
    var 
arr lineView.changes || (lineView.changes = []);
    if (
indexOf(arrtype) == -1) { arr.push(type); }
  }

  
// Clear the view.
  
function resetView(cm) {
    
cm.display.viewFrom cm.display.viewTo cm.doc.first;
    
cm.display.view = [];
    
cm.display.viewOffset 0;
  }

  function 
viewCuttingPoint(cmoldNnewNdir) {
    var 
index findViewIndex(cmoldN), diffview cm.display.view;
    if (!
sawCollapsedSpans || newN == cm.doc.first cm.doc.size)
      { return {
indexindexlineNnewN} }
    var 
cm.display.viewFrom;
    for (var 
0indexi++)
      { 
+= view[i].size; }
    if (
!= oldN) {
      if (
dir 0) {
        if (
index == view.length 1) { return null }
        
diff = (view[index].size) - oldN;
        
index++;
      } else {
        
diff oldN;
      }
      
oldN += diffnewN += diff;
    }
    while (
visualLineNo(cm.docnewN) != newN) {
      if (
index == (dir view.length 1)) { return null }
      
newN += dir view[index - (dir 0)].size;
      
index += dir;
    }
    return {
indexindexlineNnewN}
  }

  
// Force the view to cover a given range, adding empty view element
  // or clipping off existing ones as needed.
  
function adjustView(cmfromto) {
    var 
display cm.displayview display.view;
    if (
view.length == || from >= display.viewTo || to <= display.viewFrom) {
      
display.view buildViewArray(cmfromto);
      
display.viewFrom from;
    } else {
      if (
display.viewFrom from)
        { 
display.view buildViewArray(cmfromdisplay.viewFrom).concat(display.view); }
      else if (
display.viewFrom from)
        { 
display.view display.view.slice(findViewIndex(cmfrom)); }
      
display.viewFrom from;
      if (
display.viewTo to)
        { 
display.view display.view.concat(buildViewArray(cmdisplay.viewToto)); }
      else if (
display.viewTo to)
        { 
display.view display.view.slice(0findViewIndex(cmto)); }
    }
    
display.viewTo to;
  }

  
// Count the number of lines in the view whose DOM representation is
  // out of date (or nonexistent).
  
function countDirtyView(cm) {
    var 
view cm.display.viewdirty 0;
    for (var 
0view.lengthi++) {
      var 
lineView view[i];
      if (!
lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
    }
    return 
dirty
  
}

  function 
updateSelection(cm) {
    
cm.display.input.showSelection(cm.display.input.prepareSelection());
  }

  function 
prepareSelection(cmprimary) {
    if ( 
primary === void 0 primary true;

    var 
doc cm.docresult = {};
    var 
curFragment result.cursors document.createDocumentFragment();
    var 
selFragment result.selection document.createDocumentFragment();

    for (var 
0doc.sel.ranges.lengthi++) {
      if (!
primary && == doc.sel.primIndex) { continue }
      var 
range doc.sel.ranges[i];
      if (
range.from().line >= cm.display.viewTo || range.to().line cm.display.viewFrom) { continue }
      var 
collapsed range.empty();
      if (
collapsed || cm.options.showCursorWhenSelecting)
        { 
drawSelectionCursor(cmrange.headcurFragment); }
      if (!
collapsed)
        { 
drawSelectionRange(cmrangeselFragment); }
    }
    return 
result
  
}

  
// Draws a cursor for the given range
  
function drawSelectionCursor(cmheadoutput) {
    var 
pos cursorCoords(cmhead"div"nullnull, !cm.options.singleCursorHeightPerLine);

    var 
cursor output.appendChild(elt("div""u00a0""CodeMirror-cursor"));
    
cursor.style.left pos.left "px";
    
cursor.style.top pos.top "px";
    
cursor.style.height Math.max(0pos.bottom pos.top) * cm.options.cursorHeight "px";

    if (
pos.other) {
      
// Secondary cursor, shown when on a 'jump' in bi-directional text
      
var otherCursor output.appendChild(elt("div""u00a0""CodeMirror-cursor CodeMirror-secondarycursor"));
      
otherCursor.style.display "";
      
otherCursor.style.left pos.other.left "px";
      
otherCursor.style.top pos.other.top "px";
      
otherCursor.style.height = (pos.other.bottom pos.other.top) * .85 "px";
    }
  }

  function 
cmpCoords(ab) { return a.top b.top || a.left b.left }

  
// Draws the given range as a highlighted selection
  
function drawSelectionRange(cmrangeoutput) {
    var 
display cm.displaydoc cm.doc;
    var 
fragment document.createDocumentFragment();
    var 
padding paddingH(cm.display), leftSide padding.left;
    var 
rightSide Math.max(display.sizerWidthdisplayWidth(cm) - display.sizer.offsetLeft) - padding.right;
    var 
docLTR doc.direction == "ltr";

    function 
add(lefttopwidthbottom) {
      if (
top 0) { top 0; }
      
top Math.round(top);
      
bottom Math.round(bottom);
      
fragment.appendChild(elt("div"null"CodeMirror-selected", ("position: absolute; left: " left "px;n                             top: " top "px; width: " + (width == null rightSide left width) + "px;n                             height: " + (bottom top) + "px")));
    }

    function 
drawForLine(linefromArgtoArg) {
      var 
lineObj getLine(docline);
      var 
lineLen lineObj.text.length;
      var 
startend;
      function 
coords(chbias) {
        return 
charCoords(cmPos(linech), "div"lineObjbias)
      }

      function 
wrapX(posdirside) {
        var 
extent wrappedLineExtentChar(cmlineObjnullpos);
        var 
prop = (dir == "ltr") == (side == "after") ? "left" "right";
        var 
ch side == "after" extent.begin extent.end - (/s/.test(lineObj.text.charAt(extent.end 1)) ? 1);
        return 
coords(chprop)[prop]
      }

      var 
order getOrder(lineObjdoc.direction);
      
iterateBidiSections(orderfromArg || 0toArg == null lineLen toArg, function (fromtodiri) {
        var 
ltr dir == "ltr";
        var 
fromPos coords(fromltr "left" "right");
        var 
toPos coords(to 1ltr "right" "left");

        var 
openStart fromArg == null && from == 0openEnd toArg == null && to == lineLen;
        var 
first == 0last = !order || == order.length 1;
        if (
toPos.top fromPos.top <= 3) { // Single line
          
var openLeft = (docLTR openStart openEnd) && first;
          var 
openRight = (docLTR openEnd openStart) && last;
          var 
left openLeft leftSide : (ltr fromPos toPos).left;
          var 
right openRight rightSide : (ltr toPos fromPos).right;
          
add(leftfromPos.topright leftfromPos.bottom);
        } else { 
// Multiple lines
          
var topLefttopRightbotLeftbotRight;
          if (
ltr) {
            
topLeft docLTR && openStart && first leftSide fromPos.left;
            
topRight docLTR rightSide wrapX(fromdir"before");
            
botLeft docLTR leftSide wrapX(todir"after");
            
botRight docLTR && openEnd && last rightSide toPos.right;
          } else {
            
topLeft = !docLTR leftSide wrapX(fromdir"before");
            
topRight = !docLTR && openStart && first rightSide fromPos.right;
            
botLeft = !docLTR && openEnd && last leftSide toPos.left;
            
botRight = !docLTR rightSide wrapX(todir"after");
          }
          
add(topLeftfromPos.toptopRight topLeftfromPos.bottom);
          if (
fromPos.bottom toPos.top) { add(leftSidefromPos.bottomnulltoPos.top); }
          
add(botLefttoPos.topbotRight botLefttoPos.bottom);
        }

        if (!
start || cmpCoords(fromPosstart) < 0) { start fromPos; }
        if (
cmpCoords(toPosstart) < 0) { start toPos; }
        if (!
end || cmpCoords(fromPosend) < 0) { end fromPos; }
        if (
cmpCoords(toPosend) < 0) { end toPos; }
      });
      return {
startstartendend}
    }

    var 
sFrom range.from(), sTo range.to();
    if (
sFrom.line == sTo.line) {
      
drawForLine(sFrom.linesFrom.chsTo.ch);
    } else {
      var 
fromLine getLine(docsFrom.line), toLine getLine(docsTo.line);
      var 
singleVLine visualLine(fromLine) == visualLine(toLine);
      var 
leftEnd drawForLine(sFrom.linesFrom.chsingleVLine fromLine.text.length null).end;
      var 
rightStart drawForLine(sTo.linesingleVLine nullsTo.ch).start;
      if (
singleVLine) {
        if (
leftEnd.top rightStart.top 2) {
          
add(leftEnd.rightleftEnd.topnullleftEnd.bottom);
          
add(leftSiderightStart.toprightStart.leftrightStart.bottom);
        } else {
          
add(leftEnd.rightleftEnd.toprightStart.left leftEnd.rightleftEnd.bottom);
        }
      }
      if (
leftEnd.bottom rightStart.top)
        { 
add(leftSideleftEnd.bottomnullrightStart.top); }
    }

    
output.appendChild(fragment);
  }

  
// Cursor-blinking
  
function restartBlink(cm) {
    if (!
cm.state.focused) { return }
    var 
display cm.display;
    
clearInterval(display.blinker);
    var 
on true;
    
display.cursorDiv.style.visibility "";
    if (
cm.options.cursorBlinkRate 0)
      { 
display.blinker setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" "hidden"; },
        
cm.options.cursorBlinkRate); }
    else if (
cm.options.cursorBlinkRate 0)
      { 
display.cursorDiv.style.visibility "hidden"; }
  }

  function 
ensureFocus(cm) {
    if (!
cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
  }

  function 
delayBlurEvent(cm) {
    
cm.state.delayingBlurEvent true;
    
setTimeout(function () { if (cm.state.delayingBlurEvent) {
      
cm.state.delayingBlurEvent false;
      
onBlur(cm);
    } }, 
100);
  }

  function 
onFocus(cme) {
    if (
cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent false; }

    if (
cm.options.readOnly == "nocursor") { return }
    if (!
cm.state.focused) {
      
signal(cm"focus"cme);
      
cm.state.focused true;
      
addClass(cm.display.wrapper"CodeMirror-focused");
      
// This test prevents this from firing when a context
      // menu is closed (since the input reset would kill the
      // select-all detection hack)
      
if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
        
cm.display.input.reset();
        if (
webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
      
}
      
cm.display.input.receivedFocus();
    }
    
restartBlink(cm);
  }
  function 
onBlur(cme) {
    if (
cm.state.delayingBlurEvent) { return }

    if (
cm.state.focused) {
      
signal(cm"blur"cme);
      
cm.state.focused false;
      
rmClass(cm.display.wrapper"CodeMirror-focused");
    }
    
clearInterval(cm.display.blinker);
    
setTimeout(function () { if (!cm.state.focused) { cm.display.shift false; } }, 150);
  }

  
// Read the actual heights of the rendered lines, and update their
  // stored heights to match.
  
function updateHeightsInViewport(cm) {
    var 
display cm.display;
    var 
prevBottom display.lineDiv.offsetTop;
    for (var 
0display.view.lengthi++) {
      var 
cur display.view[i], wrapping cm.options.lineWrapping;
      var 
height = (void 0), width 0;
      if (
cur.hidden) { continue }
      if (
ie && ie_version 8) {
        var 
bot cur.node.offsetTop cur.node.offsetHeight;
        
height bot prevBottom;
        
prevBottom bot;
      } else {
        var 
box cur.node.getBoundingClientRect();
        
height box.bottom box.top;
        
// Check that lines don't extend past the right of the current
        // editor width
        
if (!wrapping && cur.text.firstChild)
          { 
width cur.text.firstChild.getBoundingClientRect().right box.left 1; }
      }
      var 
diff cur.line.height height;
      if (
diff .005 || diff < -.005) {
        
updateLineHeight(cur.lineheight);
        
updateWidgetHeight(cur.line);
        if (
cur.rest) { for (var 0cur.rest.lengthj++)
          { 
updateWidgetHeight(cur.rest[j]); } }
      }
      if (
width cm.display.sizerWidth) {
        var 
chWidth Math.ceil(width charWidth(cm.display));
        if (
chWidth cm.display.maxLineLength) {
          
cm.display.maxLineLength chWidth;
          
cm.display.maxLine cur.line;
          
cm.display.maxLineChanged true;
        }
      }
    }
  }

  
// Read and store the height of line widgets associated with the
  // given line.
  
function updateWidgetHeight(line) {
    if (
line.widgets) { for (var 0line.widgets.length; ++i) {
      var 
line.widgets[i], parent w.node.parentNode;
      if (
parent) { w.height parent.offsetHeight; }
    } }
  }

  
// Compute the lines that are visible in a given viewport (defaults
  // the the current scroll position). viewport may contain top,
  // height, and ensure (see op.scrollToPos) properties.
  
function visibleLines(displaydocviewport) {
    var 
top viewport && viewport.top != null Math.max(0viewport.top) : display.scroller.scrollTop;
    
top Math.floor(top paddingTop(display));
    var 
bottom viewport && viewport.bottom != null viewport.bottom top display.wrapper.clientHeight;

    var 
from lineAtHeight(doctop), to lineAtHeight(docbottom);
    
// Ensure is a {from: {line, ch}, to: {line, ch}} object, and
    // forces those lines into the viewport (if possible).
    
if (viewport && viewport.ensure) {
      var 
ensureFrom viewport.ensure.from.lineensureTo viewport.ensure.to.line;
      if (
ensureFrom from) {
        
from ensureFrom;
        
to lineAtHeight(docheightAtLine(getLine(docensureFrom)) + display.wrapper.clientHeight);
      } else if (
Math.min(ensureTodoc.lastLine()) >= to) {
        
from lineAtHeight(docheightAtLine(getLine(docensureTo)) - display.wrapper.clientHeight);
        
to ensureTo;
      }
    }
    return {
fromfromtoMath.max(tofrom 1)}
  }

  
// SCROLLING THINGS INTO VIEW

  // If an editor sits on the top or bottom of the window, partially
  // scrolled out of view, this ensures that the cursor is visible.
  
function maybeScrollWindow(cmrect) {
    if (
signalDOMEvent(cm"scrollCursorIntoView")) { return }

    var 
display cm.displaybox display.sizer.getBoundingClientRect(), doScroll null;
    if (
rect.top box.top 0) { doScroll true; }
    else if (
rect.bottom box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll false; }
    if (
doScroll != null && !phantom) {
      var 
scrollNode elt("div""u200b"null, ("position: absolute;n                         top: " + (rect.top display.viewOffset paddingTop(cm.display)) + "px;n                         height: " + (rect.bottom rect.top scrollGap(cm) + display.barHeight) + "px;n                         left: " + (rect.left) + "px; width: " + (Math.max(2rect.right rect.left)) + "px;"));
      
cm.display.lineSpace.appendChild(scrollNode);
      
scrollNode.scrollIntoView(doScroll);
      
cm.display.lineSpace.removeChild(scrollNode);
    }
  }

  
// Scroll a given position into view (immediately), verifying that
  // it actually became visible (as line heights are accurately
  // measured, the position of something may 'drift' during drawing).
  
function scrollPosIntoView(cmposendmargin) {
    if (
margin == null) { margin 0; }
    var 
rect;
    if (!
cm.options.lineWrapping && pos == end) {
      
// Set pos and end to the cursor positions around the character pos sticks to
      // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
      // If pos == Pos(_, 0, "before"), pos and end are unchanged
      
pos pos.ch Pos(pos.linepos.sticky == "before" pos.ch pos.ch"after") : pos;
      
end pos.sticky == "before" Pos(pos.linepos.ch 1"before") : pos;
    }
    for (var 
limit 0limit 5limit++) {
      var 
changed false;
      var 
coords cursorCoords(cmpos);
      var 
endCoords = !end || end == pos coords cursorCoords(cmend);
      
rect = {leftMath.min(coords.leftendCoords.left),
              
topMath.min(coords.topendCoords.top) - margin,
              
rightMath.max(coords.leftendCoords.left),
              
bottomMath.max(coords.bottomendCoords.bottom) + margin};
      var 
scrollPos calculateScrollPos(cmrect);
      var 
startTop cm.doc.scrollTopstartLeft cm.doc.scrollLeft;
      if (
scrollPos.scrollTop != null) {
        
updateScrollTop(cmscrollPos.scrollTop);
        if (
Math.abs(cm.doc.scrollTop startTop) > 1) { changed true; }
      }
      if (
scrollPos.scrollLeft != null) {
        
setScrollLeft(cmscrollPos.scrollLeft);
        if (
Math.abs(cm.doc.scrollLeft startLeft) > 1) { changed true; }
      }
      if (!
changed) { break }
    }
    return 
rect
  
}

  
// Scroll a given set of coordinates into view (immediately).
  
function scrollIntoView(cmrect) {
    var 
scrollPos calculateScrollPos(cmrect);
    if (
scrollPos.scrollTop != null) { updateScrollTop(cmscrollPos.scrollTop); }
    if (
scrollPos.scrollLeft != null) { setScrollLeft(cmscrollPos.scrollLeft); }
  }

  
// Calculate a new scroll position needed to scroll the given
  // rectangle into view. Returns an object with scrollTop and
  // scrollLeft properties. When these are undefined, the
  // vertical/horizontal position does not need to be adjusted.
  
function calculateScrollPos(cmrect) {
    var 
display cm.displaysnapMargin textHeight(cm.display);
    if (
rect.top 0) { rect.top 0; }
    var 
screentop cm.curOp && cm.curOp.scrollTop != null cm.curOp.scrollTop display.scroller.scrollTop;
    var 
screen displayHeight(cm), result = {};
    if (
rect.bottom rect.top screen) { rect.bottom rect.top screen; }
    var 
docBottom cm.doc.height paddingVert(display);
    var 
atTop rect.top snapMarginatBottom rect.bottom docBottom snapMargin;
    if (
rect.top screentop) {
      
result.scrollTop atTop rect.top;
    } else if (
rect.bottom screentop screen) {
      var 
newTop Math.min(rect.top, (atBottom docBottom rect.bottom) - screen);
      if (
newTop != screentop) { result.scrollTop newTop; }
    }

    var 
screenleft cm.curOp && cm.curOp.scrollLeft != null cm.curOp.scrollLeft display.scroller.scrollLeft;
    var 
screenw displayWidth(cm) - (cm.options.fixedGutter display.gutters.offsetWidth 0);
    var 
tooWide rect.right rect.left screenw;
    if (
tooWide) { rect.right rect.left screenw; }
    if (
rect.left 10)
      { 
result.scrollLeft 0; }
    else if (
rect.left screenleft)
      { 
result.scrollLeft Math.max(0rect.left - (tooWide 10)); }
    else if (
rect.right screenw screenleft 3)
      { 
result.scrollLeft rect.right + (tooWide 10) - screenw; }
    return 
result
  
}

  
// Store a relative adjustment to the scroll position in the current
  // operation (to be applied when the operation finishes).
  
function addToScrollTop(cmtop) {
    if (
top == null) { return }
    
resolveScrollToPos(cm);
    
cm.curOp.scrollTop = (cm.curOp.scrollTop == null cm.doc.scrollTop cm.curOp.scrollTop) + top;
  }

  
// Make sure that at the end of the operation the current cursor is
  // shown.
  
function ensureCursorVisible(cm) {
    
resolveScrollToPos(cm);
    var 
cur cm.getCursor();
    
cm.curOp.scrollToPos = {fromcurtocurmargincm.options.cursorScrollMargin};
  }

  function 
scrollToCoords(cmxy) {
    if (
!= null || != null) { resolveScrollToPos(cm); }
    if (
!= null) { cm.curOp.scrollLeft x; }
    if (
!= null) { cm.curOp.scrollTop y; }
  }

  function 
scrollToRange(cmrange) {
    
resolveScrollToPos(cm);
    
cm.curOp.scrollToPos range;
  }

  
// When an operation has its scrollToPos property set, and another
  // scroll action is applied before the end of the operation, this
  // 'simulates' scrolling that position into view in a cheap way, so
  // that the effect of intermediate scroll commands is not ignored.
  
function resolveScrollToPos(cm) {
    var 
range cm.curOp.scrollToPos;
    if (
range) {
      
cm.curOp.scrollToPos null;
      var 
from estimateCoords(cmrange.from), to estimateCoords(cmrange.to);
      
scrollToCoordsRange(cmfromtorange.margin);
    }
  }

  function 
scrollToCoordsRange(cmfromtomargin) {
    var 
sPos calculateScrollPos(cm, {
      
leftMath.min(from.leftto.left),
      
topMath.min(from.topto.top) - margin,
      
rightMath.max(from.rightto.right),
      
bottomMath.max(from.bottomto.bottom) + margin
    
});
    
scrollToCoords(cmsPos.scrollLeftsPos.scrollTop);
  }

  
// Sync the scrollable area and scrollbars, ensure the viewport
  // covers the visible area.
  
function updateScrollTop(cmval) {
    if (
Math.abs(cm.doc.scrollTop val) < 2) { return }
    if (!
gecko) { updateDisplaySimple(cm, {topval}); }
    
setScrollTop(cmvaltrue);
    if (
gecko) { updateDisplaySimple(cm); }
    
startWorker(cm100);
  }

  function 
setScrollTop(cmvalforceScroll) {
    
val Math.max(0Math.min(cm.display.scroller.scrollHeight cm.display.scroller.clientHeightval));
    if (
cm.display.scroller.scrollTop == val && !forceScroll) { return }
    
cm.doc.scrollTop val;
    
cm.display.scrollbars.setScrollTop(val);
    if (
cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop val; }
  }

  
// Sync scroller and scrollbar, ensure the gutter elements are
  // aligned.
  
function setScrollLeft(cmvalisScrollerforceScroll) {
    
val Math.max(0Math.min(valcm.display.scroller.scrollWidth cm.display.scroller.clientWidth));
    if ((
isScroller val == cm.doc.scrollLeft Math.abs(cm.doc.scrollLeft val) < 2) && !forceScroll) { return }
    
cm.doc.scrollLeft val;
    
alignHorizontally(cm);
    if (
cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft val; }
    
cm.display.scrollbars.setScrollLeft(val);
  }

  
// SCROLLBARS

  // Prepare DOM reads needed to update the scrollbars. Done in one
  // shot to minimize update/measure roundtrips.
  
function measureForScrollbars(cm) {
    var 
cm.displaygutterW d.gutters.offsetWidth;
    var 
docH Math.round(cm.doc.height paddingVert(cm.display));
    return {
      
clientHeightd.scroller.clientHeight,
      
viewHeightd.wrapper.clientHeight,
      
scrollWidthd.scroller.scrollWidthclientWidthd.scroller.clientWidth,
      
viewWidthd.wrapper.clientWidth,
      
barLeftcm.options.fixedGutter gutterW 0,
      
docHeightdocH,
      
scrollHeightdocH scrollGap(cm) + d.barHeight,
      
nativeBarWidthd.nativeBarWidth,
      
gutterWidthgutterW
    
}
  }

  var 
NativeScrollbars = function(placescrollcm) {
    
this.cm cm;
    var 
vert this.vert elt("div", [elt("div"nullnull"min-width: 1px")], "CodeMirror-vscrollbar");
    var 
horiz this.horiz elt("div", [elt("div"nullnull"height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
    
vert.tabIndex horiz.tabIndex = -1;
    
place(vert); place(horiz);

    
on(vert"scroll", function () {
      if (
vert.clientHeight) { scroll(vert.scrollTop"vertical"); }
    });
    
on(horiz"scroll", function () {
      if (
horiz.clientWidth) { scroll(horiz.scrollLeft"horizontal"); }
    });

    
this.checkedZeroWidth false;
    
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
    
if (ie && ie_version 8) { this.horiz.style.minHeight this.vert.style.minWidth "18px"; }
  };

  
NativeScrollbars.prototype.update = function (measure) {
    var 
needsH measure.scrollWidth measure.clientWidth 1;
    var 
needsV measure.scrollHeight measure.clientHeight 1;
    var 
sWidth measure.nativeBarWidth;

    if (
needsV) {
      
this.vert.style.display "block";
      
this.vert.style.bottom needsH sWidth "px" "0";
      var 
totalHeight measure.viewHeight - (needsH sWidth 0);
      
// A bug in IE8 can cause this value to be negative, so guard it.
      
this.vert.firstChild.style.height =
        
Math.max(0measure.scrollHeight measure.clientHeight totalHeight) + "px";
    } else {
      
this.vert.style.display "";
      
this.vert.firstChild.style.height "0";
    }

    if (
needsH) {
      
this.horiz.style.display "block";
      
this.horiz.style.right needsV sWidth "px" "0";
      
this.horiz.style.left measure.barLeft "px";
      var 
totalWidth measure.viewWidth measure.barLeft - (needsV sWidth 0);
      
this.horiz.firstChild.style.width =
        
Math.max(0measure.scrollWidth measure.clientWidth totalWidth) + "px";
    } else {
      
this.horiz.style.display "";
      
this.horiz.firstChild.style.width "0";
    }

    if (!
this.checkedZeroWidth && measure.clientHeight 0) {
      if (
sWidth == 0) { this.zeroWidthHack(); }
      
this.checkedZeroWidth true;
    }

    return {
rightneedsV sWidth 0bottomneedsH sWidth 0}
  };

  
NativeScrollbars.prototype.setScrollLeft = function (pos) {
    if (
this.horiz.scrollLeft != pos) { this.horiz.scrollLeft pos; }
    if (
this.disableHoriz) { this.enableZeroWidthBar(this.horizthis.disableHoriz"horiz"); }
  };

  
NativeScrollbars.prototype.setScrollTop = function (pos) {
    if (
this.vert.scrollTop != pos) { this.vert.scrollTop pos; }
    if (
this.disableVert) { this.enableZeroWidthBar(this.vertthis.disableVert"vert"); }
  };

  
NativeScrollbars.prototype.zeroWidthHack = function () {
    var 
mac && !mac_geMountainLion "12px" "18px";
    
this.horiz.style.height this.vert.style.width w;
    
this.horiz.style.pointerEvents this.vert.style.pointerEvents "none";
    
this.disableHoriz = new Delayed;
    
this.disableVert = new Delayed;
  };

  
NativeScrollbars.prototype.enableZeroWidthBar = function (bardelaytype) {
    
bar.style.pointerEvents "auto";
    function 
maybeDisable() {
      
// To find out whether the scrollbar is still visible, we
      // check whether the element under the pixel in the bottom
      // right corner of the scrollbar box is the scrollbar box
      // itself (when the bar is still visible) or its filler child
      // (when the bar is hidden). If it is still visible, we keep
      // it enabled, if it's hidden, we disable pointer events.
      
var box bar.getBoundingClientRect();
      var 
elt type == "vert" document.elementFromPoint(box.right 1, (box.top box.bottom) / 2)
          : 
document.elementFromPoint((box.right box.left) / 2box.bottom 1);
      if (
elt != bar) { bar.style.pointerEvents "none"; }
      else { 
delay.set(1000maybeDisable); }
    }
    
delay.set(1000maybeDisable);
  };

  
NativeScrollbars.prototype.clear = function () {
    var 
parent this.horiz.parentNode;
    
parent.removeChild(this.horiz);
    
parent.removeChild(this.vert);
  };

  var 
NullScrollbars = function () {};

  
NullScrollbars.prototype.update = function () { return {bottom0right0} };
  
NullScrollbars.prototype.setScrollLeft = function () {};
  
NullScrollbars.prototype.setScrollTop = function () {};
  
NullScrollbars.prototype.clear = function () {};

  function 
updateScrollbars(cmmeasure) {
    if (!
measure) { measure measureForScrollbars(cm); }
    var 
startWidth cm.display.barWidthstartHeight cm.display.barHeight;
    
updateScrollbarsInner(cmmeasure);
    for (var 
0&& startWidth != cm.display.barWidth || startHeight != cm.display.barHeighti++) {
      if (
startWidth != cm.display.barWidth && cm.options.lineWrapping)
        { 
updateHeightsInViewport(cm); }
      
updateScrollbarsInner(cmmeasureForScrollbars(cm));
      
startWidth cm.display.barWidthstartHeight cm.display.barHeight;
    }
  }

  
// Re-synchronize the fake scrollbars with the actual size of the
  // content.
  
function updateScrollbarsInner(cmmeasure) {
    var 
cm.display;
    var 
sizes d.scrollbars.update(measure);

    
d.sizer.style.paddingRight = (d.barWidth sizes.right) + "px";
    
d.sizer.style.paddingBottom = (d.barHeight sizes.bottom) + "px";
    
d.heightForcer.style.borderBottom sizes.bottom "px solid transparent";

    if (
sizes.right && sizes.bottom) {
      
d.scrollbarFiller.style.display "block";
      
d.scrollbarFiller.style.height sizes.bottom "px";
      
d.scrollbarFiller.style.width sizes.right "px";
    } else { 
d.scrollbarFiller.style.display ""; }
    if (
sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
      
d.gutterFiller.style.display "block";
      
d.gutterFiller.style.height sizes.bottom "px";
      
d.gutterFiller.style.width measure.gutterWidth "px";
    } else { 
d.gutterFiller.style.display ""; }
  }

  var 
scrollbarModel = {"native"NativeScrollbars"null"NullScrollbars};

  function 
initScrollbars(cm) {
    if (
cm.display.scrollbars) {
      
cm.display.scrollbars.clear();
      if (
cm.display.scrollbars.addClass)
        { 
rmClass(cm.display.wrappercm.display.scrollbars.addClass); }
    }

    
cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
      
cm.display.wrapper.insertBefore(nodecm.display.scrollbarFiller);
      
// Prevent clicks in the scrollbars from killing focus
      
on(node"mousedown", function () {
        if (
cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
      });
      
node.setAttribute("cm-not-content""true");
    }, function (
posaxis) {
      if (
axis == "horizontal") { setScrollLeft(cmpos); }
      else { 
updateScrollTop(cmpos); }
    }, 
cm);
    if (
cm.display.scrollbars.addClass)
      { 
addClass(cm.display.wrappercm.display.scrollbars.addClass); }
  }

  
// Operations are used to wrap a series of changes to the editor
  // state in such a way that each change won't have to update the
  // cursor and display (which would be awkward, slow, and
  // error-prone). Instead, display updates are batched and then all
  // combined and executed at once.

  
var nextOpId 0;
  
// Start a new operation.
  
function startOperation(cm) {
    
cm.curOp = {
      
cmcm,
      
viewChangedfalse,      // Flag that indicates that lines might need to be redrawn
      
startHeightcm.doc.height// Used to detect need to update scrollbar
      
forceUpdatefalse,      // Used to force a redraw
      
updateInput0,       // Whether to reset the input textarea
      
typingfalse,           // Whether this reset should be careful to leave existing text (for compositing)
      
changeObjsnull,        // Accumulated changes, for firing change events
      
cursorActivityHandlersnull// Set of handlers to fire cursorActivity on
      
cursorActivityCalled0// Tracks which cursorActivity handlers have been called already
      
selectionChangedfalse// Whether the selection needs to be redrawn
      
updateMaxLinefalse,    // Set when the widest line needs to be determined anew
      
scrollLeftnullscrollTopnull// Intermediate scroll position, not pushed to DOM yet
      
scrollToPosnull,       // Used to scroll to a specific position
      
focusfalse,
      
id: ++nextOpId           // Unique ID
    
};
    
pushOperation(cm.curOp);
  }

  
// Finish an operation, updating the display and signalling delayed events
  
function endOperation(cm) {
    var 
op cm.curOp;
    if (
op) { finishOperation(op, function (group) {
      for (var 
0group.ops.lengthi++)
        { 
group.ops[i].cm.curOp null; }
      
endOperations(group);
    }); }
  }

  
// The DOM updates done when an operation finishes are batched so
  // that the minimum number of relayouts are required.
  
function endOperations(group) {
    var 
ops group.ops;
    for (var 
0ops.lengthi++) // Read DOM
      
endOperation_R1(ops[i]); }
    for (var 
i$0i$ops.lengthi$1++) // Write DOM (maybe)
      
endOperation_W1(ops[i$1]); }
    for (var 
i$0i$ops.lengthi$2++) // Read DOM
      
endOperation_R2(ops[i$2]); }
    for (var 
i$0i$ops.lengthi$3++) // Write DOM (maybe)
      
endOperation_W2(ops[i$3]); }
    for (var 
i$0i$ops.lengthi$4++) // Read DOM
      
endOperation_finish(ops[i$4]); }
  }

  function 
endOperation_R1(op) {
    var 
cm op.cmdisplay cm.display;
    
maybeClipScrollbars(cm);
    if (
op.updateMaxLine) { findMaxLine(cm); }

    
op.mustUpdate op.viewChanged || op.forceUpdate || op.scrollTop != null ||
      
op.scrollToPos && (op.scrollToPos.from.line display.viewFrom ||
                         
op.scrollToPos.to.line >= display.viewTo) ||
      
display.maxLineChanged && cm.options.lineWrapping;
    
op.update op.mustUpdate &&
      new 
DisplayUpdate(cmop.mustUpdate && {topop.scrollTopensureop.scrollToPos}, op.forceUpdate);
  }

  function 
endOperation_W1(op) {
    
op.updatedDisplay op.mustUpdate && updateDisplayIfNeeded(op.cmop.update);
  }

  function 
endOperation_R2(op) {
    var 
cm op.cmdisplay cm.display;
    if (
op.updatedDisplay) { updateHeightsInViewport(cm); }

    
op.barMeasure measureForScrollbars(cm);

    
// If the max line changed since it was last measured, measure it,
    // and ensure the document's width matches it.
    // updateDisplay_W2 will use these properties to do the actual resizing
    
if (display.maxLineChanged && !cm.options.lineWrapping) {
      
op.adjustWidthTo measureChar(cmdisplay.maxLinedisplay.maxLine.text.length).left 3;
      
cm.display.sizerWidth op.adjustWidthTo;
      
op.barMeasure.scrollWidth =
        
Math.max(display.scroller.clientWidthdisplay.sizer.offsetLeft op.adjustWidthTo scrollGap(cm) + cm.display.barWidth);
      
op.maxScrollLeft Math.max(0display.sizer.offsetLeft op.adjustWidthTo displayWidth(cm));
    }

    if (
op.updatedDisplay || op.selectionChanged)
      { 
op.preparedSelection display.input.prepareSelection(); }
  }

  function 
endOperation_W2(op) {
    var 
cm op.cm;

    if (
op.adjustWidthTo != null) {
      
cm.display.sizer.style.minWidth op.adjustWidthTo "px";
      if (
op.maxScrollLeft cm.doc.scrollLeft)
        { 
setScrollLeft(cmMath.min(cm.display.scroller.scrollLeftop.maxScrollLeft), true); }
      
cm.display.maxLineChanged false;
    }

    var 
takeFocus op.focus && op.focus == activeElt();
    if (
op.preparedSelection)
      { 
cm.display.input.showSelection(op.preparedSelectiontakeFocus); }
    if (
op.updatedDisplay || op.startHeight != cm.doc.height)
      { 
updateScrollbars(cmop.barMeasure); }
    if (
op.updatedDisplay)
      { 
setDocumentHeight(cmop.barMeasure); }

    if (
op.selectionChanged) { restartBlink(cm); }

    if (
cm.state.focused && op.updateInput)
      { 
cm.display.input.reset(op.typing); }
    if (
takeFocus) { ensureFocus(op.cm); }
  }

  function 
endOperation_finish(op) {
    var 
cm op.cmdisplay cm.displaydoc cm.doc;

    if (
op.updatedDisplay) { postUpdateDisplay(cmop.update); }

    
// Abort mouse wheel delta measurement, when scrolling explicitly
    
if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
      { 
display.wheelStartX display.wheelStartY null; }

    
// Propagate the scroll position to the actual DOM scroller
    
if (op.scrollTop != null) { setScrollTop(cmop.scrollTopop.forceScroll); }

    if (
op.scrollLeft != null) { setScrollLeft(cmop.scrollLefttruetrue); }
    
// If we need to scroll a specific position into view, do so.
    
if (op.scrollToPos) {
      var 
rect scrollPosIntoView(cmclipPos(docop.scrollToPos.from),
                                   
clipPos(docop.scrollToPos.to), op.scrollToPos.margin);
      
maybeScrollWindow(cmrect);
    }

    
// Fire events for markers that are hidden/unidden by editing or
    // undoing
    
var hidden op.maybeHiddenMarkersunhidden op.maybeUnhiddenMarkers;
    if (
hidden) { for (var 0hidden.length; ++i)
      { if (!
hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
    if (
unhidden) { for (var i$0i$unhidden.length; ++i$1)
      { if (
unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }

    if (
display.wrapper.offsetHeight)
      { 
doc.scrollTop cm.display.scroller.scrollTop; }

    
// Fire change events, and delayed event handlers
    
if (op.changeObjs)
      { 
signal(cm"changes"cmop.changeObjs); }
    if (
op.update)
      { 
op.update.finish(); }
  }

  
// Run the given function in an operation
  
function runInOp(cmf) {
    if (
cm.curOp) { return f() }
    
startOperation(cm);
    try { return 
f() }
    finally { 
endOperation(cm); }
  }
  
// Wraps a function in an operation. Returns the wrapped function.
  
function operation(cmf) {
    return function() {
      if (
cm.curOp) { return f.apply(cmarguments) }
      
startOperation(cm);
      try { return 
f.apply(cmarguments) }
      finally { 
endOperation(cm); }
    }
  }
  
// Used to add methods to editor and doc instances, wrapping them in
  // operations.
  
function methodOp(f) {
    return function() {
      if (
this.curOp) { return f.apply(thisarguments) }
      
startOperation(this);
      try { return 
f.apply(thisarguments) }
      finally { 
endOperation(this); }
    }
  }
  function 
docMethodOp(f) {
    return function() {
      var 
cm this.cm;
      if (!
cm || cm.curOp) { return f.apply(thisarguments) }
      
startOperation(cm);
      try { return 
f.apply(thisarguments) }
      finally { 
endOperation(cm); }
    }
  }

  
// HIGHLIGHT WORKER

  
function startWorker(cmtime) {
    if (
cm.doc.highlightFrontier cm.display.viewTo)
      { 
cm.state.highlight.set(timebind(highlightWorkercm)); }
  }

  function 
highlightWorker(cm) {
    var 
doc cm.doc;
    if (
doc.highlightFrontier >= cm.display.viewTo) { return }
    var 
end = +new Date cm.options.workTime;
    var 
context getContextBefore(cmdoc.highlightFrontier);
    var 
changedLines = [];

    
doc.iter(context.lineMath.min(doc.first doc.sizecm.display.viewTo 500), function (line) {
      if (
context.line >= cm.display.viewFrom) { // Visible
        
var oldStyles line.styles;
        var 
resetState line.text.length cm.options.maxHighlightLength copyState(doc.modecontext.state) : null;
        var 
highlighted highlightLine(cmlinecontexttrue);
        if (
resetState) { context.state resetState; }
        
line.styles highlighted.styles;
        var 
oldCls line.styleClassesnewCls highlighted.classes;
        if (
newCls) { line.styleClasses newCls; }
        else if (
oldCls) { line.styleClasses null; }
        var 
ischange = !oldStyles || oldStyles.length != line.styles.length ||
          
oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
        for (var 
0; !ischange && oldStyles.length; ++i) { ischange oldStyles[i] != line.styles[i]; }
        if (
ischange) { changedLines.push(context.line); }
        
line.stateAfter context.save();
        
context.nextLine();
      } else {
        if (
line.text.length <= cm.options.maxHighlightLength)
          { 
processLine(cmline.textcontext); }
        
line.stateAfter context.line == context.save() : null;
        
context.nextLine();
      }
      if (+new 
Date end) {
        
startWorker(cmcm.options.workDelay);
        return 
true
      
}
    });
    
doc.highlightFrontier context.line;
    
doc.modeFrontier Math.max(doc.modeFrontiercontext.line);
    if (
changedLines.length) { runInOp(cm, function () {
      for (var 
0changedLines.lengthi++)
        { 
regLineChange(cmchangedLines[i], "text"); }
    }); }
  }

  
// DISPLAY DRAWING

  
var DisplayUpdate = function(cmviewportforce) {
    var 
display cm.display;

    
this.viewport viewport;
    
// Store some values that we'll need later (but don't want to force a relayout for)
    
this.visible visibleLines(displaycm.docviewport);
    
this.editorIsHidden = !display.wrapper.offsetWidth;
    
this.wrapperHeight display.wrapper.clientHeight;
    
this.wrapperWidth display.wrapper.clientWidth;
    
this.oldDisplayWidth displayWidth(cm);
    
this.force force;
    
this.dims getDimensions(cm);
    
this.events = [];
  };

  
DisplayUpdate.prototype.signal = function (emittertype) {
    if (
hasHandler(emittertype))
      { 
this.events.push(arguments); }
  };
  
DisplayUpdate.prototype.finish = function () {
    for (var 
0this.events.lengthi++)
      { 
signal.apply(nullthis.events[i]); }
  };

  function 
maybeClipScrollbars(cm) {
    var 
display cm.display;
    if (!
display.scrollbarsClipped && display.scroller.offsetWidth) {
      
display.nativeBarWidth display.scroller.offsetWidth display.scroller.clientWidth;
      
display.heightForcer.style.height scrollGap(cm) + "px";
      
display.sizer.style.marginBottom = -display.nativeBarWidth "px";
      
display.sizer.style.borderRightWidth scrollGap(cm) + "px";
      
display.scrollbarsClipped true;
    }
  }

  function 
selectionSnapshot(cm) {
    if (
cm.hasFocus()) { return null }
    var 
active activeElt();
    if (!
active || !contains(cm.display.lineDivactive)) { return null }
    var 
result = {activeEltactive};
    if (
window.getSelection) {
      var 
sel window.getSelection();
      if (
sel.anchorNode && sel.extend && contains(cm.display.lineDivsel.anchorNode)) {
        
result.anchorNode sel.anchorNode;
        
result.anchorOffset sel.anchorOffset;
        
result.focusNode sel.focusNode;
        
result.focusOffset sel.focusOffset;
      }
    }
    return 
result
  
}

  function 
restoreSelection(snapshot) {
    if (!
snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
    
snapshot.activeElt.focus();
    if (!/^(
INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) &&
        
snapshot.anchorNode && contains(document.bodysnapshot.anchorNode) && contains(document.bodysnapshot.focusNode)) {
      var 
sel window.getSelection(), range document.createRange();
      
range.setEnd(snapshot.anchorNodesnapshot.anchorOffset);
      
range.collapse(false);
      
sel.removeAllRanges();
      
sel.addRange(range);
      
sel.extend(snapshot.focusNodesnapshot.focusOffset);
    }
  }

  
// Does the actual updating of the line display. Bails out
  // (returning false) when there is nothing to be done and forced is
  // false.
  
function updateDisplayIfNeeded(cmupdate) {
    var 
display cm.displaydoc cm.doc;

    if (
update.editorIsHidden) {
      
resetView(cm);
      return 
false
    
}

    
// Bail out if the visible area is already rendered and nothing changed.
    
if (!update.force &&
        
update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
        (
display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
        
display.renderedView == display.view && countDirtyView(cm) == 0)
      { return 
false }

    if (
maybeUpdateLineNumberWidth(cm)) {
      
resetView(cm);
      
update.dims getDimensions(cm);
    }

    
// Compute a suitable new viewport (from & to)
    
var end doc.first doc.size;
    var 
from Math.max(update.visible.from cm.options.viewportMargindoc.first);
    var 
to Math.min(endupdate.visible.to cm.options.viewportMargin);
    if (
display.viewFrom from && from display.viewFrom 20) { from Math.max(doc.firstdisplay.viewFrom); }
    if (
display.viewTo to && display.viewTo to 20) { to Math.min(enddisplay.viewTo); }
    if (
sawCollapsedSpans) {
      
from visualLineNo(cm.docfrom);
      
to visualLineEndNo(cm.docto);
    }

    var 
different from != display.viewFrom || to != display.viewTo ||
      
display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
    
adjustView(cmfromto);

    
display.viewOffset heightAtLine(getLine(cm.docdisplay.viewFrom));
    
// Position the mover div to align with the current scroll position
    
cm.display.mover.style.top display.viewOffset "px";

    var 
toUpdate countDirtyView(cm);
    if (!
different && toUpdate == && !update.force && display.renderedView == display.view &&
        (
display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
      { return 
false }

    
// For big changes, we hide the enclosing element during the
    // update, since that speeds up the operations on most browsers.
    
var selSnapshot selectionSnapshot(cm);
    if (
toUpdate 4) { display.lineDiv.style.display "none"; }
    
patchDisplay(cmdisplay.updateLineNumbersupdate.dims);
    if (
toUpdate 4) { display.lineDiv.style.display ""; }
    
display.renderedView display.view;
    
// There might have been a widget with a focused element that got
    // hidden or updated, if so re-focus it.
    
restoreSelection(selSnapshot);

    
// Prevent selection and cursors from interfering with the scroll
    // width and height.
    
removeChildren(display.cursorDiv);
    
removeChildren(display.selectionDiv);
    
display.gutters.style.height display.sizer.style.minHeight 0;

    if (
different) {
      
display.lastWrapHeight update.wrapperHeight;
      
display.lastWrapWidth update.wrapperWidth;
      
startWorker(cm400);
    }

    
display.updateLineNumbers null;

    return 
true
  
}

  function 
postUpdateDisplay(cmupdate) {
    var 
viewport update.viewport;

    for (var 
first true;; first false) {
      if (!
first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
        
// Clip forced viewport to actual scrollable area.
        
if (viewport && viewport.top != null)
          { 
viewport = {topMath.min(cm.doc.height paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
        
// Updated line heights might result in the drawn area not
        // actually covering the viewport. Keep looping until it does.
        
update.visible visibleLines(cm.displaycm.docviewport);
        if (
update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
          { break }
      } else if (
first) {
        
update.visible visibleLines(cm.displaycm.docviewport);
      }
      if (!
updateDisplayIfNeeded(cmupdate)) { break }
      
updateHeightsInViewport(cm);
      var 
barMeasure measureForScrollbars(cm);
      
updateSelection(cm);
      
updateScrollbars(cmbarMeasure);
      
setDocumentHeight(cmbarMeasure);
      
update.force false;
    }

    
update.signal(cm"update"cm);
    if (
cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
      
update.signal(cm"viewportChange"cmcm.display.viewFromcm.display.viewTo);
      
cm.display.reportedViewFrom cm.display.viewFromcm.display.reportedViewTo cm.display.viewTo;
    }
  }

  function 
updateDisplaySimple(cmviewport) {
    var 
update = new DisplayUpdate(cmviewport);
    if (
updateDisplayIfNeeded(cmupdate)) {
      
updateHeightsInViewport(cm);
      
postUpdateDisplay(cmupdate);
      var 
barMeasure measureForScrollbars(cm);
      
updateSelection(cm);
      
updateScrollbars(cmbarMeasure);
      
setDocumentHeight(cmbarMeasure);
      
update.finish();
    }
  }

  
// Sync the actual display DOM structure with display.view, removing
  // nodes for lines that are no longer in view, and creating the ones
  // that are not there yet, and updating the ones that are out of
  // date.
  
function patchDisplay(cmupdateNumbersFromdims) {
    var 
display cm.displaylineNumbers cm.options.lineNumbers;
    var 
container display.lineDivcur container.firstChild;

    function 
rm(node) {
      var 
next node.nextSibling;
      
// Works around a throw-scroll bug in OS X Webkit
      
if (webkit && mac && cm.display.currentWheelTarget == node)
        { 
node.style.display "none"; }
      else
        { 
node.parentNode.removeChild(node); }
      return 
next
    
}

    var 
view display.viewlineN display.viewFrom;
    
// Loop over the elements in the view, syncing cur (the DOM nodes
    // in display.lineDiv) with the view as we go.
    
for (var 0view.lengthi++) {
      var 
lineView view[i];
      if (
lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
        
var node buildLineElement(cmlineViewlineNdims);
        
container.insertBefore(nodecur);
      } else { 
// Already drawn
        
while (cur != lineView.node) { cur rm(cur); }
        var 
updateNumber lineNumbers && updateNumbersFrom != null &&
          
updateNumbersFrom <= lineN && lineView.lineNumber;
        if (
lineView.changes) {
          if (
indexOf(lineView.changes"gutter") > -1) { updateNumber false; }
          
updateLineForChanges(cmlineViewlineNdims);
        }
        if (
updateNumber) {
          
removeChildren(lineView.lineNumber);
          
lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.optionslineN)));
        }
        
cur lineView.node.nextSibling;
      }
      
lineN += lineView.size;
    }
    while (
cur) { cur rm(cur); }
  }

  function 
updateGutterSpace(display) {
    var 
width display.gutters.offsetWidth;
    
display.sizer.style.marginLeft width "px";
  }

  function 
setDocumentHeight(cmmeasure) {
    
cm.display.sizer.style.minHeight measure.docHeight "px";
    
cm.display.heightForcer.style.top measure.docHeight "px";
    
cm.display.gutters.style.height = (measure.docHeight cm.display.barHeight scrollGap(cm)) + "px";
  }

  
// Re-align line numbers and gutter marks to compensate for
  // horizontal scrolling.
  
function alignHorizontally(cm) {
    var 
display cm.displayview display.view;
    if (!
display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
    var 
comp compensateForHScroll(display) - display.scroller.scrollLeft cm.doc.scrollLeft;
    var 
gutterW display.gutters.offsetWidthleft comp "px";
    for (var 
0view.lengthi++) { if (!view[i].hidden) {
      if (
cm.options.fixedGutter) {
        if (
view[i].gutter)
          { 
view[i].gutter.style.left left; }
        if (
view[i].gutterBackground)
          { 
view[i].gutterBackground.style.left left; }
      }
      var 
align view[i].alignable;
      if (
align) { for (var 0align.lengthj++)
        { 
align[j].style.left left; } }
    } }
    if (
cm.options.fixedGutter)
      { 
display.gutters.style.left = (comp gutterW) + "px"; }
  }

  
// Used to ensure that the line number gutter is still the right
  // size for the current document size. Returns true when an update
  // is needed.
  
function maybeUpdateLineNumberWidth(cm) {
    if (!
cm.options.lineNumbers) { return false }
    var 
doc cm.doclast lineNumberFor(cm.optionsdoc.first doc.size 1), display cm.display;
    if (
last.length != display.lineNumChars) {
      var 
test display.measure.appendChild(elt("div", [elt("div"last)],
                                                 
"CodeMirror-linenumber CodeMirror-gutter-elt"));
      var 
innerW test.firstChild.offsetWidthpadding test.offsetWidth innerW;
      
display.lineGutter.style.width "";
      
display.lineNumInnerWidth Math.max(innerWdisplay.lineGutter.offsetWidth padding) + 1;
      
display.lineNumWidth display.lineNumInnerWidth padding;
      
display.lineNumChars display.lineNumInnerWidth last.length : -1;
      
display.lineGutter.style.width display.lineNumWidth "px";
      
updateGutterSpace(cm.display);
      return 
true
    
}
    return 
false
  
}

  function 
getGutters(gutterslineNumbers) {
    var 
result = [], sawLineNumbers false;
    for (var 
0gutters.lengthi++) {
      var 
name gutters[i], style null;
      if (
typeof name != "string") { style name.stylename name.className; }
      if (
name == "CodeMirror-linenumbers") {
        if (!
lineNumbers) { continue }
        else { 
sawLineNumbers true; }
      }
      
result.push({classNamenamestylestyle});
    }
    if (
lineNumbers && !sawLineNumbers) { result.push({className"CodeMirror-linenumbers"stylenull}); }
    return 
result
  
}

  
// Rebuild the gutter elements, ensure the margin to the left of the
  // code matches their width.
  
function renderGutters(display) {
    var 
gutters display.guttersspecs display.gutterSpecs;
    
removeChildren(gutters);
    
display.lineGutter null;
    for (var 
0specs.length; ++i) {
      var 
ref specs[i];
      var 
className ref.className;
      var 
style ref.style;
      var 
gElt gutters.appendChild(elt("div"null"CodeMirror-gutter " className));
      if (
style) { gElt.style.cssText style; }
      if (
className == "CodeMirror-linenumbers") {
        
display.lineGutter gElt;
        
gElt.style.width = (display.lineNumWidth || 1) + "px";
      }
    }
    
gutters.style.display specs.length "" "none";
    
updateGutterSpace(display);
  }

  function 
updateGutters(cm) {
    
renderGutters(cm.display);
    
regChange(cm);
    
alignHorizontally(cm);
  }

  
// The display handles the DOM integration, both for input reading
  // and content drawing. It holds references to DOM nodes and
  // display-related state.

  
function Display(placedocinputoptions) {
    var 
this;
    
this.input input;

    
// Covers bottom-right square when both scrollbars are present.
    
d.scrollbarFiller elt("div"null"CodeMirror-scrollbar-filler");
    
d.scrollbarFiller.setAttribute("cm-not-content""true");
    
// Covers bottom of gutter when coverGutterNextToScrollbar is on
    // and h scrollbar is present.
    
d.gutterFiller elt("div"null"CodeMirror-gutter-filler");
    
d.gutterFiller.setAttribute("cm-not-content""true");
    
// Will contain the actual code, positioned to cover the viewport.
    
d.lineDiv eltP("div"null"CodeMirror-code");
    
// Elements are added to these to represent selection and cursors.
    
d.selectionDiv elt("div"nullnull"position: relative; z-index: 1");
    
d.cursorDiv elt("div"null"CodeMirror-cursors");
    
// A visibility: hidden element used to find the size of things.
    
d.measure elt("div"null"CodeMirror-measure");
    
// When lines outside of the viewport are measured, they are drawn in this.
    
d.lineMeasure elt("div"null"CodeMirror-measure");
    
// Wraps everything that needs to exist inside the vertically-padded coordinate system
    
d.lineSpace eltP("div", [d.measured.lineMeasured.selectionDivd.cursorDivd.lineDiv],
                      
null"position: relative; outline: none");
    var 
lines eltP("div", [d.lineSpace], "CodeMirror-lines");
    
// Moved around its parent to cover visible view.
    
d.mover elt("div", [lines], null"position: relative");
    
// Set to the height of the document, allowing scrolling.
    
d.sizer elt("div", [d.mover], "CodeMirror-sizer");
    
d.sizerWidth null;
    
// Behavior of elts with overflow: auto and padding is
    // inconsistent across browsers. This is used to ensure the
    // scrollable area is big enough.
    
d.heightForcer elt("div"nullnull"position: absolute; height: " scrollerGap "px; width: 1px;");
    
// Will contain the gutters, if any.
    
d.gutters elt("div"null"CodeMirror-gutters");
    
d.lineGutter null;
    
// Actual scrollable element.
    
d.scroller elt("div", [d.sizerd.heightForcerd.gutters], "CodeMirror-scroll");
    
d.scroller.setAttribute("tabIndex""-1");
    
// The element in which the editor lives.
    
d.wrapper elt("div", [d.scrollbarFillerd.gutterFillerd.scroller], "CodeMirror");

    
// Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
    
if (ie && ie_version 8) { d.gutters.style.zIndex = -1d.scroller.style.paddingRight 0; }
    if (!
webkit && !(gecko && mobile)) { d.scroller.draggable true; }

    if (
place) {
      if (
place.appendChild) { place.appendChild(d.wrapper); }
      else { 
place(d.wrapper); }
    }

    
// Current rendered range (may be bigger than the view window).
    
d.viewFrom d.viewTo doc.first;
    
d.reportedViewFrom d.reportedViewTo doc.first;
    
// Information about the rendered lines.
    
d.view = [];
    
d.renderedView null;
    
// Holds info about a single rendered line when it was rendered
    // for measurement, while not in view.
    
d.externalMeasured null;
    
// Empty space (in pixels) above the view
    
d.viewOffset 0;
    
d.lastWrapHeight d.lastWrapWidth 0;
    
d.updateLineNumbers null;

    
d.nativeBarWidth d.barHeight d.barWidth 0;
    
d.scrollbarsClipped false;

    
// Used to only resize the line number gutter when necessary (when
    // the amount of lines crosses a boundary that makes its width change)
    
d.lineNumWidth d.lineNumInnerWidth d.lineNumChars null;
    
// Set to true when a non-horizontal-scrolling line widget is
    // added. As an optimization, line widget aligning is skipped when
    // this is false.
    
d.alignWidgets false;

    
d.cachedCharWidth d.cachedTextHeight d.cachedPaddingH null;

    
// Tracks the maximum line length so that the horizontal scrollbar
    // can be kept static when scrolling.
    
d.maxLine null;
    
d.maxLineLength 0;
    
d.maxLineChanged false;

    
// Used for measuring wheel scrolling granularity
    
d.wheelDX d.wheelDY d.wheelStartX d.wheelStartY null;

    
// True when shift is held down.
    
d.shift false;

    
// Used to track whether anything happened since the context menu
    // was opened.
    
d.selForContextMenu null;

    
d.activeTouch null;

    
d.gutterSpecs getGutters(options.guttersoptions.lineNumbers);
    
renderGutters(d);

    
input.init(d);
  }

  
// Since the delta values reported on mouse wheel events are
  // unstandardized between browsers and even browser versions, and
  // generally horribly unpredictable, this code starts by measuring
  // the scroll effect that the first few mouse wheel events have,
  // and, from that, detects the way it can convert deltas to pixel
  // offsets afterwards.
  //
  // The reason we want to know the amount a wheel event will scroll
  // is that it gives us a chance to update the display before the
  // actual scrolling happens, reducing flickering.

  
var wheelSamples 0wheelPixelsPerUnit null;
  
// Fill in a browser-detected starting value on browsers where we
  // know one. These don't have to be accurate -- the result of them
  // being wrong would just be a slight flicker on the first wheel
  // scroll (if it is large enough).
  
if (ie) { wheelPixelsPerUnit = -.53; }
  else if (
gecko) { wheelPixelsPerUnit 15; }
  else if (
chrome) { wheelPixelsPerUnit = -.7; }
  else if (
safari) { wheelPixelsPerUnit = -1/3; }

  function 
wheelEventDelta(e) {
    var 
dx e.wheelDeltaXdy e.wheelDeltaY;
    if (
dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx e.detail; }
    if (
dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy e.detail; }
    else if (
dy == null) { dy e.wheelDelta; }
    return {
xdxydy}
  }
  function 
wheelEventPixels(e) {
    var 
delta wheelEventDelta(e);
    
delta.*= wheelPixelsPerUnit;
    
delta.*= wheelPixelsPerUnit;
    return 
delta
  
}

  function 
onScrollWheel(cme) {
    var 
delta wheelEventDelta(e), dx delta.xdy delta.y;

    var 
display cm.displayscroll display.scroller;
    
// Quit if there's nothing to scroll here
    
var canScrollX scroll.scrollWidth scroll.clientWidth;
    var 
canScrollY scroll.scrollHeight scroll.clientHeight;
    if (!(
dx && canScrollX || dy && canScrollY)) { return }

    
// Webkit browsers on OS X abort momentum scrolls when the target
    // of the scroll event is removed from the scrollable element.
    // This hack (see related code in patchDisplay) makes sure the
    // element is kept around.
    
if (dy && mac && webkit) {
      
outer: for (var cur e.targetview display.viewcur != scrollcur cur.parentNode) {
        for (var 
0view.lengthi++) {
          if (
view[i].node == cur) {
            
cm.display.currentWheelTarget cur;
            break 
outer
          
}
        }
      }
    }

    
// On some browsers, horizontal scrolling will cause redraws to
    // happen before the gutter has been realigned, causing it to
    // wriggle around in a most unseemly way. When we have an
    // estimated pixels/delta value, we just handle horizontal
    // scrolling entirely here. It'll be slightly off from native, but
    // better than glitching out.
    
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
      if (
dy && canScrollY)
        { 
updateScrollTop(cmMath.max(0scroll.scrollTop dy wheelPixelsPerUnit)); }
      
setScrollLeft(cmMath.max(0scroll.scrollLeft dx wheelPixelsPerUnit));
      
// Only prevent default scrolling if vertical scrolling is
      // actually possible. Otherwise, it causes vertical scroll
      // jitter on OSX trackpads when deltaX is small and deltaY
      // is large (issue #3579)
      
if (!dy || (dy && canScrollY))
        { 
e_preventDefault(e); }
      
display.wheelStartX null// Abort measurement, if in progress
      
return
    }

    
// 'Project' the visible viewport to cover the area that is being
    // scrolled into view (if we know enough to estimate it).
    
if (dy && wheelPixelsPerUnit != null) {
      var 
pixels dy wheelPixelsPerUnit;
      var 
top cm.doc.scrollTopbot top display.wrapper.clientHeight;
      if (
pixels 0) { top Math.max(0top pixels 50); }
      else { 
bot Math.min(cm.doc.heightbot pixels 50); }
      
updateDisplaySimple(cm, {toptopbottombot});
    }

    if (
wheelSamples 20) {
      if (
display.wheelStartX == null) {
        
display.wheelStartX scroll.scrollLeftdisplay.wheelStartY scroll.scrollTop;
        
display.wheelDX dxdisplay.wheelDY dy;
        
setTimeout(function () {
          if (
display.wheelStartX == null) { return }
          var 
movedX scroll.scrollLeft display.wheelStartX;
          var 
movedY scroll.scrollTop display.wheelStartY;
          var 
sample = (movedY && display.wheelDY && movedY display.wheelDY) ||
            (
movedX && display.wheelDX && movedX display.wheelDX);
          
display.wheelStartX display.wheelStartY null;
          if (!
sample) { return }
          
wheelPixelsPerUnit = (wheelPixelsPerUnit wheelSamples sample) / (wheelSamples 1);
          ++
wheelSamples;
        }, 
200);
      } else {
        
display.wheelDX += dxdisplay.wheelDY += dy;
      }
    }
  }

  
// Selection objects are immutable. A new one is created every time
  // the selection changes. A selection is one or more non-overlapping
  // (and non-touching) ranges, sorted, and an integer that indicates
  // which one is the primary selection (the one that's scrolled into
  // view, that getCursor returns, etc).
  
var Selection = function(rangesprimIndex) {
    
this.ranges ranges;
    
this.primIndex primIndex;
  };

  
Selection.prototype.primary = function () { return this.ranges[this.primIndex] };

  
Selection.prototype.equals = function (other) {
    if (
other == this) { return true }
    if (
other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
    for (var 
0this.ranges.lengthi++) {
      var 
here this.ranges[i], there other.ranges[i];
      if (!
equalCursorPos(here.anchorthere.anchor) || !equalCursorPos(here.headthere.head)) { return false }
    }
    return 
true
  
};

  
Selection.prototype.deepCopy = function () {
    var 
out = [];
    for (var 
0this.ranges.lengthi++)
      { 
out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); }
    return new 
Selection(outthis.primIndex)
  };

  
Selection.prototype.somethingSelected = function () {
    for (var 
0this.ranges.lengthi++)
      { if (!
this.ranges[i].empty()) { return true } }
    return 
false
  
};

  
Selection.prototype.contains = function (posend) {
    if (!
end) { end pos; }
    for (var 
0this.ranges.lengthi++) {
      var 
range this.ranges[i];
      if (
cmp(endrange.from()) >= && cmp(posrange.to()) <= 0)
        { return 
}
    }
    return -
1
  
};

  var 
Range = function(anchorhead) {
    
this.anchor anchorthis.head head;
  };

  
Range.prototype.from = function () { return minPos(this.anchorthis.head) };
  
Range.prototype.to = function () { return maxPos(this.anchorthis.head) };
  
Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };

  
// Take an unsorted, potentially overlapping set of ranges, and
  // build a selection out of it. 'Consumes' ranges array (modifying
  // it).
  
function normalizeSelection(cmrangesprimIndex) {
    var 
mayTouch cm && cm.options.selectionsMayTouch;
    var 
prim ranges[primIndex];
    
ranges.sort(function (ab) { return cmp(a.from(), b.from()); });
    
primIndex indexOf(rangesprim);
    for (var 
1ranges.lengthi++) {
      var 
cur ranges[i], prev ranges[1];
      var 
diff cmp(prev.to(), cur.from());
      if (
mayTouch && !cur.empty() ? diff diff >= 0) {
        var 
from minPos(prev.from(), cur.from()), to maxPos(prev.to(), cur.to());
        var 
inv prev.empty() ? cur.from() == cur.head prev.from() == prev.head;
        if (
<= primIndex) { --primIndex; }
        
ranges.splice(--i2, new Range(inv to frominv from to));
      }
    }
    return new 
Selection(rangesprimIndex)
  }

  function 
simpleSelection(anchorhead) {
    return new 
Selection([new Range(anchorhead || anchor)], 0)
  }

  
// Compute the position of the end of a change (its 'to' property
  // refers to the pre-change end).
  
function changeEnd(change) {
    if (!
change.text) { return change.to }
    return 
Pos(change.from.line change.text.length 1,
               
lst(change.text).length + (change.text.length == change.from.ch 0))
  }

  
// Adjust a position to refer to the post-change position of the
  // same text, or the end of the change if the change covers it.
  
function adjustForChange(poschange) {
    if (
cmp(poschange.from) < 0) { return pos }
    if (
cmp(poschange.to) <= 0) { return changeEnd(change) }

    var 
line pos.line change.text.length - (change.to.line change.from.line) - 1ch pos.ch;
    if (
pos.line == change.to.line) { ch += changeEnd(change).ch change.to.ch; }
    return 
Pos(linech)
  }

  function 
computeSelAfterChange(docchange) {
    var 
out = [];
    for (var 
0doc.sel.ranges.lengthi++) {
      var 
range doc.sel.ranges[i];
      
out.push(new Range(adjustForChange(range.anchorchange),
                         
adjustForChange(range.headchange)));
    }
    return 
normalizeSelection(doc.cmoutdoc.sel.primIndex)
  }

  function 
offsetPos(posoldnw) {
    if (
pos.line == old.line)
      { return 
Pos(nw.linepos.ch old.ch nw.ch) }
    else
      { return 
Pos(nw.line + (pos.line old.line), pos.ch) }
  }

  
// Used by replaceSelections to allow moving the selection to the
  // start or around the replaced test. Hint may be "start" or "around".
  
function computeReplacedSel(docchangeshint) {
    var 
out = [];
    var 
oldPrev Pos(doc.first0), newPrev oldPrev;
    for (var 
0changes.lengthi++) {
      var 
change changes[i];
      var 
from offsetPos(change.fromoldPrevnewPrev);
      var 
to offsetPos(changeEnd(change), oldPrevnewPrev);
      
oldPrev change.to;
      
newPrev to;
      if (
hint == "around") {
        var 
range doc.sel.ranges[i], inv cmp(range.headrange.anchor) < 0;
        
out[i] = new Range(inv to frominv from to);
      } else {
        
out[i] = new Range(fromfrom);
      }
    }
    return new 
Selection(outdoc.sel.primIndex)
  }

  
// Used to get the editor into a consistent state again when options change.

  
function loadMode(cm) {
    
cm.doc.mode getMode(cm.optionscm.doc.modeOption);
    
resetModeState(cm);
  }

  function 
resetModeState(cm) {
    
cm.doc.iter(function (line) {
      if (
line.stateAfter) { line.stateAfter null; }
      if (
line.styles) { line.styles null; }
    });
    
cm.doc.modeFrontier cm.doc.highlightFrontier cm.doc.first;
    
startWorker(cm100);
    
cm.state.modeGen++;
    if (
cm.curOp) { regChange(cm); }
  }

  
// DOCUMENT DATA STRUCTURE

  // By default, updates that start and end at the beginning of a line
  // are treated specially, in order to make the association of line
  // widgets and marker elements with the text behave more intuitive.
  
function isWholeLineUpdate(docchange) {
    return 
change.from.ch == && change.to.ch == && lst(change.text) == "" &&
      (!
doc.cm || doc.cm.options.wholeLineUpdateBefore)
  }

  
// Perform a change on the document data structure.
  
function updateDoc(docchangemarkedSpansestimateHeight) {
    function 
spansFor(n) {return markedSpans markedSpans[n] : null}
    function 
update(linetextspans) {
      
updateLine(linetextspansestimateHeight);
      
signalLater(line"change"linechange);
    }
    function 
linesFor(startend) {
      var 
result = [];
      for (var 
startend; ++i)
        { 
result.push(new Line(text[i], spansFor(i), estimateHeight)); }
      return 
result
    
}

    var 
from change.fromto change.totext change.text;
    var 
firstLine getLine(docfrom.line), lastLine getLine(docto.line);
    var 
lastText lst(text), lastSpans spansFor(text.length 1), nlines to.line from.line;

    
// Adjust the line structure
    
if (change.full) {
      
doc.insert(0linesFor(0text.length));
      
doc.remove(text.lengthdoc.size text.length);
    } else if (
isWholeLineUpdate(docchange)) {
      
// This is a whole-line replace. Treated specially to make
      // sure line objects move the way they are supposed to.
      
var added linesFor(0text.length 1);
      
update(lastLinelastLine.textlastSpans);
      if (
nlines) { doc.remove(from.linenlines); }
      if (
added.length) { doc.insert(from.lineadded); }
    } else if (
firstLine == lastLine) {
      if (
text.length == 1) {
        
update(firstLinefirstLine.text.slice(0from.ch) + lastText firstLine.text.slice(to.ch), lastSpans);
      } else {
        var 
added$linesFor(1text.length 1);
        
added$1.push(new Line(lastText firstLine.text.slice(to.ch), lastSpansestimateHeight));
        
update(firstLinefirstLine.text.slice(0from.ch) + text[0], spansFor(0));
        
doc.insert(from.line 1added$1);
      }
    } else if (
text.length == 1) {
      
update(firstLinefirstLine.text.slice(0from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
      
doc.remove(from.line 1nlines);
    } else {
      
update(firstLinefirstLine.text.slice(0from.ch) + text[0], spansFor(0));
      
update(lastLinelastText lastLine.text.slice(to.ch), lastSpans);
      var 
added$linesFor(1text.length 1);
      if (
nlines 1) { doc.remove(from.line 1nlines 1); }
      
doc.insert(from.line 1added$2);
    }

    
signalLater(doc"change"docchange);
  }

  
// Call f for all linked documents.
  
function linkedDocs(docfsharedHistOnly) {
    function 
propagate(docskipsharedHist) {
      if (
doc.linked) { for (var 0doc.linked.length; ++i) {
        var 
rel doc.linked[i];
        if (
rel.doc == skip) { continue }
        var 
shared sharedHist && rel.sharedHist;
        if (
sharedHistOnly && !shared) { continue }
        
f(rel.docshared);
        
propagate(rel.docdocshared);
      } }
    }
    
propagate(docnulltrue);
  }

  
// Attach a document to an editor.
  
function attachDoc(cmdoc) {
    if (
doc.cm) { throw new Error("This document is already in use.") }
    
cm.doc doc;
    
doc.cm cm;
    
estimateLineHeights(cm);
    
loadMode(cm);
    
setDirectionClass(cm);
    if (!
cm.options.lineWrapping) { findMaxLine(cm); }
    
cm.options.mode doc.modeOption;
    
regChange(cm);
  }

  function 
setDirectionClass(cm) {
  (
cm.doc.direction == "rtl" addClass rmClass)(cm.display.lineDiv"CodeMirror-rtl");
  }

  function 
directionChanged(cm) {
    
runInOp(cm, function () {
      
setDirectionClass(cm);
      
regChange(cm);
    });
  }

  function 
History(startGen) {
    
// Arrays of change events and selections. Doing something adds an
    // event to done and clears undo. Undoing moves events from done
    // to undone, redoing moves them in the other direction.
    
this.done = []; this.undone = [];
    
this.undoDepth Infinity;
    
// Used to track when changes can be merged into a single undo
    // event
    
this.lastModTime this.lastSelTime 0;
    
this.lastOp this.lastSelOp null;
    
this.lastOrigin this.lastSelOrigin null;
    
// Used by the isClean() method
    
this.generation this.maxGeneration startGen || 1;
  }

  
// Create a history change event from an updateDoc-style change
  // object.
  
function historyChangeFromChange(docchange) {
    var 
histChange = {fromcopyPos(change.from), tochangeEnd(change), textgetBetween(docchange.fromchange.to)};
    
attachLocalSpans(dochistChangechange.from.linechange.to.line 1);
    
linkedDocs(doc, function (doc) { return attachLocalSpans(dochistChangechange.from.linechange.to.line 1); }, true);
    return 
histChange
  
}

  
// Pop all selection events off the end of a history array. Stop at
  // a change event.
  
function clearSelectionEvents(array) {
    while (array.
length) {
      var 
last lst(array);
      if (
last.ranges) { array.pop(); }
      else { break }
    }
  }

  
// Find the top change event in the history. Pop off selection
  // events that are in the way.
  
function lastChangeEvent(histforce) {
    if (
force) {
      
clearSelectionEvents(hist.done);
      return 
lst(hist.done)
    } else if (
hist.done.length && !lst(hist.done).ranges) {
      return 
lst(hist.done)
    } else if (
hist.done.length && !hist.done[hist.done.length 2].ranges) {
      
hist.done.pop();
      return 
lst(hist.done)
    }
  }

  
// Register a change in the history. Merges changes that are within
  // a single operation, or are close together with an origin that
  // allows merging (starting with "+") into a single event.
  
function addChangeToHistory(docchangeselAfteropId) {
    var 
hist doc.history;
    
hist.undone.length 0;
    var 
time = +new Datecur;
    var 
last;

    if ((
hist.lastOp == opId ||
         
hist.lastOrigin == change.origin && change.origin &&
         ((
change.origin.charAt(0) == "+" && hist.lastModTime time - (doc.cm doc.cm.options.historyEventDelay 500)) ||
          
change.origin.charAt(0) == "*")) &&
        (
cur lastChangeEvent(histhist.lastOp == opId))) {
      
// Merge this change into the last event
      
last lst(cur.changes);
      if (
cmp(change.fromchange.to) == && cmp(change.fromlast.to) == 0) {
        
// Optimized case for simple insertion -- don't want to add
        // new changesets for every character typed
        
last.to changeEnd(change);
      } else {
        
// Add new sub-event
        
cur.changes.push(historyChangeFromChange(docchange));
      }
    } else {
      
// Can not be merged, start a new event.
      
var before lst(hist.done);
      if (!
before || !before.ranges)
        { 
pushSelectionToHistory(doc.selhist.done); }
      
cur = {changes: [historyChangeFromChange(docchange)],
             
generationhist.generation};
      
hist.done.push(cur);
      while (
hist.done.length hist.undoDepth) {
        
hist.done.shift();
        if (!
hist.done[0].ranges) { hist.done.shift(); }
      }
    }
    
hist.done.push(selAfter);
    
hist.generation = ++hist.maxGeneration;
    
hist.lastModTime hist.lastSelTime time;
    
hist.lastOp hist.lastSelOp opId;
    
hist.lastOrigin hist.lastSelOrigin change.origin;

    if (!
last) { signal(doc"historyAdded"); }
  }

  function 
selectionEventCanBeMerged(docoriginprevsel) {
    var 
ch origin.charAt(0);
    return 
ch == "*" ||
      
ch == "+" &&
      
prev.ranges.length == sel.ranges.length &&
      
prev.somethingSelected() == sel.somethingSelected() &&
      new 
Date doc.history.lastSelTime <= (doc.cm doc.cm.options.historyEventDelay 500)
  }

  
// Called whenever the selection changes, sets the new selection as
  // the pending selection in the history, and pushes the old pending
  // selection into the 'done' array when it was significantly
  // different (in number of selected ranges, emptiness, or time).
  
function addSelectionToHistory(docselopIdoptions) {
    var 
hist doc.historyorigin options && options.origin;

    
// A new event is started when the previous origin does not match
    // the current, or the origins don't allow matching. Origins
    // starting with * are always merged, those starting with + are
    // merged when similar and close together in time.
    
if (opId == hist.lastSelOp ||
        (
origin && hist.lastSelOrigin == origin &&
         (
hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
          
selectionEventCanBeMerged(docoriginlst(hist.done), sel))))
      { 
hist.done[hist.done.length 1] = sel; }
    else
      { 
pushSelectionToHistory(selhist.done); }

    
hist.lastSelTime = +new Date;
    
hist.lastSelOrigin origin;
    
hist.lastSelOp opId;
    if (
options && options.clearRedo !== false)
      { 
clearSelectionEvents(hist.undone); }
  }

  function 
pushSelectionToHistory(seldest) {
    var 
top lst(dest);
    if (!(
top && top.ranges && top.equals(sel)))
      { 
dest.push(sel); }
  }

  
// Used to store marked span information in the history.
  
function attachLocalSpans(docchangefromto) {
    var 
existing change["spans_" doc.id], 0;
    
doc.iter(Math.max(doc.firstfrom), Math.min(doc.first doc.sizeto), function (line) {
      if (
line.markedSpans)
        { (
existing || (existing change["spans_" doc.id] = {}))[n] = line.markedSpans; }
      ++
n;
    });
  }

  
// When un/re-doing restores text containing marked spans, those
  // that have been explicitly cleared should not be restored.
  
function removeClearedSpans(spans) {
    if (!
spans) { return null }
    var 
out;
    for (var 
0spans.length; ++i) {
      if (
spans[i].marker.explicitlyCleared) { if (!out) { out spans.slice(0i); } }
      else if (
out) { out.push(spans[i]); }
    }
    return !
out spans out.length out null
  
}

  
// Retrieve and filter the old marked spans stored in a change event.
  
function getOldSpans(docchange) {
    var 
found change["spans_" doc.id];
    if (!
found) { return null }
    var 
nw = [];
    for (var 
0change.text.length; ++i)
      { 
nw.push(removeClearedSpans(found[i])); }
    return 
nw
  
}

  
// Used for un/re-doing changes from the history. Combines the
  // result of computing the existing spans with the set of spans that
  // existed in the history (so that deleting around a span and then
  // undoing brings back the span).
  
function mergeOldSpans(docchange) {
    var 
old getOldSpans(docchange);
    var 
stretched stretchSpansOverChange(docchange);
    if (!
old) { return stretched }
    if (!
stretched) { return old }

    for (var 
0old.length; ++i) {
      var 
oldCur old[i], stretchCur stretched[i];
      if (
oldCur && stretchCur) {
        
spans: for (var 0stretchCur.length; ++j) {
          var 
span stretchCur[j];
          for (var 
0oldCur.length; ++k)
            { if (
oldCur[k].marker == span.marker) { continue spans } }
          
oldCur.push(span);
        }
      } else if (
stretchCur) {
        
old[i] = stretchCur;
      }
    }
    return 
old
  
}

  
// Used both to provide a JSON-safe object in .getHistory, and, when
  // detaching a document, to split the history in two
  
function copyHistoryArray(eventsnewGroupinstantiateSel) {
    var 
copy = [];
    for (var 
0events.length; ++i) {
      var 
event events[i];
      if (
event.ranges) {
        
copy.push(instantiateSel Selection.prototype.deepCopy.call(event) : event);
        continue
      }
      var 
changes event.changesnewChanges = [];
      
copy.push({changesnewChanges});
      for (var 
0changes.length; ++j) {
        var 
change changes[j], = (void 0);
        
newChanges.push({fromchange.fromtochange.totextchange.text});
        if (
newGroup) { for (var prop in change) { if (prop.match(/^spans_(d+)$/)) {
          if (
indexOf(newGroupNumber(m[1])) > -1) {
            
lst(newChanges)[prop] = change[prop];
            
delete change[prop];
          }
        } } }
      }
    }
    return 
copy
  
}

  
// The 'scroll' parameter given to many of these indicated whether
  // the new cursor position should be scrolled into view after
  // modifying the selection.

  // If shift is held or the extend flag is set, extends a range to
  // include a given position (and optionally a second position).
  // Otherwise, simply returns the range between the given positions.
  // Used for cursor motion and such.
  
function extendRange(rangeheadotherextend) {
    if (
extend) {
      var 
anchor range.anchor;
      if (
other) {
        var 
posBefore cmp(headanchor) < 0;
        if (
posBefore != (cmp(otheranchor) < 0)) {
          
anchor head;
          
head other;
        } else if (
posBefore != (cmp(headother) < 0)) {
          
head other;
        }
      }
      return new 
Range(anchorhead)
    } else {
      return new 
Range(other || headhead)
    }
  }

  
// Extend the primary selection range, discard the rest.
  
function extendSelection(docheadotheroptionsextend) {
    if (
extend == null) { extend doc.cm && (doc.cm.display.shift || doc.extend); }
    
setSelection(doc, new Selection([extendRange(doc.sel.primary(), headotherextend)], 0), options);
  }

  
// Extend all selections (pos is an array of selections with length
  // equal the number of selections)
  
function extendSelections(docheadsoptions) {
    var 
out = [];
    var 
extend doc.cm && (doc.cm.display.shift || doc.extend);
    for (var 
0doc.sel.ranges.lengthi++)
      { 
out[i] = extendRange(doc.sel.ranges[i], heads[i], nullextend); }
    var 
newSel normalizeSelection(doc.cmoutdoc.sel.primIndex);
    
setSelection(docnewSeloptions);
  }

  
// Updates a single range in the selection.
  
function replaceOneSelection(docirangeoptions) {
    var 
ranges doc.sel.ranges.slice(0);
    
ranges[i] = range;
    
setSelection(docnormalizeSelection(doc.cmrangesdoc.sel.primIndex), options);
  }

  
// Reset the selection to a single range.
  
function setSimpleSelection(docanchorheadoptions) {
    
setSelection(docsimpleSelection(anchorhead), options);
  }

  
// Give beforeSelectionChange handlers a change to influence a
  // selection update.
  
function filterSelectionChange(docseloptions) {
    var 
obj = {
      
rangessel.ranges,
      
update: function(ranges) {
        
this.ranges = [];
        for (var 
0ranges.lengthi++)
          { 
this.ranges[i] = new Range(clipPos(docranges[i].anchor),
                                     
clipPos(docranges[i].head)); }
      },
      
originoptions && options.origin
    
};
    
signal(doc"beforeSelectionChange"docobj);
    if (
doc.cm) { signal(doc.cm"beforeSelectionChange"doc.cmobj); }
    if (
obj.ranges != sel.ranges) { return normalizeSelection(doc.cmobj.rangesobj.ranges.length 1) }
    else { return 
sel }
  }

  function 
setSelectionReplaceHistory(docseloptions) {
    var 
done doc.history.donelast lst(done);
    if (
last && last.ranges) {
      
done[done.length 1] = sel;
      
setSelectionNoUndo(docseloptions);
    } else {
      
setSelection(docseloptions);
    }
  }

  
// Set a new selection.
  
function setSelection(docseloptions) {
    
setSelectionNoUndo(docseloptions);
    
addSelectionToHistory(docdoc.seldoc.cm doc.cm.curOp.id NaNoptions);
  }

  function 
setSelectionNoUndo(docseloptions) {
    if (
hasHandler(doc"beforeSelectionChange") || doc.cm && hasHandler(doc.cm"beforeSelectionChange"))
      { 
sel filterSelectionChange(docseloptions); }

    var 
bias options && options.bias ||
      (
cmp(sel.primary().headdoc.sel.primary().head) < ? -1);
    
setSelectionInner(docskipAtomicInSelection(docselbiastrue));

    if (!(
options && options.scroll === false) && doc.cm)
      { 
ensureCursorVisible(doc.cm); }
  }

  function 
setSelectionInner(docsel) {
    if (
sel.equals(doc.sel)) { return }

    
doc.sel sel;

    if (
doc.cm) {
      
doc.cm.curOp.updateInput 1;
      
doc.cm.curOp.selectionChanged true;
      
signalCursorActivity(doc.cm);
    }
    
signalLater(doc"cursorActivity"doc);
  }

  
// Verify that the selection does not partially select any atomic
  // marked ranges.
  
function reCheckSelection(doc) {
    
setSelectionInner(docskipAtomicInSelection(docdoc.selnullfalse));
  }

  
// Return a selection that does not partially select any atomic
  // ranges.
  
function skipAtomicInSelection(docselbiasmayClear) {
    var 
out;
    for (var 
0sel.ranges.lengthi++) {
      var 
range sel.ranges[i];
      var 
old sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
      var 
newAnchor skipAtomic(docrange.anchorold && old.anchorbiasmayClear);
      var 
newHead skipAtomic(docrange.headold && old.headbiasmayClear);
      if (
out || newAnchor != range.anchor || newHead != range.head) {
        if (!
out) { out sel.ranges.slice(0i); }
        
out[i] = new Range(newAnchornewHead);
      }
    }
    return 
out normalizeSelection(doc.cmoutsel.primIndex) : sel
  
}

  function 
skipAtomicInner(docposoldPosdirmayClear) {
    var 
line getLine(docpos.line);
    if (
line.markedSpans) { for (var 0line.markedSpans.length; ++i) {
      var 
sp line.markedSpans[i], sp.marker;

      
// Determine if we should prevent the cursor being placed to the left/right of an atomic marker
      // Historically this was determined using the inclusiveLeft/Right option, but the new way to control it
      // is with selectLeft/Right
      
var preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft m.inclusiveLeft;
      var 
preventCursorRight = ("selectRight" in m) ? !m.selectRight m.inclusiveRight;

      if ((
sp.from == null || (preventCursorLeft sp.from <= pos.ch sp.from pos.ch)) &&
          (
sp.to == null || (preventCursorRight sp.to >= pos.ch sp.to pos.ch))) {
        if (
mayClear) {
          
signal(m"beforeCursorEnter");
          if (
m.explicitlyCleared) {
            if (!
line.markedSpans) { break }
            else {--
i; continue}
          }
        }
        if (!
m.atomic) { continue }

        if (
oldPos) {
          var 
near m.find(dir : -1), diff = (void 0);
          if (
dir preventCursorRight preventCursorLeft)
            { 
near movePos(docnear, -dirnear && near.line == pos.line line null); }
          if (
near && near.line == pos.line && (diff cmp(nearoldPos)) && (dir diff diff 0))
            { return 
skipAtomicInner(docnearposdirmayClear) }
        }

        var 
far m.find(dir ? -1);
        if (
dir preventCursorLeft preventCursorRight)
          { 
far movePos(docfardirfar.line == pos.line line null); }
        return 
far skipAtomicInner(docfarposdirmayClear) : null
      
}
    } }
    return 
pos
  
}

  
// Ensure a given position is not inside an atomic range.
  
function skipAtomic(docposoldPosbiasmayClear) {
    var 
dir bias || 1;
    var 
found skipAtomicInner(docposoldPosdirmayClear) ||
        (!
mayClear && skipAtomicInner(docposoldPosdirtrue)) ||
        
skipAtomicInner(docposoldPos, -dirmayClear) ||
        (!
mayClear && skipAtomicInner(docposoldPos, -dirtrue));
    if (!
found) {
      
doc.cantEdit true;
      return 
Pos(doc.first0)
    }
    return 
found
  
}

  function 
movePos(docposdirline) {
    if (
dir && pos.ch == 0) {
      if (
pos.line doc.first) { return clipPos(docPos(pos.line 1)) }
      else { return 
null }
    } else if (
dir && pos.ch == (line || getLine(docpos.line)).text.length) {
      if (
pos.line doc.first doc.size 1) { return Pos(pos.line 10) }
      else { return 
null }
    } else {
      return new 
Pos(pos.linepos.ch dir)
    }
  }

  function 
selectAll(cm) {
    
cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
  }

  
// UPDATING

  // Allow "beforeChange" event handlers to influence a change
  
function filterChange(docchangeupdate) {
    var 
obj = {
      
canceledfalse,
      
fromchange.from,
      
tochange.to,
      
textchange.text,
      
originchange.origin,
      
cancel: function () { return obj.canceled true; }
    };
    if (
update) { obj.update = function (fromtotextorigin) {
      if (
from) { obj.from clipPos(docfrom); }
      if (
to) { obj.to clipPos(docto); }
      if (
text) { obj.text text; }
      if (
origin !== undefined) { obj.origin origin; }
    }; }
    
signal(doc"beforeChange"docobj);
    if (
doc.cm) { signal(doc.cm"beforeChange"doc.cmobj); }

    if (
obj.canceled) {
      if (
doc.cm) { doc.cm.curOp.updateInput 2; }
      return 
null
    
}
    return {
fromobj.fromtoobj.totextobj.textoriginobj.origin}
  }

  
// Apply a change to a document, and add it to the document's
  // history, and propagating it to all linked documents.
  
function makeChange(docchangeignoreReadOnly) {
    if (
doc.cm) {
      if (!
doc.cm.curOp) { return operation(doc.cmmakeChange)(docchangeignoreReadOnly) }
      if (
doc.cm.state.suppressEdits) { return }
    }

    if (
hasHandler(doc"beforeChange") || doc.cm && hasHandler(doc.cm"beforeChange")) {
      
change filterChange(docchangetrue);
      if (!
change) { return }
    }

    
// Possibly split or suppress the update based on the presence
    // of read-only spans in its range.
    
var split sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(docchange.fromchange.to);
    if (
split) {
      for (var 
split.length 1>= 0; --i)
        { 
makeChangeInner(doc, {fromsplit[i].fromtosplit[i].totext? [""] : change.textoriginchange.origin}); }
    } else {
      
makeChangeInner(docchange);
    }
  }

  function 
makeChangeInner(docchange) {
    if (
change.text.length == && change.text[0] == "" && cmp(change.fromchange.to) == 0) { return }
    var 
selAfter computeSelAfterChange(docchange);
    
addChangeToHistory(docchangeselAfterdoc.cm doc.cm.curOp.id NaN);

    
makeChangeSingleDoc(docchangeselAfterstretchSpansOverChange(docchange));
    var 
rebased = [];

    
linkedDocs(doc, function (docsharedHist) {
      if (!
sharedHist && indexOf(rebaseddoc.history) == -1) {
        
rebaseHist(doc.historychange);
        
rebased.push(doc.history);
      }
      
makeChangeSingleDoc(docchangenullstretchSpansOverChange(docchange));
    });
  }

  
// Revert a change stored in a document's history.
  
function makeChangeFromHistory(doctypeallowSelectionOnly) {
    var 
suppress doc.cm && doc.cm.state.suppressEdits;
    if (
suppress && !allowSelectionOnly) { return }

    var 
hist doc.historyeventselAfter doc.sel;
    var 
source type == "undo" hist.done hist.undonedest type == "undo" hist.undone hist.done;

    
// Verify that there is a useable event (so that ctrl-z won't
    // needlessly clear selection events)
    
var 0;
    for (; 
source.lengthi++) {
      
event source[i];
      if (
allowSelectionOnly event.ranges && !event.equals(doc.sel) : !event.ranges)
        { break }
    }
    if (
== source.length) { return }
    
hist.lastOrigin hist.lastSelOrigin null;

    for (;;) {
      
event source.pop();
      if (
event.ranges) {
        
pushSelectionToHistory(eventdest);
        if (
allowSelectionOnly && !event.equals(doc.sel)) {
          
setSelection(docevent, {clearRedofalse});
          return
        }
        
selAfter event;
      } else if (
suppress) {
        
source.push(event);
        return
      } else { break }
    }

    
// Build up a reverse change object to add to the opposite history
    // stack (redo when undoing, and vice versa).
    
var antiChanges = [];
    
pushSelectionToHistory(selAfterdest);
    
dest.push({changesantiChangesgenerationhist.generation});
    
hist.generation event.generation || ++hist.maxGeneration;

    var 
filter hasHandler(doc"beforeChange") || doc.cm && hasHandler(doc.cm"beforeChange");

    var 
loop = function ( ) {
      var 
change event.changes[i];
      
change.origin type;
      if (
filter && !filterChange(docchangefalse)) {
        
source.length 0;
        return {}
      }

      
antiChanges.push(historyChangeFromChange(docchange));

      var 
after computeSelAfterChange(docchange) : lst(source);
      
makeChangeSingleDoc(docchangeaftermergeOldSpans(docchange));
      if (!
&& doc.cm) { doc.cm.scrollIntoView({fromchange.fromtochangeEnd(change)}); }
      var 
rebased = [];

      
// Propagate to the linked documents
      
linkedDocs(doc, function (docsharedHist) {
        if (!
sharedHist && indexOf(rebaseddoc.history) == -1) {
          
rebaseHist(doc.historychange);
          
rebased.push(doc.history);
        }
        
makeChangeSingleDoc(docchangenullmergeOldSpans(docchange));
      });
    };

    for (var 
i$event.changes.length 1i$>= 0; --i$1) {
      var 
returned loopi$);

      if ( 
returned ) return returned.v;
    }
  }

  
// Sub-views need their line numbers shifted when text is added
  // above or below them in the parent document.
  
function shiftDoc(docdistance) {
    if (
distance == 0) { return }
    
doc.first += distance;
    
doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
      
Pos(range.anchor.line distancerange.anchor.ch),
      
Pos(range.head.line distancerange.head.ch)
    ); }), 
doc.sel.primIndex);
    if (
doc.cm) {
      
regChange(doc.cmdoc.firstdoc.first distancedistance);
      for (var 
doc.cm.displayd.viewFromd.viewTol++)
        { 
regLineChange(doc.cml"gutter"); }
    }
  }

  
// More lower-level change function, handling only a single document
  // (not linked ones).
  
function makeChangeSingleDoc(docchangeselAfterspans) {
    if (
doc.cm && !doc.cm.curOp)
      { return 
operation(doc.cmmakeChangeSingleDoc)(docchangeselAfterspans) }

    if (
change.to.line doc.first) {
      
shiftDoc(docchange.text.length - (change.to.line change.from.line));
      return
    }
    if (
change.from.line doc.lastLine()) { return }

    
// Clip the change to the size of this doc
    
if (change.from.line doc.first) {
      var 
shift change.text.length - (doc.first change.from.line);
      
shiftDoc(docshift);
      
change = {fromPos(doc.first0), toPos(change.to.line shiftchange.to.ch),
                
text: [lst(change.text)], originchange.origin};
    }
    var 
last doc.lastLine();
    if (
change.to.line last) {
      
change = {fromchange.fromtoPos(lastgetLine(doclast).text.length),
                
text: [change.text[0]], originchange.origin};
    }

    
change.removed getBetween(docchange.fromchange.to);

    if (!
selAfter) { selAfter computeSelAfterChange(docchange); }
    if (
doc.cm) { makeChangeSingleDocInEditor(doc.cmchangespans); }
    else { 
updateDoc(docchangespans); }
    
setSelectionNoUndo(docselAftersel_dontScroll);

    if (
doc.cantEdit && skipAtomic(docPos(doc.firstLine(), 0)))
      { 
doc.cantEdit false; }
  }

  
// Handle the interaction of a change to a document with the editor
  // that this document is part of.
  
function makeChangeSingleDocInEditor(cmchangespans) {
    var 
doc cm.docdisplay cm.displayfrom change.fromto change.to;

    var 
recomputeMaxLength falsecheckWidthStart from.line;
    if (!
cm.options.lineWrapping) {
      
checkWidthStart lineNo(visualLine(getLine(docfrom.line)));
      
doc.iter(checkWidthStartto.line 1, function (line) {
        if (
line == display.maxLine) {
          
recomputeMaxLength true;
          return 
true
        
}
      });
    }

    if (
doc.sel.contains(change.fromchange.to) > -1)
      { 
signalCursorActivity(cm); }

    
updateDoc(docchangespansestimateHeight(cm));

    if (!
cm.options.lineWrapping) {
      
doc.iter(checkWidthStartfrom.line change.text.length, function (line) {
        var 
len lineLength(line);
        if (
len display.maxLineLength) {
          
display.maxLine line;
          
display.maxLineLength len;
          
display.maxLineChanged true;
          
recomputeMaxLength false;
        }
      });
      if (
recomputeMaxLength) { cm.curOp.updateMaxLine true; }
    }

    
retreatFrontier(docfrom.line);
    
startWorker(cm400);

    var 
lendiff change.text.length - (to.line from.line) - 1;
    
// Remember that these lines changed, for updating the display
    
if (change.full)
      { 
regChange(cm); }
    else if (
from.line == to.line && change.text.length == && !isWholeLineUpdate(cm.docchange))
      { 
regLineChange(cmfrom.line"text"); }
    else
      { 
regChange(cmfrom.lineto.line 1lendiff); }

    var 
changesHandler hasHandler(cm"changes"), changeHandler hasHandler(cm"change");
    if (
changeHandler || changesHandler) {
      var 
obj = {
        
fromfromtoto,
        
textchange.text,
        
removedchange.removed,
        
originchange.origin
      
};
      if (
changeHandler) { signalLater(cm"change"cmobj); }
      if (
changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
    }
    
cm.display.selForContextMenu null;
  }

  function 
replaceRange(doccodefromtoorigin) {
    var 
assign;

    if (!
to) { to from; }
    if (
cmp(tofrom) < 0) { (assign = [tofrom], from assign[0], to assign[1]); }
    if (
typeof code == "string") { code doc.splitLines(code); }
    
makeChange(doc, {fromfromtototextcodeoriginorigin});
  }

  
// Rebasing/resetting history to deal with externally-sourced changes

  
function rebaseHistSelSingle(posfromtodiff) {
    if (
to pos.line) {
      
pos.line += diff;
    } else if (
from pos.line) {
      
pos.line from;
      
pos.ch 0;
    }
  }

  
// Tries to rebase an array of history events given a change in the
  // document. If the change touches the same lines as the event, the
  // event, and everything 'behind' it, is discarded. If the change is
  // before the event, the event's positions are updated. Uses a
  // copy-on-write scheme for the positions, to avoid having to
  // reallocate them all on every rebase, but also avoid problems with
  // shared position objects being unsafely updated.
  
function rebaseHistArray(array, fromtodiff) {
    for (var 
0< array.length; ++i) {
      var 
sub = array[i], ok true;
      if (
sub.ranges) {
        if (!
sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied true; }
        for (var 
0sub.ranges.lengthj++) {
          
rebaseHistSelSingle(sub.ranges[j].anchorfromtodiff);
          
rebaseHistSelSingle(sub.ranges[j].headfromtodiff);
        }
        continue
      }
      for (var 
j$0j$sub.changes.length; ++j$1) {
        var 
cur sub.changes[j$1];
        if (
to cur.from.line) {
          
cur.from Pos(cur.from.line diffcur.from.ch);
          
cur.to Pos(cur.to.line diffcur.to.ch);
        } else if (
from <= cur.to.line) {
          
ok false;
          break
        }
      }
      if (!
ok) {
        array.
splice(01);
        
0;
      }
    }
  }

  function 
rebaseHist(histchange) {
    var 
from change.from.lineto change.to.linediff change.text.length - (to from) - 1;
    
rebaseHistArray(hist.donefromtodiff);
    
rebaseHistArray(hist.undonefromtodiff);
  }

  
// Utility for applying a change to a line by handle or number,
  // returning the number and optionally registering the line as
  // changed.
  
function changeLine(dochandlechangeTypeop) {
    var 
no handleline handle;
    if (
typeof handle == "number") { line getLine(docclipLine(dochandle)); }
    else { 
no lineNo(handle); }
    if (
no == null) { return null }
    if (
op(lineno) && doc.cm) { regLineChange(doc.cmnochangeType); }
    return 
line
  
}

  
// The document is represented as a BTree consisting of leaves, with
  // chunk of lines in them, and branches, with up to ten leaves or
  // other branch nodes below them. The top node is always a branch
  // node, and is the document object itself (meaning it has
  // additional methods and properties).
  //
  // All nodes have parent links. The tree is used both to go from
  // line numbers to line objects, and to go from objects to numbers.
  // It also indexes by height, and is used to convert between height
  // and line object, and to find the total height of the document.
  //
  // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html

  
function LeafChunk(lines) {
    
this.lines lines;
    
this.parent null;
    var 
height 0;
    for (var 
0lines.length; ++i) {
      
lines[i].parent this;
      
height += lines[i].height;
    }
    
this.height height;
  }

  
LeafChunk.prototype = {
    
chunkSize: function() { return this.lines.length },

    
// Remove the n lines at offset 'at'.
    
removeInner: function(atn) {
      for (var 
atat ne; ++i) {
        var 
line this.lines[i];
        
this.height -= line.height;
        
cleanUpLine(line);
        
signalLater(line"delete");
      }
      
this.lines.splice(atn);
    },

    
// Helper used to collapse a small branch into a single leaf.
    
collapse: function(lines) {
      
lines.push.apply(linesthis.lines);
    },

    
// Insert the given array of lines at offset 'at', count them as
    // having the given height.
    
insertInner: function(atlinesheight) {
      
this.height += height;
      
this.lines this.lines.slice(0at).concat(lines).concat(this.lines.slice(at));
      for (var 
0lines.length; ++i) { lines[i].parent this; }
    },

    
// Used to iterate over a part of the tree.
    
iterN: function(atnop) {
      for (var 
at nat e; ++at)
        { if (
op(this.lines[at])) { return true } }
    }
  };

  function 
BranchChunk(children) {
    
this.children children;
    var 
size 0height 0;
    for (var 
0children.length; ++i) {
      var 
ch children[i];
      
size += ch.chunkSize(); height += ch.height;
      
ch.parent this;
    }
    
this.size size;
    
this.height height;
    
this.parent null;
  }

  
BranchChunk.prototype = {
    
chunkSize: function() { return this.size },

    
removeInner: function(atn) {
      
this.size -= n;
      for (var 
0this.children.length; ++i) {
        var 
child this.children[i], sz child.chunkSize();
        if (
at sz) {
          var 
rm Math.min(nsz at), oldHeight child.height;
          
child.removeInner(atrm);
          
this.height -= oldHeight child.height;
          if (
sz == rm) { this.children.splice(i--, 1); child.parent null; }
          if ((
-= rm) == 0) { break }
          
at 0;
        } else { 
at -= sz; }
      }
      
// If the result is smaller than 25 lines, ensure that it is a
      // single leaf node.
      
if (this.size 25 &&
          (
this.children.length || !(this.children[0] instanceof LeafChunk))) {
        var 
lines = [];
        
this.collapse(lines);
        
this.children = [new LeafChunk(lines)];
        
this.children[0].parent this;
      }
    },

    
collapse: function(lines) {
      for (var 
0this.children.length; ++i) { this.children[i].collapse(lines); }
    },

    
insertInner: function(atlinesheight) {
      
this.size += lines.length;
      
this.height += height;
      for (var 
0this.children.length; ++i) {
        var 
child this.children[i], sz child.chunkSize();
        if (
at <= sz) {
          
child.insertInner(atlinesheight);
          if (
child.lines && child.lines.length 50) {
            
// To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
            // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
            
var remaining child.lines.length 25 25;
            for (var 
pos remainingpos child.lines.length;) {
              var 
leaf = new LeafChunk(child.lines.slice(pospos += 25));
              
child.height -= leaf.height;
              
this.children.splice(++i0leaf);
              
leaf.parent this;
            }
            
child.lines child.lines.slice(0remaining);
            
this.maybeSpill();
          }
          break
        }
        
at -= sz;
      }
    },

    
// When a node has grown, check whether it should be split.
    
maybeSpill: function() {
      if (
this.children.length <= 10) { return }
      var 
me this;
      do {
        var 
spilled me.children.splice(me.children.length 55);
        var 
sibling = new BranchChunk(spilled);
        if (!
me.parent) { // Become the parent node
          
var copy = new BranchChunk(me.children);
          
copy.parent me;
          
me.children = [copysibling];
          
me copy;
       } else {
          
me.size -= sibling.size;
          
me.height -= sibling.height;
          var 
myIndex indexOf(me.parent.childrenme);
          
me.parent.children.splice(myIndex 10sibling);
        }
        
sibling.parent me.parent;
      } while (
me.children.length 10)
      
me.parent.maybeSpill();
    },

    
iterN: function(atnop) {
      for (var 
0this.children.length; ++i) {
        var 
child this.children[i], sz child.chunkSize();
        if (
at sz) {
          var 
used Math.min(nsz at);
          if (
child.iterN(atusedop)) { return true }
          if ((
-= used) == 0) { break }
          
at 0;
        } else { 
at -= sz; }
      }
    }
  };

  
// Line widgets are block elements displayed above or below a line.

  
var LineWidget = function(docnodeoptions) {
    if (
options) { for (var opt in options) { if (options.hasOwnProperty(opt))
      { 
this[opt] = options[opt]; } } }
    
this.doc doc;
    
this.node node;
  };

  
LineWidget.prototype.clear = function () {
    var 
cm this.doc.cmws this.line.widgetsline this.lineno lineNo(line);
    if (
no == null || !ws) { return }
    for (var 
0ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } }
    if (!
ws.length) { line.widgets null; }
    var 
height widgetHeight(this);
    
updateLineHeight(lineMath.max(0line.height height));
    if (
cm) {
      
runInOp(cm, function () {
        
adjustScrollWhenAboveVisible(cmline, -height);
        
regLineChange(cmno"widget");
      });
      
signalLater(cm"lineWidgetCleared"cmthisno);
    }
  };

  
LineWidget.prototype.changed = function () {
      var 
this$this;

    var 
oldH this.heightcm this.doc.cmline this.line;
    
this.height null;
    var 
diff widgetHeight(this) - oldH;
    if (!
diff) { return }
    if (!
lineIsHidden(this.docline)) { updateLineHeight(lineline.height diff); }
    if (
cm) {
      
runInOp(cm, function () {
        
cm.curOp.forceUpdate true;
        
adjustScrollWhenAboveVisible(cmlinediff);
        
signalLater(cm"lineWidgetChanged"cmthis$1lineNo(line));
      });
    }
  };
  
eventMixin(LineWidget);

  function 
adjustScrollWhenAboveVisible(cmlinediff) {
    if (
heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
      { 
addToScrollTop(cmdiff); }
  }

  function 
addLineWidget(dochandlenodeoptions) {
    var 
widget = new LineWidget(docnodeoptions);
    var 
cm doc.cm;
    if (
cm && widget.noHScroll) { cm.display.alignWidgets true; }
    
changeLine(dochandle"widget", function (line) {
      var 
widgets line.widgets || (line.widgets = []);
      if (
widget.insertAt == null) { widgets.push(widget); }
      else { 
widgets.splice(Math.min(widgets.length 1Math.max(0widget.insertAt)), 0widget); }
      
widget.line line;
      if (
cm && !lineIsHidden(docline)) {
        var 
aboveVisible heightAtLine(line) < doc.scrollTop;
        
updateLineHeight(lineline.height widgetHeight(widget));
        if (
aboveVisible) { addToScrollTop(cmwidget.height); }
        
cm.curOp.forceUpdate true;
      }
      return 
true
    
});
    if (
cm) { signalLater(cm"lineWidgetAdded"cmwidgettypeof handle == "number" handle lineNo(handle)); }
    return 
widget
  
}

  
// TEXTMARKERS

  // Created with markText and setBookmark methods. A TextMarker is a
  // handle that can be used to clear or find a marked position in the
  // document. Line objects hold arrays (markedSpans) containing
  // {from, to, marker} object pointing to such marker objects, and
  // indicating that such a marker is present on that line. Multiple
  // lines may point to the same marker when it spans across lines.
  // The spans will have null for their from/to properties when the
  // marker continues beyond the start/end of the line. Markers have
  // links back to the lines they currently touch.

  // Collapsed markers have unique ids, in order to be able to order
  // them, which is needed for uniquely determining an outer marker
  // when they overlap (they may nest, but not partially overlap).
  
var nextMarkerId 0;

  var 
TextMarker = function(doctype) {
    
this.lines = [];
    
this.type type;
    
this.doc doc;
    
this.id = ++nextMarkerId;
  };

  
// Clear the marker.
  
TextMarker.prototype.clear = function () {
    if (
this.explicitlyCleared) { return }
    var 
cm this.doc.cmwithOp cm && !cm.curOp;
    if (
withOp) { startOperation(cm); }
    if (
hasHandler(this"clear")) {
      var 
found this.find();
      if (
found) { signalLater(this"clear"found.fromfound.to); }
    }
    var 
min nullmax null;
    for (var 
0this.lines.length; ++i) {
      var 
line this.lines[i];
      var 
span getMarkedSpanFor(line.markedSpansthis);
      if (
cm && !this.collapsed) { regLineChange(cmlineNo(line), "text"); }
      else if (
cm) {
        if (
span.to != null) { max lineNo(line); }
        if (
span.from != null) { min lineNo(line); }
      }
      
line.markedSpans removeMarkedSpan(line.markedSpansspan);
      if (
span.from == null && this.collapsed && !lineIsHidden(this.docline) && cm)
        { 
updateLineHeight(linetextHeight(cm.display)); }
    }
    if (
cm && this.collapsed && !cm.options.lineWrapping) { for (var i$0i$this.lines.length; ++i$1) {
      var 
visual visualLine(this.lines[i$1]), len lineLength(visual);
      if (
len cm.display.maxLineLength) {
        
cm.display.maxLine visual;
        
cm.display.maxLineLength len;
        
cm.display.maxLineChanged true;
      }
    } }

    if (
min != null && cm && this.collapsed) { regChange(cmminmax 1); }
    
this.lines.length 0;
    
this.explicitlyCleared true;
    if (
this.atomic && this.doc.cantEdit) {
      
this.doc.cantEdit false;
      if (
cm) { reCheckSelection(cm.doc); }
    }
    if (
cm) { signalLater(cm"markerCleared"cmthisminmax); }
    if (
withOp) { endOperation(cm); }
    if (
this.parent) { this.parent.clear(); }
  };

  
// Find the position of the marker in the document. Returns a {from,
  // to} object by default. Side can be passed to get a specific side
  // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
  // Pos objects returned contain a line object, rather than a line
  // number (used to prevent looking up the same line twice).
  
TextMarker.prototype.find = function (sidelineObj) {
    if (
side == null && this.type == "bookmark") { side 1; }
    var 
fromto;
    for (var 
0this.lines.length; ++i) {
      var 
line this.lines[i];
      var 
span getMarkedSpanFor(line.markedSpansthis);
      if (
span.from != null) {
        
from Pos(lineObj line lineNo(line), span.from);
        if (
side == -1) { return from }
      }
      if (
span.to != null) {
        
to Pos(lineObj line lineNo(line), span.to);
        if (
side == 1) { return to }
      }
    }
    return 
from && {fromfromtoto}
  };

  
// Signals that the marker's widget changed, and surrounding layout
  // should be recomputed.
  
TextMarker.prototype.changed = function () {
      var 
this$this;

    var 
pos this.find(-1true), widget thiscm this.doc.cm;
    if (!
pos || !cm) { return }
    
runInOp(cm, function () {
      var 
line pos.linelineN lineNo(pos.line);
      var 
view findViewForLine(cmlineN);
      if (
view) {
        
clearLineMeasurementCacheFor(view);
        
cm.curOp.selectionChanged cm.curOp.forceUpdate true;
      }
      
cm.curOp.updateMaxLine true;
      if (!
lineIsHidden(widget.docline) && widget.height != null) {
        var 
oldHeight widget.height;
        
widget.height null;
        var 
dHeight widgetHeight(widget) - oldHeight;
        if (
dHeight)
          { 
updateLineHeight(lineline.height dHeight); }
      }
      
signalLater(cm"markerChanged"cmthis$1);
    });
  };

  
TextMarker.prototype.attachLine = function (line) {
    if (!
this.lines.length && this.doc.cm) {
      var 
op this.doc.cm.curOp;
      if (!
op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkersthis) == -1)
        { (
op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
    }
    
this.lines.push(line);
  };

  
TextMarker.prototype.detachLine = function (line) {
    
this.lines.splice(indexOf(this.linesline), 1);
    if (!
this.lines.length && this.doc.cm) {
      var 
op this.doc.cm.curOp
      
;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
    }
  };
  
eventMixin(TextMarker);

  
// Create a marker, wire it up to the right lines, and
  
function markText(docfromtooptionstype) {
    
// Shared markers (across linked documents) are handled separately
    // (markTextShared will call out to this again, once per
    // document).
    
if (options && options.shared) { return markTextShared(docfromtooptionstype) }
    
// Ensure we are in an operation.
    
if (doc.cm && !doc.cm.curOp) { return operation(doc.cmmarkText)(docfromtooptionstype) }

    var 
marker = new TextMarker(doctype), diff cmp(fromto);
    if (
options) { copyObj(optionsmarkerfalse); }
    
// Don't connect empty markers unless clearWhenEmpty is false
    
if (diff || diff == && marker.clearWhenEmpty !== false)
      { return 
marker }
    if (
marker.replacedWith) {
      
// Showing up as a widget implies collapsed (widget replaces text)
      
marker.collapsed true;
      
marker.widgetNode eltP("span", [marker.replacedWith], "CodeMirror-widget");
      if (!
options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events""true"); }
      if (
options.insertLeft) { marker.widgetNode.insertLeft true; }
    }
    if (
marker.collapsed) {
      if (
conflictingCollapsedRange(docfrom.linefromtomarker) ||
          
from.line != to.line && conflictingCollapsedRange(docto.linefromtomarker))
        { throw new 
Error("Inserting collapsed marker partially overlapping an existing one") }
      
seeCollapsedSpans();
    }

    if (
marker.addToHistory)
      { 
addChangeToHistory(doc, {fromfromtotoorigin"markText"}, doc.selNaN); }

    var 
curLine from.linecm doc.cmupdateMaxLine;
    
doc.iter(curLineto.line 1, function (line) {
      if (
cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
        { 
updateMaxLine true; }
      if (
marker.collapsed && curLine != from.line) { updateLineHeight(line0); }
      
addMarkedSpan(line, new MarkedSpan(marker,
                                         
curLine == from.line from.ch null,
                                         
curLine == to.line to.ch null));
      ++
curLine;
    });
    
// lineIsHidden depends on the presence of the spans, so needs a second pass
    
if (marker.collapsed) { doc.iter(from.lineto.line 1, function (line) {
      if (
lineIsHidden(docline)) { updateLineHeight(line0); }
    }); }

    if (
marker.clearOnEnter) { on(marker"beforeCursorEnter", function () { return marker.clear(); }); }

    if (
marker.readOnly) {
      
seeReadOnlySpans();
      if (
doc.history.done.length || doc.history.undone.length)
        { 
doc.clearHistory(); }
    }
    if (
marker.collapsed) {
      
marker.id = ++nextMarkerId;
      
marker.atomic true;
    }
    if (
cm) {
      
// Sync editor state
      
if (updateMaxLine) { cm.curOp.updateMaxLine true; }
      if (
marker.collapsed)
        { 
regChange(cmfrom.lineto.line 1); }
      else if (
marker.className || marker.startStyle || marker.endStyle || marker.css ||
               
marker.attributes || marker.title)
        { for (var 
from.line<= to.linei++) { regLineChange(cmi"text"); } }
      if (
marker.atomic) { reCheckSelection(cm.doc); }
      
signalLater(cm"markerAdded"cmmarker);
    }
    return 
marker
  
}

  
// SHARED TEXTMARKERS

  // A shared marker spans multiple linked documents. It is
  // implemented as a meta-marker-object controlling multiple normal
  // markers.
  
var SharedTextMarker = function(markersprimary) {
    
this.markers markers;
    
this.primary primary;
    for (var 
0markers.length; ++i)
      { 
markers[i].parent this; }
  };

  
SharedTextMarker.prototype.clear = function () {
    if (
this.explicitlyCleared) { return }
    
this.explicitlyCleared true;
    for (var 
0this.markers.length; ++i)
      { 
this.markers[i].clear(); }
    
signalLater(this"clear");
  };

  
SharedTextMarker.prototype.find = function (sidelineObj) {
    return 
this.primary.find(sidelineObj)
  };
  
eventMixin(SharedTextMarker);

  function 
markTextShared(docfromtooptionstype) {
    
options copyObj(options);
    
options.shared false;
    var 
markers = [markText(docfromtooptionstype)], primary markers[0];
    var 
widget options.widgetNode;
    
linkedDocs(doc, function (doc) {
      if (
widget) { options.widgetNode widget.cloneNode(true); }
      
markers.push(markText(docclipPos(docfrom), clipPos(docto), optionstype));
      for (var 
0doc.linked.length; ++i)
        { if (
doc.linked[i].isParent) { return } }
      
primary lst(markers);
    });
    return new 
SharedTextMarker(markersprimary)
  }

  function 
findSharedMarkers(doc) {
    return 
doc.findMarks(Pos(doc.first0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
  }

  function 
copySharedMarkers(docmarkers) {
    for (var 
0markers.lengthi++) {
      var 
marker markers[i], pos marker.find();
      var 
mFrom doc.clipPos(pos.from), mTo doc.clipPos(pos.to);
      if (
cmp(mFrommTo)) {
        var 
subMark markText(docmFrommTomarker.primarymarker.primary.type);
        
marker.markers.push(subMark);
        
subMark.parent marker;
      }
    }
  }

  function 
detachSharedMarkers(markers) {
    var 
loop = function ( ) {
      var 
marker markers[i], linked = [marker.primary.doc];
      
linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
      for (var 
0marker.markers.lengthj++) {
        var 
subMarker marker.markers[j];
        if (
indexOf(linkedsubMarker.doc) == -1) {
          
subMarker.parent null;
          
marker.markers.splice(j--, 1);
        }
      }
    };

    for (var 
0markers.lengthi++) loop);
  }

  var 
nextDocId 0;
  var 
Doc = function(textmodefirstLinelineSepdirection) {
    if (!(
this instanceof Doc)) { return new Doc(textmodefirstLinelineSepdirection) }
    if (
firstLine == null) { firstLine 0; }

    
BranchChunk.call(this, [new LeafChunk([new Line(""null)])]);
    
this.first firstLine;
    
this.scrollTop this.scrollLeft 0;
    
this.cantEdit false;
    
this.cleanGeneration 1;
    
this.modeFrontier this.highlightFrontier firstLine;
    var 
start Pos(firstLine0);
    
this.sel simpleSelection(start);
    
this.history = new History(null);
    
this.id = ++nextDocId;
    
this.modeOption mode;
    
this.lineSep lineSep;
    
this.direction = (direction == "rtl") ? "rtl" "ltr";
    
this.extend false;

    if (
typeof text == "string") { text this.splitLines(text); }
    
updateDoc(this, {fromstarttostarttexttext});
    
setSelection(thissimpleSelection(start), sel_dontScroll);
  };

  
Doc.prototype createObj(BranchChunk.prototype, {
    
constructorDoc,
    
// Iterate over the document. Supports two forms -- with only one
    // argument, it calls that for each line in the document. With
    // three, it iterates over the range given by the first two (with
    // the second being non-inclusive).
    
iter: function(fromtoop) {
      if (
op) { this.iterN(from this.firstto fromop); }
      else { 
this.iterN(this.firstthis.first this.sizefrom); }
    },

    
// Non-public interface for adding and removing lines.
    
insert: function(atlines) {
      var 
height 0;
      for (var 
0lines.length; ++i) { height += lines[i].height; }
      
this.insertInner(at this.firstlinesheight);
    },
    
remove: function(atn) { this.removeInner(at this.firstn); },

    
// From here, the methods are part of the public interface. Most
    // are also available from CodeMirror (editor) instances.

    
getValue: function(lineSep) {
      var 
lines getLines(thisthis.firstthis.first this.size);
      if (
lineSep === false) { return lines }
      return 
lines.join(lineSep || this.lineSeparator())
    },
    
setValuedocMethodOp(function(code) {
      var 
top Pos(this.first0), last this.first this.size 1;
      
makeChange(this, {fromtoptoPos(lastgetLine(thislast).text.length),
                        
textthis.splitLines(code), origin"setValue"fulltrue}, true);
      if (
this.cm) { scrollToCoords(this.cm00); }
      
setSelection(thissimpleSelection(top), sel_dontScroll);
    }),
    
replaceRange: function(codefromtoorigin) {
      
from clipPos(thisfrom);
      
to to clipPos(thisto) : from;
      
replaceRange(thiscodefromtoorigin);
    },
    
getRange: function(fromtolineSep) {
      var 
lines getBetween(thisclipPos(thisfrom), clipPos(thisto));
      if (
lineSep === false) { return lines }
      return 
lines.join(lineSep || this.lineSeparator())
    },

    
getLine: function(line) {var this.getLineHandle(line); return && l.text},

    
getLineHandle: function(line) {if (isLine(thisline)) { return getLine(thisline) }},
    
getLineNumber: function(line) {return lineNo(line)},

    
getLineHandleVisualStart: function(line) {
      if (
typeof line == "number") { line getLine(thisline); }
      return 
visualLine(line)
    },

    
lineCount: function() {return this.size},
    
firstLine: function() {return this.first},
    
lastLine: function() {return this.first this.size 1},

    
clipPos: function(pos) {return clipPos(thispos)},

    
getCursor: function(start) {
      var 
range this.sel.primary(), pos;
      if (
start == null || start == "head") { pos range.head; }
      else if (
start == "anchor") { pos range.anchor; }
      else if (
start == "end" || start == "to" || start === false) { pos range.to(); }
      else { 
pos range.from(); }
      return 
pos
    
},
    
listSelections: function() { return this.sel.ranges },
    
somethingSelected: function() {return this.sel.somethingSelected()},

    
setCursordocMethodOp(function(linechoptions) {
      
setSimpleSelection(thisclipPos(thistypeof line == "number" Pos(linech || 0) : line), nulloptions);
    }),
    
setSelectiondocMethodOp(function(anchorheadoptions) {
      
setSimpleSelection(thisclipPos(thisanchor), clipPos(thishead || anchor), options);
    }),
    
extendSelectiondocMethodOp(function(headotheroptions) {
      
extendSelection(thisclipPos(thishead), other && clipPos(thisother), options);
    }),
    
extendSelectionsdocMethodOp(function(headsoptions) {
      
extendSelections(thisclipPosArray(thisheads), options);
    }),
    
extendSelectionsBydocMethodOp(function(foptions) {
      var 
heads map(this.sel.rangesf);
      
extendSelections(thisclipPosArray(thisheads), options);
    }),
    
setSelectionsdocMethodOp(function(rangesprimaryoptions) {
      if (!
ranges.length) { return }
      var 
out = [];
      for (var 
0ranges.lengthi++)
        { 
out[i] = new Range(clipPos(thisranges[i].anchor),
                           
clipPos(thisranges[i].head)); }
      if (
primary == null) { primary Math.min(ranges.length 1this.sel.primIndex); }
      
setSelection(thisnormalizeSelection(this.cmoutprimary), options);
    }),
    
addSelectiondocMethodOp(function(anchorheadoptions) {
      var 
ranges this.sel.ranges.slice(0);
      
ranges.push(new Range(clipPos(thisanchor), clipPos(thishead || anchor)));
      
setSelection(thisnormalizeSelection(this.cmrangesranges.length 1), options);
    }),

    
getSelection: function(lineSep) {
      var 
ranges this.sel.rangeslines;
      for (var 
0ranges.lengthi++) {
        var 
sel getBetween(thisranges[i].from(), ranges[i].to());
        
lines lines lines.concat(sel) : sel;
      }
      if (
lineSep === false) { return lines }
      else { return 
lines.join(lineSep || this.lineSeparator()) }
    },
    
getSelections: function(lineSep) {
      var 
parts = [], ranges this.sel.ranges;
      for (var 
0ranges.lengthi++) {
        var 
sel getBetween(thisranges[i].from(), ranges[i].to());
        if (
lineSep !== false) { sel sel.join(lineSep || this.lineSeparator()); }
        
parts[i] = sel;
      }
      return 
parts
    
},
    
replaceSelection: function(codecollapseorigin) {
      var 
dup = [];
      for (var 
0this.sel.ranges.lengthi++)
        { 
dup[i] = code; }
      
this.replaceSelections(dupcollapseorigin || "+input");
    },
    
replaceSelectionsdocMethodOp(function(codecollapseorigin) {
      var 
changes = [], sel this.sel;
      for (var 
0sel.ranges.lengthi++) {
        var 
range sel.ranges[i];
        
changes[i] = {fromrange.from(), torange.to(), textthis.splitLines(code[i]), originorigin};
      }
      var 
newSel collapse && collapse != "end" && computeReplacedSel(thischangescollapse);
      for (var 
i$changes.length 1i$>= 0i$1--)
        { 
makeChange(thischanges[i$1]); }
      if (
newSel) { setSelectionReplaceHistory(thisnewSel); }
      else if (
this.cm) { ensureCursorVisible(this.cm); }
    }),
    
undodocMethodOp(function() {makeChangeFromHistory(this"undo");}),
    
redodocMethodOp(function() {makeChangeFromHistory(this"redo");}),
    
undoSelectiondocMethodOp(function() {makeChangeFromHistory(this"undo"true);}),
    
redoSelectiondocMethodOp(function() {makeChangeFromHistory(this"redo"true);}),

    
setExtending: function(val) {this.extend val;},
    
getExtending: function() {return this.extend},

    
historySize: function() {
      var 
hist this.historydone 0undone 0;
      for (var 
0hist.done.lengthi++) { if (!hist.done[i].ranges) { ++done; } }
      for (var 
i$0i$hist.undone.lengthi$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
      return {
undodoneredoundone}
    },
    
clearHistory: function() {
      var 
this$this;

      
this.history = new History(this.history.maxGeneration);
      
linkedDocs(this, function (doc) { return doc.history this$1.history; }, true);
    },

    
markClean: function() {
      
this.cleanGeneration this.changeGeneration(true);
    },
    
changeGeneration: function(forceSplit) {
      if (
forceSplit)
        { 
this.history.lastOp this.history.lastSelOp this.history.lastOrigin null; }
      return 
this.history.generation
    
},
    
isClean: function (gen) {
      return 
this.history.generation == (gen || this.cleanGeneration)
    },

    
getHistory: function() {
      return {
donecopyHistoryArray(this.history.done),
              
undonecopyHistoryArray(this.history.undone)}
    },
    
setHistory: function(histData) {
      var 
hist this.history = new History(this.history.maxGeneration);
      
hist.done copyHistoryArray(histData.done.slice(0), nulltrue);
      
hist.undone copyHistoryArray(histData.undone.slice(0), nulltrue);
    },

    
setGutterMarkerdocMethodOp(function(linegutterIDvalue) {
      return 
changeLine(thisline"gutter", function (line) {
        var 
markers line.gutterMarkers || (line.gutterMarkers = {});
        
markers[gutterID] = value;
        if (!
value && isEmpty(markers)) { line.gutterMarkers null; }
        return 
true
      
})
    }),

    
clearGutterdocMethodOp(function(gutterID) {
      var 
this$this;

      
this.iter(function (line) {
        if (
line.gutterMarkers && line.gutterMarkers[gutterID]) {
          
changeLine(this$1line"gutter", function () {
            
line.gutterMarkers[gutterID] = null;
            if (
isEmpty(line.gutterMarkers)) { line.gutterMarkers null; }
            return 
true
          
});
        }
      });
    }),

    
lineInfo: function(line) {
      var 
n;
      if (
typeof line == "number") {
        if (!
isLine(thisline)) { return null }
        
line;
        
line getLine(thisline);
        if (!
line) { return null }
      } else {
        
lineNo(line);
        if (
== null) { return null }
      }
      return {
linenhandlelinetextline.textgutterMarkersline.gutterMarkers,
              
textClassline.textClassbgClassline.bgClasswrapClassline.wrapClass,
              
widgetsline.widgets}
    },

    
addLineClassdocMethodOp(function(handlewherecls) {
      return 
changeLine(thishandlewhere == "gutter" "gutter" "class", function (line) {
        var 
prop where == "text" "textClass"
                 
where == "background" "bgClass"
                 
where == "gutter" "gutterClass" "wrapClass";
        if (!
line[prop]) { line[prop] = cls; }
        else if (
classTest(cls).test(line[prop])) { return false }
        else { 
line[prop] += " " cls; }
        return 
true
      
})
    }),
    
removeLineClassdocMethodOp(function(handlewherecls) {
      return 
changeLine(thishandlewhere == "gutter" "gutter" "class", function (line) {
        var 
prop where == "text" "textClass"
                 
where == "background" "bgClass"
                 
where == "gutter" "gutterClass" "wrapClass";
        var 
cur line[prop];
        if (!
cur) { return false }
        else if (
cls == null) { line[prop] = null; }
        else {
          var 
found cur.match(classTest(cls));
          if (!
found) { return false }
          var 
end found.index found[0].length;
          
line[prop] = cur.slice(0found.index) + (!found.index || end == cur.length "" " ") + cur.slice(end) || null;
        }
        return 
true
      
})
    }),

    
addLineWidgetdocMethodOp(function(handlenodeoptions) {
      return 
addLineWidget(thishandlenodeoptions)
    }),
    
removeLineWidget: function(widget) { widget.clear(); },

    
markText: function(fromtooptions) {
      return 
markText(thisclipPos(thisfrom), clipPos(thisto), optionsoptions && options.type || "range")
    },
    
setBookmark: function(posoptions) {
      var 
realOpts = {replacedWithoptions && (options.nodeType == null options.widget options),
                      
insertLeftoptions && options.insertLeft,
                      
clearWhenEmptyfalsesharedoptions && options.shared,
                      
handleMouseEventsoptions && options.handleMouseEvents};
      
pos clipPos(thispos);
      return 
markText(thisposposrealOpts"bookmark")
    },
    
findMarksAt: function(pos) {
      
pos clipPos(thispos);
      var 
markers = [], spans getLine(thispos.line).markedSpans;
      if (
spans) { for (var 0spans.length; ++i) {
        var 
span spans[i];
        if ((
span.from == null || span.from <= pos.ch) &&
            (
span.to == null || span.to >= pos.ch))
          { 
markers.push(span.marker.parent || span.marker); }
      } }
      return 
markers
    
},
    
findMarks: function(fromtofilter) {
      
from clipPos(thisfrom); to clipPos(thisto);
      var 
found = [], lineNo from.line;
      
this.iter(from.lineto.line 1, function (line) {
        var 
spans line.markedSpans;
        if (
spans) { for (var 0spans.lengthi++) {
          var 
span spans[i];
          if (!(
span.to != null && lineNo == from.line && from.ch >= span.to ||
                
span.from == null && lineNo != from.line ||
                
span.from != null && lineNo == to.line && span.from >= to.ch) &&
              (!
filter || filter(span.marker)))
            { 
found.push(span.marker.parent || span.marker); }
        } }
        ++
lineNo;
      });
      return 
found
    
},
    
getAllMarks: function() {
      var 
markers = [];
      
this.iter(function (line) {
        var 
sps line.markedSpans;
        if (
sps) { for (var 0sps.length; ++i)
          { if (
sps[i].from != null) { markers.push(sps[i].marker); } } }
      });
      return 
markers
    
},

    
posFromIndex: function(off) {
      var 
chlineNo this.firstsepSize this.lineSeparator().length;
      
this.iter(function (line) {
        var 
sz line.text.length sepSize;
        if (
sz off) { ch off; return true }
        
off -= sz;
        ++
lineNo;
      });
      return 
clipPos(thisPos(lineNoch))
    },
    
indexFromPos: function (coords) {
      
coords clipPos(thiscoords);
      var 
index coords.ch;
      if (
coords.line this.first || coords.ch 0) { return }
      var 
sepSize this.lineSeparator().length;
      
this.iter(this.firstcoords.line, function (line) { // iter aborts when callback returns a truthy value
        
index += line.text.length sepSize;
      });
      return 
index
    
},

    
copy: function(copyHistory) {
      var 
doc = new Doc(getLines(thisthis.firstthis.first this.size),
                        
this.modeOptionthis.firstthis.lineSepthis.direction);
      
doc.scrollTop this.scrollTopdoc.scrollLeft this.scrollLeft;
      
doc.sel this.sel;
      
doc.extend false;
      if (
copyHistory) {
        
doc.history.undoDepth this.history.undoDepth;
        
doc.setHistory(this.getHistory());
      }
      return 
doc
    
},

    
linkedDoc: function(options) {
      if (!
options) { options = {}; }
      var 
from this.firstto this.first this.size;
      if (
options.from != null && options.from from) { from options.from; }
      if (
options.to != null && options.to to) { to options.to; }
      var 
copy = new Doc(getLines(thisfromto), options.mode || this.modeOptionfromthis.lineSepthis.direction);
      if (
options.sharedHist) { copy.history this.history
      
; }(this.linked || (this.linked = [])).push({doccopysharedHistoptions.sharedHist});
      
copy.linked = [{docthisisParenttruesharedHistoptions.sharedHist}];
      
copySharedMarkers(copyfindSharedMarkers(this));
      return 
copy
    
},
    
unlinkDoc: function(other) {
      if (
other instanceof CodeMirror) { other other.doc; }
      if (
this.linked) { for (var 0this.linked.length; ++i) {
        var 
link this.linked[i];
        if (
link.doc != other) { continue }
        
this.linked.splice(i1);
        
other.unlinkDoc(this);
        
detachSharedMarkers(findSharedMarkers(this));
        break
      } }
      
// If the histories were shared, split them again
      
if (other.history == this.history) {
        var 
splitIds = [other.id];
        
linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
        
other.history = new History(null);
        
other.history.done copyHistoryArray(this.history.donesplitIds);
        
other.history.undone copyHistoryArray(this.history.undonesplitIds);
      }
    },
    
iterLinkedDocs: function(f) {linkedDocs(thisf);},

    
getMode: function() {return this.mode},
    
getEditor: function() {return this.cm},

    
splitLines: function(str) {
      if (
this.lineSep) { return str.split(this.lineSep) }
      return 
splitLinesAuto(str)
    },
    
lineSeparator: function() { return this.lineSep || "n" },

    
setDirectiondocMethodOp(function (dir) {
      if (
dir != "rtl") { dir "ltr"; }
      if (
dir == this.direction) { return }
      
this.direction dir;
      
this.iter(function (line) { return line.order null; });
      if (
this.cm) { directionChanged(this.cm); }
    })
  });

  
// Public alias.
  
Doc.prototype.eachLine Doc.prototype.iter;

  
// Kludge to work around strange IE behavior where it'll sometimes
  // re-fire a series of drag-related events right after the drop (#1551)
  
var lastDrop 0;

  function 
onDrop(e) {
    var 
cm this;
    
clearDragCursor(cm);
    if (
signalDOMEvent(cme) || eventInWidget(cm.displaye))
      { return }
    
e_preventDefault(e);
    if (
ie) { lastDrop = +new Date; }
    var 
pos posFromMouse(cmetrue), files e.dataTransfer.files;
    if (!
pos || cm.isReadOnly()) { return }
    
// Might be a file drop, in which case we simply extract the text
    // and insert it.
    
if (files && files.length && window.FileReader && window.File) {
      var 
files.lengthtext = Array(n), read 0;
      var 
markAsReadAndPasteIfAllFilesAreRead = function () {
        if (++
read == n) {
          
operation(cm, function () {
            
pos clipPos(cm.docpos);
            var 
change = {frompostopos,
                          
textcm.doc.splitLines(
                              
text.filter(function (t) { return != null; }).join(cm.doc.lineSeparator())),
                          
origin"paste"};
            
makeChange(cm.docchange);
            
setSelectionReplaceHistory(cm.docsimpleSelection(clipPos(cm.docpos), clipPos(cm.docchangeEnd(change))));
          })();
        }
      };
      var 
readTextFromFile = function (filei) {
        if (
cm.options.allowDropFileTypes &&
            
indexOf(cm.options.allowDropFileTypesfile.type) == -1) {
          
markAsReadAndPasteIfAllFilesAreRead();
          return
        }
        var 
reader = new FileReader;
        
reader.onerror = function () { return markAsReadAndPasteIfAllFilesAreRead(); };
        
reader.onload = function () {
          var 
content reader.result;
          if (/[
x00-x08x0e-x1f]{2}/.test(content)) {
            
markAsReadAndPasteIfAllFilesAreRead();
            return
          }
          
text[i] = content;
          
markAsReadAndPasteIfAllFilesAreRead();
        };
        
reader.readAsText(file);
      };
      for (var 
0files.lengthi++) { readTextFromFile(files[i], i); }
    } else { 
// Normal drop
      // Don't do a replace if the drop happened inside of the selected text.
      
if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
        
cm.state.draggingText(e);
        
// Ensure the editor is re-focused
        
setTimeout(function () { return cm.display.input.focus(); }, 20);
        return
      }
      try {
        var 
text$e.dataTransfer.getData("Text");
        if (
text$1) {
          var 
selected;
          if (
cm.state.draggingText && !cm.state.draggingText.copy)
            { 
selected cm.listSelections(); }
          
setSelectionNoUndo(cm.docsimpleSelection(pospos));
          if (
selected) { for (var i$0i$selected.length; ++i$1)
            { 
replaceRange(cm.doc""selected[i$1].anchorselected[i$1].head"drag"); } }
          
cm.replaceSelection(text$1"around""paste");
          
cm.display.input.focus();
        }
      }
      catch(
e){}
    }
  }

  function 
onDragStart(cme) {
    if (
ie && (!cm.state.draggingText || +new Date lastDrop 100)) { e_stop(e); return }
    if (
signalDOMEvent(cme) || eventInWidget(cm.displaye)) { return }

    
e.dataTransfer.setData("Text"cm.getSelection());
    
e.dataTransfer.effectAllowed "copyMove";

    
// Use dummy image instead of default browsers image.
    // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
    
if (e.dataTransfer.setDragImage && !safari) {
      var 
img elt("img"nullnull"position: fixed; left: 0; top: 0;");
      
img.src "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
      if (
presto) {
        
img.width img.height 1;
        
cm.display.wrapper.appendChild(img);
        
// Force a relayout, or Opera won't use our image for some obscure reason
        
img._top img.offsetTop;
      }
      
e.dataTransfer.setDragImage(img00);
      if (
presto) { img.parentNode.removeChild(img); }
    }
  }

  function 
onDragOver(cme) {
    var 
pos posFromMouse(cme);
    if (!
pos) { return }
    var 
frag document.createDocumentFragment();
    
drawSelectionCursor(cmposfrag);
    if (!
cm.display.dragCursor) {
      
cm.display.dragCursor elt("div"null"CodeMirror-cursors CodeMirror-dragcursors");
      
cm.display.lineSpace.insertBefore(cm.display.dragCursorcm.display.cursorDiv);
    }
    
removeChildrenAndAdd(cm.display.dragCursorfrag);
  }

  function 
clearDragCursor(cm) {
    if (
cm.display.dragCursor) {
      
cm.display.lineSpace.removeChild(cm.display.dragCursor);
      
cm.display.dragCursor null;
    }
  }

  
// These must be handled carefully, because naively registering a
  // handler for each editor will cause the editors to never be
  // garbage collected.

  
function forEachCodeMirror(f) {
    if (!
document.getElementsByClassName) { return }
    var 
byClass document.getElementsByClassName("CodeMirror"), editors = [];
    for (var 
0byClass.lengthi++) {
      var 
cm byClass[i].CodeMirror;
      if (
cm) { editors.push(cm); }
    }
    if (
editors.length) { editors[0].operation(function () {
      for (var 
0editors.lengthi++) { f(editors[i]); }
    }); }
  }

  var 
globalsRegistered false;
  function 
ensureGlobalHandlers() {
    if (
globalsRegistered) { return }
    
registerGlobalHandlers();
    
globalsRegistered true;
  }
  function 
registerGlobalHandlers() {
    
// When the window resizes, we need to refresh active editors.
    
var resizeTimer;
    
on(window"resize", function () {
      if (
resizeTimer == null) { resizeTimer setTimeout(function () {
        
resizeTimer null;
        
forEachCodeMirror(onResize);
      }, 
100); }
    });
    
// When the window loses focus, we want to show the editor as blurred
    
on(window"blur", function () { return forEachCodeMirror(onBlur); });
  }
  
// Called when the window resizes
  
function onResize(cm) {
    var 
cm.display;
    
// Might be a text scaling operation, clear size caches.
    
d.cachedCharWidth d.cachedTextHeight d.cachedPaddingH null;
    
d.scrollbarsClipped false;
    
cm.setSize();
  }

  var 
keyNames = {
    
3"Pause"8"Backspace"9"Tab"13"Enter"16"Shift"17"Ctrl"18"Alt",
    
19"Pause"20"CapsLock"27"Esc"32"Space"33"PageUp"34"PageDown"35"End",
    
36"Home"37"Left"38"Up"39"Right"40"Down"44"PrintScrn"45"Insert",
    
46"Delete"59";"61"="91"Mod"92"Mod"93"Mod",
    
106"*"107"="109"-"110"."111"/"145"ScrollLock",
    
173"-"186";"187"="188","189"-"190"."191"/"192"`"219"["220"\",
    221: "
]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
    63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
  };

  // Number keys
  for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
  // Alphabetic keys
  for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
  // Function keys
  for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }

  var keyMap = {};

  keyMap.basic = {
    "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
    "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
    "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
    "Tab": "defaultTab", "Shift-Tab": "indentAuto",
    "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
    "Esc": "singleSelection"
  };
  // Note that the save and find-related commands aren'
t defined by
  
// default. User code or addons can define them. Unknown commands
  // are simply ignored.
  
keyMap.pcDefault = {
    
"Ctrl-A""selectAll""Ctrl-D""deleteLine""Ctrl-Z""undo""Shift-Ctrl-Z""redo""Ctrl-Y""redo",
    
"Ctrl-Home""goDocStart""Ctrl-End""goDocEnd""Ctrl-Up""goLineUp""Ctrl-Down""goLineDown",
    
"Ctrl-Left""goGroupLeft""Ctrl-Right""goGroupRight""Alt-Left""goLineStart""Alt-Right""goLineEnd",
    
"Ctrl-Backspace""delGroupBefore""Ctrl-Delete""delGroupAfter""Ctrl-S""save""Ctrl-F""find",
    
"Ctrl-G""findNext""Shift-Ctrl-G""findPrev""Shift-Ctrl-F""replace""Shift-Ctrl-R""replaceAll",
    
"Ctrl-[""indentLess""Ctrl-]""indentMore",
    
"Ctrl-U""undoSelection""Shift-Ctrl-U""redoSelection""Alt-U""redoSelection",
    
"fallthrough""basic"
  
};
  
// Very basic readline/emacs-style bindings, which are standard on Mac.
  
keyMap.emacsy = {
    
"Ctrl-F""goCharRight""Ctrl-B""goCharLeft""Ctrl-P""goLineUp""Ctrl-N""goLineDown",
    
"Alt-F""goWordRight""Alt-B""goWordLeft""Ctrl-A""goLineStart""Ctrl-E""goLineEnd",
    
"Ctrl-V""goPageDown""Shift-Ctrl-V""goPageUp""Ctrl-D""delCharAfter""Ctrl-H""delCharBefore",
    
"Alt-D""delWordAfter""Alt-Backspace""delWordBefore""Ctrl-K""killLine""Ctrl-T""transposeChars",
    
"Ctrl-O""openLine"
  
};
  
keyMap.macDefault = {
    
"Cmd-A""selectAll""Cmd-D""deleteLine""Cmd-Z""undo""Shift-Cmd-Z""redo""Cmd-Y""redo",
    
"Cmd-Home""goDocStart""Cmd-Up""goDocStart""Cmd-End""goDocEnd""Cmd-Down""goDocEnd""Alt-Left""goGroupLeft",
    
"Alt-Right""goGroupRight""Cmd-Left""goLineLeft""Cmd-Right""goLineRight""Alt-Backspace""delGroupBefore",
    
"Ctrl-Alt-Backspace""delGroupAfter""Alt-Delete""delGroupAfter""Cmd-S""save""Cmd-F""find",
    
"Cmd-G""findNext""Shift-Cmd-G""findPrev""Cmd-Alt-F""replace""Shift-Cmd-Alt-F""replaceAll",
    
"Cmd-[""indentLess""Cmd-]""indentMore""Cmd-Backspace""delWrappedLineLeft""Cmd-Delete""delWrappedLineRight",
    
"Cmd-U""undoSelection""Shift-Cmd-U""redoSelection""Ctrl-Up""goDocStart""Ctrl-Down""goDocEnd",
    
"fallthrough": ["basic""emacsy"]
  };
  
keyMap["default"] = mac keyMap.macDefault keyMap.pcDefault;

  
// KEYMAP DISPATCH

  
function normalizeKeyName(name) {
    var 
parts name.split(/-(?!$)/);
    
name parts[parts.length 1];
    var 
altctrlshiftcmd;
    for (var 
0parts.length 1i++) {
      var 
mod parts[i];
      if (/^(
cmd|meta|m)$/i.test(mod)) { cmd true; }
      else if (/^
a(lt)?$/i.test(mod)) { alt true; }
      else if (/^(
c|ctrl|control)$/i.test(mod)) { ctrl true; }
      else if (/^
s(hift)?$/i.test(mod)) { shift true; }
      else { throw new 
Error("Unrecognized modifier name: " mod) }
    }
    if (
alt) { name "Alt-" name; }
    if (
ctrl) { name "Ctrl-" name; }
    if (
cmd) { name "Cmd-" name; }
    if (
shift) { name "Shift-" name; }
    return 
name
  
}

  
// This is a kludge to keep keymaps mostly working as raw objects
  // (backwards compatibility) while at the same time support features
  // like normalization and multi-stroke key bindings. It compiles a
  // new normalized keymap, and then updates the old object to reflect
  // this.
  
function normalizeKeyMap(keymap) {
    var 
copy = {};
    for (var 
keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
      var 
value keymap[keyname];
      if (/^(
name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
      if (
value == "...") { delete keymap[keyname]; continue }

      var 
keys map(keyname.split(" "), normalizeKeyName);
      for (var 
0keys.lengthi++) {
        var 
val = (void 0), name = (void 0);
        if (
== keys.length 1) {
          
name keys.join(" ");
          
val value;
        } else {
          
name keys.slice(01).join(" ");
          
val "...";
        }
        var 
prev copy[name];
        if (!
prev) { copy[name] = val; }
        else if (
prev != val) { throw new Error("Inconsistent bindings for " name) }
      }
      
delete keymap[keyname];
    } }
    for (var 
prop in copy) { keymap[prop] = copy[prop]; }
    return 
keymap
  
}

  function 
lookupKey(keymaphandlecontext) {
    
map getKeyMap(map);
    var 
found map.call map.call(keycontext) : map[key];
    if (
found === false) { return "nothing" }
    if (
found === "...") { return "multi" }
    if (
found != null && handle(found)) { return "handled" }

    if (
map.fallthrough) {
      if (
Object.prototype.toString.call(map.fallthrough) != "[object Array]")
        { return 
lookupKey(keymap.fallthroughhandlecontext) }
      for (var 
0map.fallthrough.lengthi++) {
        var 
result lookupKey(keymap.fallthrough[i], handlecontext);
        if (
result) { return result }
      }
    }
  }

  
// Modifier key presses don't count as 'real' key presses for the
  // purpose of keymap fallthrough.
  
function isModifierKey(value) {
    var 
name typeof value == "string" value keyNames[value.keyCode];
    return 
name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
  
}

  function 
addModifierNames(nameeventnoShift) {
    var 
base name;
    if (
event.altKey && base != "Alt") { name "Alt-" name; }
    if ((
flipCtrlCmd event.metaKey event.ctrlKey) && base != "Ctrl") { name "Ctrl-" name; }
    if ((
flipCtrlCmd event.ctrlKey event.metaKey) && base != "Cmd") { name "Cmd-" name; }
    if (!
noShift && event.shiftKey && base != "Shift") { name "Shift-" name; }
    return 
name
  
}

  
// Look up the name of a key as indicated by an event object.
  
function keyName(eventnoShift) {
    if (
presto && event.keyCode == 34 && event["char"]) { return false }
    var 
name keyNames[event.keyCode];
    if (
name == null || event.altGraphKey) { return false }
    
// Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
    // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
    
if (event.keyCode == && event.code) { name event.code; }
    return 
addModifierNames(nameeventnoShift)
  }

  function 
getKeyMap(val) {
    return 
typeof val == "string" keyMap[val] : val
  
}

  
// Helper for deleting text near the selection(s), used to implement
  // backspace, delete, and similar functionality.
  
function deleteNearSelection(cmcompute) {
    var 
ranges cm.doc.sel.rangeskill = [];
    
// Build up a set of ranges to kill first, merging overlapping
    // ranges.
    
for (var 0ranges.lengthi++) {
      var 
toKill compute(ranges[i]);
      while (
kill.length && cmp(toKill.fromlst(kill).to) <= 0) {
        var 
replaced kill.pop();
        if (
cmp(replaced.fromtoKill.from) < 0) {
          
toKill.from replaced.from;
          break
        }
      }
      
kill.push(toKill);
    }
    
// Next, remove those actual ranges.
    
runInOp(cm, function () {
      for (var 
kill.length 1>= 0i--)
        { 
replaceRange(cm.doc""kill[i].fromkill[i].to"+delete"); }
      
ensureCursorVisible(cm);
    });
  }

  function 
moveCharLogically(linechdir) {
    var 
target skipExtendingChars(line.textch dirdir);
    return 
target || target line.text.length null target
  
}

  function 
moveLogically(linestartdir) {
    var 
ch moveCharLogically(linestart.chdir);
    return 
ch == null null : new Pos(start.linechdir "after" "before")
  }

  function 
endOfLine(visuallycmlineObjlineNodir) {
    if (
visually) {
      if (
cm.doc.direction == "rtl") { dir = -dir; }
      var 
order getOrder(lineObjcm.doc.direction);
      if (
order) {
        var 
part dir lst(order) : order[0];
        var 
moveInStorageOrder = (dir 0) == (part.level == 1);
        var 
sticky moveInStorageOrder "after" "before";
        var 
ch;
        
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
        // it could be that the last bidi part is not on the last visual line,
        // since visual lines contain content order-consecutive chunks.
        // Thus, in rtl, we are looking for the first (content-order) character
        // in the rtl chunk that is on the last line (that is, the same line
        // as the last (content-order) character).
        
if (part.level || cm.doc.direction == "rtl") {
          var 
prep prepareMeasureForLine(cmlineObj);
          
ch dir lineObj.text.length 0;
          var 
targetTop measureCharPrepared(cmprepch).top;
          
ch findFirst(function (ch) { return measureCharPrepared(cmprepch).top == targetTop; }, (dir 0) == (part.level == 1) ? part.from part.to 1ch);
          if (
sticky == "before") { ch moveCharLogically(lineObjch1); }
        } else { 
ch dir part.to part.from; }
        return new 
Pos(lineNochsticky)
      }
    }
    return new 
Pos(lineNodir lineObj.text.length 0dir "before" "after")
  }

  function 
moveVisually(cmlinestartdir) {
    var 
bidi getOrder(linecm.doc.direction);
    if (!
bidi) { return moveLogically(linestartdir) }
    if (
start.ch >= line.text.length) {
      
start.ch line.text.length;
      
start.sticky "before";
    } else if (
start.ch <= 0) {
      
start.ch 0;
      
start.sticky "after";
    }
    var 
partPos getBidiPartAt(bidistart.chstart.sticky), part bidi[partPos];
    if (
cm.doc.direction == "ltr" && part.level == && (dir part.to start.ch part.from start.ch)) {
      
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
      // nothing interesting happens.
      
return moveLogically(linestartdir)
    }

    var 
mv = function (posdir) { return moveCharLogically(linepos instanceof Pos pos.ch posdir); };
    var 
prep;
    var 
getWrappedLineExtent = function (ch) {
      if (!
cm.options.lineWrapping) { return {begin0endline.text.length} }
      
prep prep || prepareMeasureForLine(cmline);
      return 
wrappedLineExtentChar(cmlineprepch)
    };
    var 
wrappedLineExtent getWrappedLineExtent(start.sticky == "before" mv(start, -1) : start.ch);

    if (
cm.doc.direction == "rtl" || part.level == 1) {
      var 
moveInStorageOrder = (part.level == 1) == (dir 0);
      var 
ch mv(startmoveInStorageOrder : -1);
      if (
ch != null && (!moveInStorageOrder ch >= part.from && ch >= wrappedLineExtent.begin ch <= part.to && ch <= wrappedLineExtent.end)) {
        
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
        
var sticky moveInStorageOrder "before" "after";
        return new 
Pos(start.linechsticky)
      }
    }

    
// Case 3: Could not move within this bidi part in this visual line, so leave
    // the current bidi part

    
var searchInVisualLine = function (partPosdirwrappedLineExtent) {
      var 
getRes = function (chmoveInStorageOrder) { return moveInStorageOrder
        
? new Pos(start.linemv(ch1), "before")
        : new 
Pos(start.linech"after"); };

      for (; 
partPos >= && partPos bidi.lengthpartPos += dir) {
        var 
part bidi[partPos];
        var 
moveInStorageOrder = (dir 0) == (part.level != 1);
        var 
ch moveInStorageOrder wrappedLineExtent.begin mv(wrappedLineExtent.end, -1);
        if (
part.from <= ch && ch part.to) { return getRes(chmoveInStorageOrder) }
        
ch moveInStorageOrder part.from mv(part.to, -1);
        if (
wrappedLineExtent.begin <= ch && ch wrappedLineExtent.end) { return getRes(chmoveInStorageOrder) }
      }
    };

    
// Case 3a: Look for other bidi parts on the same visual line
    
var res searchInVisualLine(partPos dirdirwrappedLineExtent);
    if (
res) { return res }

    
// Case 3b: Look for other bidi parts on the next visual line
    
var nextCh dir wrappedLineExtent.end mv(wrappedLineExtent.begin, -1);
    if (
nextCh != null && !(dir && nextCh == line.text.length)) {
      
res searchInVisualLine(dir bidi.length 1dirgetWrappedLineExtent(nextCh));
      if (
res) { return res }
    }

    
// Case 4: Nowhere to move
    
return null
  
}

  
// Commands are parameter-less actions that can be performed on an
  // editor, mostly used for keybindings.
  
var commands = {
    
selectAllselectAll,
    
singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
    
killLine: function (cm) { return deleteNearSelection(cm, function (range) {
      if (
range.empty()) {
        var 
len getLine(cm.docrange.head.line).text.length;
        if (
range.head.ch == len && range.head.line cm.lastLine())
          { return {
fromrange.headtoPos(range.head.line 10)} }
        else
          { return {
fromrange.headtoPos(range.head.linelen)} }
      } else {
        return {
fromrange.from(), torange.to()}
      }
    }); },
    
deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
      
fromPos(range.from().line0),
      
toclipPos(cm.docPos(range.to().line 10))
    }); }); },
    
delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
      
fromPos(range.from().line0), torange.from()
    }); }); },
    
delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
      var 
top cm.charCoords(range.head"div").top 5;
      var 
leftPos cm.coordsChar({left0toptop}, "div");
      return {
fromleftPostorange.from()}
    }); },
    
delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
      var 
top cm.charCoords(range.head"div").top 5;
      var 
rightPos cm.coordsChar({leftcm.display.lineDiv.offsetWidth 100toptop}, "div");
      return {
fromrange.from(), torightPos }
    }); },
    
undo: function (cm) { return cm.undo(); },
    
redo: function (cm) { return cm.redo(); },
    
undoSelection: function (cm) { return cm.undoSelection(); },
    
redoSelection: function (cm) { return cm.redoSelection(); },
    
goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
    
goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
    
goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cmrange.head.line); },
      {
origin"+move"bias1}
    ); },
    
goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cmrange.head); },
      {
origin"+move"bias1}
    ); },
    
goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cmrange.head.line); },
      {
origin"+move"bias: -1}
    ); },
    
goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
      var 
top cm.cursorCoords(range.head"div").top 5;
      return 
cm.coordsChar({leftcm.display.lineDiv.offsetWidth 100toptop}, "div")
    }, 
sel_move); },
    
goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
      var 
top cm.cursorCoords(range.head"div").top 5;
      return 
cm.coordsChar({left0toptop}, "div")
    }, 
sel_move); },
    
goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
      var 
top cm.cursorCoords(range.head"div").top 5;
      var 
pos cm.coordsChar({left0toptop}, "div");
      if (
pos.ch cm.getLine(pos.line).search(/S/)) { return lineStartSmart(cmrange.head) }
      return 
pos
    
}, sel_move); },
    
goLineUp: function (cm) { return cm.moveV(-1"line"); },
    
goLineDown: function (cm) { return cm.moveV(1"line"); },
    
goPageUp: function (cm) { return cm.moveV(-1"page"); },
    
goPageDown: function (cm) { return cm.moveV(1"page"); },
    
goCharLeft: function (cm) { return cm.moveH(-1"char"); },
    
goCharRight: function (cm) { return cm.moveH(1"char"); },
    
goColumnLeft: function (cm) { return cm.moveH(-1"column"); },
    
goColumnRight: function (cm) { return cm.moveH(1"column"); },
    
goWordLeft: function (cm) { return cm.moveH(-1"word"); },
    
goGroupRight: function (cm) { return cm.moveH(1"group"); },
    
goGroupLeft: function (cm) { return cm.moveH(-1"group"); },
    
goWordRight: function (cm) { return cm.moveH(1"word"); },
    
delCharBefore: function (cm) { return cm.deleteH(-1"char"); },
    
delCharAfter: function (cm) { return cm.deleteH(1"char"); },
    
delWordBefore: function (cm) { return cm.deleteH(-1"word"); },
    
delWordAfter: function (cm) { return cm.deleteH(1"word"); },
    
delGroupBefore: function (cm) { return cm.deleteH(-1"group"); },
    
delGroupAfter: function (cm) { return cm.deleteH(1"group"); },
    
indentAuto: function (cm) { return cm.indentSelection("smart"); },
    
indentMore: function (cm) { return cm.indentSelection("add"); },
    
indentLess: function (cm) { return cm.indentSelection("subtract"); },
    
insertTab: function (cm) { return cm.replaceSelection("t"); },
    
insertSoftTab: function (cm) {
      var 
spaces = [], ranges cm.listSelections(), tabSize cm.options.tabSize;
      for (var 
0ranges.lengthi++) {
        var 
pos ranges[i].from();
        var 
col countColumn(cm.getLine(pos.line), pos.chtabSize);
        
spaces.push(spaceStr(tabSize col tabSize));
      }
      
cm.replaceSelections(spaces);
    },
    
defaultTab: function (cm) {
      if (
cm.somethingSelected()) { cm.indentSelection("add"); }
      else { 
cm.execCommand("insertTab"); }
    },
    
// Swap the two chars left and right of each selection's head.
    // Move cursor behind the two swapped characters afterwards.
    //
    // Doesn't consider line feeds a character.
    // Doesn't scan more than one line above to find a character.
    // Doesn't do anything on an empty line.
    // Doesn't do anything with non-empty selections.
    
transposeChars: function (cm) { return runInOp(cm, function () {
      var 
ranges cm.listSelections(), newSel = [];
      for (var 
0ranges.lengthi++) {
        if (!
ranges[i].empty()) { continue }
        var 
cur ranges[i].headline getLine(cm.doccur.line).text;
        if (
line) {
          if (
cur.ch == line.length) { cur = new Pos(cur.linecur.ch 1); }
          if (
cur.ch 0) {
            
cur = new Pos(cur.linecur.ch 1);
            
cm.replaceRange(line.charAt(cur.ch 1) + line.charAt(cur.ch 2),
                            
Pos(cur.linecur.ch 2), cur"+transpose");
          } else if (
cur.line cm.doc.first) {
            var 
prev getLine(cm.doccur.line 1).text;
            if (
prev) {
              
cur = new Pos(cur.line1);
              
cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
                              
prev.charAt(prev.length 1),
                              
Pos(cur.line 1prev.length 1), cur"+transpose");
            }
          }
        }
        
newSel.push(new Range(curcur));
      }
      
cm.setSelections(newSel);
    }); },
    
newlineAndIndent: function (cm) { return runInOp(cm, function () {
      var 
sels cm.listSelections();
      for (var 
sels.length 1>= 0i--)
        { 
cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchorsels[i].head"+input"); }
      
sels cm.listSelections();
      for (var 
i$0i$sels.lengthi$1++)
        { 
cm.indentLine(sels[i$1].from().linenulltrue); }
      
ensureCursorVisible(cm);
    }); },
    
openLine: function (cm) { return cm.replaceSelection("n""start"); },
    
toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
  };


  function 
lineStart(cmlineN) {
    var 
line getLine(cm.doclineN);
    var 
visual visualLine(line);
    if (
visual != line) { lineN lineNo(visual); }
    return 
endOfLine(truecmvisuallineN1)
  }
  function 
lineEnd(cmlineN) {
    var 
line getLine(cm.doclineN);
    var 
visual visualLineEnd(line);
    if (
visual != line) { lineN lineNo(visual); }
    return 
endOfLine(truecmlinelineN, -1)
  }
  function 
lineStartSmart(cmpos) {
    var 
start lineStart(cmpos.line);
    var 
line getLine(cm.docstart.line);
    var 
order getOrder(linecm.doc.direction);
    if (!
order || order[0].level == 0) {
      var 
firstNonWS Math.max(start.chline.text.search(/S/));
      var 
inWS pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
      return 
Pos(start.lineinWS firstNonWSstart.sticky)
    }
    return 
start
  
}

  
// Run a handler that was bound to a key.
  
function doHandleBinding(cmbounddropShift) {
    if (
typeof bound == "string") {
      
bound commands[bound];
      if (!
bound) { return false }
    }
    
// Ensure previous input has been read, so that the handler sees a
    // consistent view of the document
    
cm.display.input.ensurePolled();
    var 
prevShift cm.display.shiftdone false;
    try {
      if (
cm.isReadOnly()) { cm.state.suppressEdits true; }
      if (
dropShift) { cm.display.shift false; }
      
done bound(cm) != Pass;
    } finally {
      
cm.display.shift prevShift;
      
cm.state.suppressEdits false;
    }
    return 
done
  
}

  function 
lookupKeyForEditor(cmnamehandle) {
    for (var 
0cm.state.keyMaps.lengthi++) {
      var 
result lookupKey(namecm.state.keyMaps[i], handlecm);
      if (
result) { return result }
    }
    return (
cm.options.extraKeys && lookupKey(namecm.options.extraKeyshandlecm))
      || 
lookupKey(namecm.options.keyMaphandlecm)
  }

  
// Note that, despite the name, this function is also used to check
  // for bound mouse clicks.

  
var stopSeq = new Delayed;

  function 
dispatchKey(cmnameehandle) {
    var 
seq cm.state.keySeq;
    if (
seq) {
      if (
isModifierKey(name)) { return "handled" }
      if (/
'$/.test(name))
        { cm.state.keySeq = null; }
      else
        { stopSeq.set(50, function () {
          if (cm.state.keySeq == seq) {
            cm.state.keySeq = null;
            cm.display.input.reset();
          }
        }); }
      if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true }
    }
    return dispatchKeyInner(cm, name, e, handle)
  }

  function dispatchKeyInner(cm, name, e, handle) {
    var result = lookupKeyForEditor(cm, name, handle);

    if (result == "multi")
      { cm.state.keySeq = name; }
    if (result == "handled")
      { signalLater(cm, "keyHandled", cm, name, e); }

    if (result == "handled" || result == "multi") {
      e_preventDefault(e);
      restartBlink(cm);
    }

    return !!result
  }

  // Handle a key from the keydown event.
  function handleKeyBinding(cm, e) {
    var name = keyName(e, true);
    if (!name) { return false }

    if (e.shiftKey && !cm.state.keySeq) {
      // First try to resolve full name (including '
Shift-'). Failing
      // that, see if there is a cursor-motion command (starting with
      // '
go') bound to the keyname without 'Shift-'.
      return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
          || dispatchKey(cm, name, e, function (b) {
               if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
                 { return doHandleBinding(cm, b) }
             })
    } else {
      return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
    }
  }

  // Handle a key from the keypress event
  function handleCharBinding(cm, e, ch) {
    return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
  }

  var lastStoppedKey = null;
  function onKeyDown(e) {
    var cm = this;
    if (e.target && e.target != cm.display.input.getField()) { return }
    cm.curOp.focus = activeElt();
    if (signalDOMEvent(cm, e)) { return }
    // IE does strange things with escape.
    if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
    var code = e.keyCode;
    cm.display.shift = code == 16 || e.shiftKey;
    var handled = handleKeyBinding(cm, e);
    if (presto) {
      lastStoppedKey = handled ? code : null;
      // Opera has no cut event... we try to at least catch the key combo
      if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
        { cm.replaceSelection("", null, "cut"); }
    }
    if (gecko && !mac && !handled && code == 46 && e.shiftKey && !e.ctrlKey && document.execCommand)
      { document.execCommand("cut"); }

    // Turn mouse into crosshair when Alt is held on Mac.
    if (code == 18 && !/bCodeMirror-crosshairb/.test(cm.display.lineDiv.className))
      { showCrossHair(cm); }
  }

  function showCrossHair(cm) {
    var lineDiv = cm.display.lineDiv;
    addClass(lineDiv, "CodeMirror-crosshair");

    function up(e) {
      if (e.keyCode == 18 || !e.altKey) {
        rmClass(lineDiv, "CodeMirror-crosshair");
        off(document, "keyup", up);
        off(document, "mouseover", up);
      }
    }
    on(document, "keyup", up);
    on(document, "mouseover", up);
  }

  function onKeyUp(e) {
    if (e.keyCode == 16) { this.doc.sel.shift = false; }
    signalDOMEvent(this, e);
  }

  function onKeyPress(e) {
    var cm = this;
    if (e.target && e.target != cm.display.input.getField()) { return }
    if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
    var keyCode = e.keyCode, charCode = e.charCode;
    if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
    if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
    var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
    // Some browsers fire keypress events for backspace
    if (ch == "x08") { return }
    if (handleCharBinding(cm, e, ch)) { return }
    cm.display.input.onKeyPress(e);
  }

  var DOUBLECLICK_DELAY = 400;

  var PastClick = function(time, pos, button) {
    this.time = time;
    this.pos = pos;
    this.button = button;
  };

  PastClick.prototype.compare = function (time, pos, button) {
    return this.time + DOUBLECLICK_DELAY > time &&
      cmp(pos, this.pos) == 0 && button == this.button
  };

  var lastClick, lastDoubleClick;
  function clickRepeat(pos, button) {
    var now = +new Date;
    if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
      lastClick = lastDoubleClick = null;
      return "triple"
    } else if (lastClick && lastClick.compare(now, pos, button)) {
      lastDoubleClick = new PastClick(now, pos, button);
      lastClick = null;
      return "double"
    } else {
      lastClick = new PastClick(now, pos, button);
      lastDoubleClick = null;
      return "single"
    }
  }

  // A mouse down can be a single click, double click, triple click,
  // start of selection drag, start of text drag, new cursor
  // (ctrl-click), rectangle drag (alt-drag), or xwin
  // middle-click-paste. Or it might be a click on something we should
  // not interfere with, such as a scrollbar or widget.
  function onMouseDown(e) {
    var cm = this, display = cm.display;
    if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
    display.input.ensurePolled();
    display.shift = e.shiftKey;

    if (eventInWidget(display, e)) {
      if (!webkit) {
        // Briefly turn off draggability, to allow widgets to do
        // normal dragging things.
        display.scroller.draggable = false;
        setTimeout(function () { return display.scroller.draggable = true; }, 100);
      }
      return
    }
    if (clickInGutter(cm, e)) { return }
    var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
    window.focus();

    // #3261: make sure, that we'
re not starting a second selection
    
if (button == && cm.state.selectingText)
      { 
cm.state.selectingText(e); }

    if (
pos && handleMappedButton(cmbuttonposrepeate)) { return }

    if (
button == 1) {
      if (
pos) { leftButtonDown(cmposrepeate); }
      else if (
e_target(e) == display.scroller) { e_preventDefault(e); }
    } else if (
button == 2) {
      if (
pos) { extendSelection(cm.docpos); }
      
setTimeout(function () { return display.input.focus(); }, 20);
    } else if (
button == 3) {
      if (
captureRightClick) { cm.display.input.onContextMenu(e); }
      else { 
delayBlurEvent(cm); }
    }
  }

  function 
handleMappedButton(cmbuttonposrepeatevent) {
    var 
name "Click";
    if (
repeat == "double") { name "Double" name; }
    else if (
repeat == "triple") { name "Triple" name; }
    
name = (button == "Left" button == "Middle" "Right") + name;

    return 
dispatchKey(cm,  addModifierNames(nameevent), event, function (bound) {
      if (
typeof bound == "string") { bound commands[bound]; }
      if (!
bound) { return false }
      var 
done false;
      try {
        if (
cm.isReadOnly()) { cm.state.suppressEdits true; }
        
done bound(cmpos) != Pass;
      } finally {
        
cm.state.suppressEdits false;
      }
      return 
done
    
})
  }

  function 
configureMouse(cmrepeatevent) {
    var 
option cm.getOption("configureMouse");
    var 
value option option(cmrepeatevent) : {};
    if (
value.unit == null) {
      var 
rect chromeOS event.shiftKey && event.metaKey event.altKey;
      
value.unit rect "rectangle" repeat == "single" "char" repeat == "double" "word" "line";
    }
    if (
value.extend == null || cm.doc.extend) { value.extend cm.doc.extend || event.shiftKey; }
    if (
value.addNew == null) { value.addNew mac event.metaKey event.ctrlKey; }
    if (
value.moveOnDrag == null) { value.moveOnDrag = !(mac event.altKey event.ctrlKey); }
    return 
value
  
}

  function 
leftButtonDown(cmposrepeatevent) {
    if (
ie) { setTimeout(bind(ensureFocuscm), 0); }
    else { 
cm.curOp.focus activeElt(); }

    var 
behavior configureMouse(cmrepeatevent);

    var 
sel cm.doc.selcontained;
    if (
cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
        
repeat == "single" && (contained sel.contains(pos)) > -&&
        (
cmp((contained sel.ranges[contained]).from(), pos) < || pos.xRel 0) &&
        (
cmp(contained.to(), pos) > || pos.xRel 0))
      { 
leftButtonStartDrag(cmeventposbehavior); }
    else
      { 
leftButtonSelect(cmeventposbehavior); }
  }

  
// Start a text drag. When it ends, see if any dragging actually
  // happen, and treat as a click if it didn't.
  
function leftButtonStartDrag(cmeventposbehavior) {
    var 
display cm.displaymoved false;
    var 
dragEnd operation(cm, function (e) {
      if (
webkit) { display.scroller.draggable false; }
      
cm.state.draggingText false;
      
off(display.wrapper.ownerDocument"mouseup"dragEnd);
      
off(display.wrapper.ownerDocument"mousemove"mouseMove);
      
off(display.scroller"dragstart"dragStart);
      
off(display.scroller"drop"dragEnd);
      if (!
moved) {
        
e_preventDefault(e);
        if (!
behavior.addNew)
          { 
extendSelection(cm.docposnullnullbehavior.extend); }
        
// Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
        
if ((webkit && !safari) || ie && ie_version == 9)
          { 
setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScrolltrue}); display.input.focus();}, 20); }
        else
          { 
display.input.focus(); }
      }
    });
    var 
mouseMove = function(e2) {
      
moved moved || Math.abs(event.clientX e2.clientX) + Math.abs(event.clientY e2.clientY) >= 10;
    };
    var 
dragStart = function () { return moved true; };
    
// Let the drag handler handle this.
    
if (webkit) { display.scroller.draggable true; }
    
cm.state.draggingText dragEnd;
    
dragEnd.copy = !behavior.moveOnDrag;
    
// IE's approach to draggable
    
if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
    
on(display.wrapper.ownerDocument"mouseup"dragEnd);
    
on(display.wrapper.ownerDocument"mousemove"mouseMove);
    
on(display.scroller"dragstart"dragStart);
    
on(display.scroller"drop"dragEnd);

    
delayBlurEvent(cm);
    
setTimeout(function () { return display.input.focus(); }, 20);
  }

  function 
rangeForUnit(cmposunit) {
    if (
unit == "char") { return new Range(pospos) }
    if (
unit == "word") { return cm.findWordAt(pos) }
    if (
unit == "line") { return new Range(Pos(pos.line0), clipPos(cm.docPos(pos.line 10))) }
    var 
result unit(cmpos);
    return new 
Range(result.fromresult.to)
  }

  
// Normal selection, as opposed to text dragging.
  
function leftButtonSelect(cmeventstartbehavior) {
    var 
display cm.displaydoc cm.doc;
    
e_preventDefault(event);

    var 
ourRangeourIndexstartSel doc.selranges startSel.ranges;
    if (
behavior.addNew && !behavior.extend) {
      
ourIndex doc.sel.contains(start);
      if (
ourIndex > -1)
        { 
ourRange ranges[ourIndex]; }
      else
        { 
ourRange = new Range(startstart); }
    } else {
      
ourRange doc.sel.primary();
      
ourIndex doc.sel.primIndex;
    }

    if (
behavior.unit == "rectangle") {
      if (!
behavior.addNew) { ourRange = new Range(startstart); }
      
start posFromMouse(cmeventtruetrue);
      
ourIndex = -1;
    } else {
      var 
range rangeForUnit(cmstartbehavior.unit);
      if (
behavior.extend)
        { 
ourRange extendRange(ourRangerange.anchorrange.headbehavior.extend); }
      else
        { 
ourRange range; }
    }

    if (!
behavior.addNew) {
      
ourIndex 0;
      
setSelection(doc, new Selection([ourRange], 0), sel_mouse);
      
startSel doc.sel;
    } else if (
ourIndex == -1) {
      
ourIndex ranges.length;
      
setSelection(docnormalizeSelection(cmranges.concat([ourRange]), ourIndex),
                   {
scrollfalseorigin"*mouse"});
    } else if (
ranges.length && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
      
setSelection(docnormalizeSelection(cmranges.slice(0ourIndex).concat(ranges.slice(ourIndex 1)), 0),
                   {
scrollfalseorigin"*mouse"});
      
startSel doc.sel;
    } else {
      
replaceOneSelection(docourIndexourRangesel_mouse);
    }

    var 
lastPos start;
    function 
extendTo(pos) {
      if (
cmp(lastPospos) == 0) { return }
      
lastPos pos;

      if (
behavior.unit == "rectangle") {
        var 
ranges = [], tabSize cm.options.tabSize;
        var 
startCol countColumn(getLine(docstart.line).textstart.chtabSize);
        var 
posCol countColumn(getLine(docpos.line).textpos.chtabSize);
        var 
left Math.min(startColposCol), right Math.max(startColposCol);
        for (var 
line Math.min(start.linepos.line), end Math.min(cm.lastLine(), Math.max(start.linepos.line));
             
line <= endline++) {
          var 
text getLine(docline).textleftPos findColumn(textlefttabSize);
          if (
left == right)
            { 
ranges.push(new Range(Pos(lineleftPos), Pos(lineleftPos))); }
          else if (
text.length leftPos)
            { 
ranges.push(new Range(Pos(lineleftPos), Pos(linefindColumn(textrighttabSize)))); }
        }
        if (!
ranges.length) { ranges.push(new Range(startstart)); }
        
setSelection(docnormalizeSelection(cmstartSel.ranges.slice(0ourIndex).concat(ranges), ourIndex),
                     {
origin"*mouse"scrollfalse});
        
cm.scrollIntoView(pos);
      } else {
        var 
oldRange ourRange;
        var 
range rangeForUnit(cmposbehavior.unit);
        var 
anchor oldRange.anchorhead;
        if (
cmp(range.anchoranchor) > 0) {
          
head range.head;
          
anchor minPos(oldRange.from(), range.anchor);
        } else {
          
head range.anchor;
          
anchor maxPos(oldRange.to(), range.head);
        }
        var 
ranges$startSel.ranges.slice(0);
        
ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(docanchor), head));
        
setSelection(docnormalizeSelection(cmranges$1ourIndex), sel_mouse);
      }
    }

    var 
editorSize display.wrapper.getBoundingClientRect();
    
// Used to ensure timeout re-tries don't fire when another extend
    // happened in the meantime (clearTimeout isn't reliable -- at
    // least on Chrome, the timeouts still happen even when cleared,
    // if the clear happens after their scheduled firing time).
    
var counter 0;

    function 
extend(e) {
      var 
curCount = ++counter;
      var 
cur posFromMouse(cmetruebehavior.unit == "rectangle");
      if (!
cur) { return }
      if (
cmp(curlastPos) != 0) {
        
cm.curOp.focus activeElt();
        
extendTo(cur);
        var 
visible visibleLines(displaydoc);
        if (
cur.line >= visible.to || cur.line visible.from)
          { 
setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
      } else {
        var 
outside e.clientY editorSize.top ? -20 e.clientY editorSize.bottom 20 0;
        if (
outside) { setTimeout(operation(cm, function () {
          if (
counter != curCount) { return }
          
display.scroller.scrollTop += outside;
          
extend(e);
        }), 
50); }
      }
    }

    function 
done(e) {
      
cm.state.selectingText false;
      
counter Infinity;
      
// If e is null or undefined we interpret this as someone trying
      // to explicitly cancel the selection rather than the user
      // letting go of the mouse button.
      
if (e) {
        
e_preventDefault(e);
        
display.input.focus();
      }
      
off(display.wrapper.ownerDocument"mousemove"move);
      
off(display.wrapper.ownerDocument"mouseup"up);
      
doc.history.lastSelOrigin null;
    }

    var 
move operation(cm, function (e) {
      if (
e.buttons === || !e_button(e)) { done(e); }
      else { 
extend(e); }
    });
    var 
up operation(cmdone);
    
cm.state.selectingText up;
    
on(display.wrapper.ownerDocument"mousemove"move);
    
on(display.wrapper.ownerDocument"mouseup"up);
  }

  
// Used when mouse-selecting to adjust the anchor to the proper side
  // of a bidi jump depending on the visual position of the head.
  
function bidiSimplify(cmrange) {
    var 
anchor range.anchor;
    var 
head range.head;
    var 
anchorLine getLine(cm.docanchor.line);
    if (
cmp(anchorhead) == && anchor.sticky == head.sticky) { return range }
    var 
order getOrder(anchorLine);
    if (!
order) { return range }
    var 
index getBidiPartAt(orderanchor.chanchor.sticky), part order[index];
    if (
part.from != anchor.ch && part.to != anchor.ch) { return range }
    var 
boundary index + ((part.from == anchor.ch) == (part.level != 1) ? 1);
    if (
boundary == || boundary == order.length) { return range }

    
// Compute the relative visual position of the head compared to the
    // anchor (<0 is to the left, >0 to the right)
    
var leftSide;
    if (
head.line != anchor.line) {
      
leftSide = (head.line anchor.line) * (cm.doc.direction == "ltr" : -1) > 0;
    } else {
      var 
headIndex getBidiPartAt(orderhead.chhead.sticky);
      var 
dir headIndex index || (head.ch anchor.ch) * (part.level == ? -1);
      if (
headIndex == boundary || headIndex == boundary)
        { 
leftSide dir 0; }
      else
        { 
leftSide dir 0; }
    }

    var 
usePart order[boundary + (leftSide ? -0)];
    var 
from leftSide == (usePart.level == 1);
    var 
ch from usePart.from usePart.tosticky from "after" "before";
    return 
anchor.ch == ch && anchor.sticky == sticky range : new Range(new Pos(anchor.linechsticky), head)
  }


  
// Determines whether an event happened in the gutter, and fires the
  // handlers for the corresponding event.
  
function gutterEvent(cmetypeprevent) {
    var 
mXmY;
    if (
e.touches) {
      
mX e.touches[0].clientX;
      
mY e.touches[0].clientY;
    } else {
      try { 
mX e.clientXmY e.clientY; }
      catch(
e) { return false }
    }
    if (
mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
    if (
prevent) { e_preventDefault(e); }

    var 
display cm.display;
    var 
lineBox display.lineDiv.getBoundingClientRect();

    if (
mY lineBox.bottom || !hasHandler(cmtype)) { return e_defaultPrevented(e) }
    
mY -= lineBox.top display.viewOffset;

    for (var 
0cm.display.gutterSpecs.length; ++i) {
      var 
display.gutters.childNodes[i];
      if (
&& g.getBoundingClientRect().right >= mX) {
        var 
line lineAtHeight(cm.docmY);
        var 
gutter cm.display.gutterSpecs[i];
        
signal(cmtypecmlinegutter.classNamee);
        return 
e_defaultPrevented(e)
      }
    }
  }

  function 
clickInGutter(cme) {
    return 
gutterEvent(cme"gutterClick"true)
  }

  
// CONTEXT MENU HANDLING

  // To make the context menu work, we need to briefly unhide the
  // textarea (making it as unobtrusive as possible) to let the
  // right-click take effect on it.
  
function onContextMenu(cme) {
    if (
eventInWidget(cm.displaye) || contextMenuInGutter(cme)) { return }
    if (
signalDOMEvent(cme"contextmenu")) { return }
    if (!
captureRightClick) { cm.display.input.onContextMenu(e); }
  }

  function 
contextMenuInGutter(cme) {
    if (!
hasHandler(cm"gutterContextMenu")) { return false }
    return 
gutterEvent(cme"gutterContextMenu"false)
  }

  function 
themeChanged(cm) {
    
cm.display.wrapper.className cm.display.wrapper.className.replace(/s*cm-s-S+/g"") +
      
cm.options.theme.replace(/(^|s)s*/g" cm-s-");
    
clearCaches(cm);
  }

  var 
Init = {toString: function(){return "CodeMirror.Init"}};

  var 
defaults = {};
  var 
optionHandlers = {};

  function 
defineOptions(CodeMirror) {
    var 
optionHandlers CodeMirror.optionHandlers;

    function 
option(namedeflthandlenotOnInit) {
      
CodeMirror.defaults[name] = deflt;
      if (
handle) { optionHandlers[name] =
        
notOnInit ? function (cmvalold) {if (old != Init) { handle(cmvalold); }} : handle; }
    }

    
CodeMirror.defineOption option;

    
// Passed to option handlers when there is no old value.
    
CodeMirror.Init Init;

    
// These two are, on init, called from the constructor because they
    // have to be initialized before the editor can start at all.
    
option("value""", function (cmval) { return cm.setValue(val); }, true);
    
option("mode"null, function (cmval) {
      
cm.doc.modeOption val;
      
loadMode(cm);
    }, 
true);

    
option("indentUnit"2loadModetrue);
    
option("indentWithTabs"false);
    
option("smartIndent"true);
    
option("tabSize"4, function (cm) {
      
resetModeState(cm);
      
clearCaches(cm);
      
regChange(cm);
    }, 
true);

    
option("lineSeparator"null, function (cmval) {
      
cm.doc.lineSep val;
      if (!
val) { return }
      var 
newBreaks = [], lineNo cm.doc.first;
      
cm.doc.iter(function (line) {
        for (var 
pos 0;;) {
          var 
found line.text.indexOf(valpos);
          if (
found == -1) { break }
          
pos found val.length;
          
newBreaks.push(Pos(lineNofound));
        }
        
lineNo++;
      });
      for (var 
newBreaks.length 1>= 0i--)
        { 
replaceRange(cm.docvalnewBreaks[i], Pos(newBreaks[i].linenewBreaks[i].ch val.length)); }
    });
    
option("specialChars", /[u0000-u001fu007f-u009fu00adu061cu200b-u200fu2028u2029ufeffufff9-ufffc]/g, function (cmvalold) {
      
cm.state.specialChars = new RegExp(val.source + (val.test("t") ? "" "|t"), "g");
      if (
old != Init) { cm.refresh(); }
    });
    
option("specialCharPlaceholder"defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
    
option("electricChars"true);
    
option("inputStyle"mobile "contenteditable" "textarea", function () {
      throw new 
Error("inputStyle can not (yet) be changed in a running editor"// FIXME
    
}, true);
    
option("spellcheck"false, function (cmval) { return cm.getInputField().spellcheck val; }, true);
    
option("autocorrect"false, function (cmval) { return cm.getInputField().autocorrect val; }, true);
    
option("autocapitalize"false, function (cmval) { return cm.getInputField().autocapitalize val; }, true);
    
option("rtlMoveVisually", !windows);
    
option("wholeLineUpdateBefore"true);

    
option("theme""default", function (cm) {
      
themeChanged(cm);
      
updateGutters(cm);
    }, 
true);
    
option("keyMap""default", function (cmvalold) {
      var 
next getKeyMap(val);
      var 
prev old != Init && getKeyMap(old);
      if (
prev && prev.detach) { prev.detach(cmnext); }
      if (
next.attach) { next.attach(cmprev || null); }
    });
    
option("extraKeys"null);
    
option("configureMouse"null);

    
option("lineWrapping"falsewrappingChangedtrue);
    
option("gutters", [], function (cmval) {
      
cm.display.gutterSpecs getGutters(valcm.options.lineNumbers);
      
updateGutters(cm);
    }, 
true);
    
option("fixedGutter"true, function (cmval) {
      
cm.display.gutters.style.left val compensateForHScroll(cm.display) + "px" "0";
      
cm.refresh();
    }, 
true);
    
option("coverGutterNextToScrollbar"false, function (cm) { return updateScrollbars(cm); }, true);
    
option("scrollbarStyle""native", function (cm) {
      
initScrollbars(cm);
      
updateScrollbars(cm);
      
cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
      
cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
    }, 
true);
    
option("lineNumbers"false, function (cmval) {
      
cm.display.gutterSpecs getGutters(cm.options.guttersval);
      
updateGutters(cm);
    }, 
true);
    
option("firstLineNumber"1updateGutterstrue);
    
option("lineNumberFormatter", function (integer) { return integer; }, updateGutterstrue);
    
option("showCursorWhenSelecting"falseupdateSelectiontrue);

    
option("resetSelectionOnContextMenu"true);
    
option("lineWiseCopyCut"true);
    
option("pasteLinesPerSelection"true);
    
option("selectionsMayTouch"false);

    
option("readOnly"false, function (cmval) {
      if (
val == "nocursor") {
        
onBlur(cm);
        
cm.display.input.blur();
      }
      
cm.display.input.readOnlyChanged(val);
    });

    
option("screenReaderLabel"null, function (cmval) {
      
val = (val === '') ? null val;
      
cm.display.input.screenReaderLabelChanged(val);
    });

    
option("disableInput"false, function (cmval) {if (!val) { cm.display.input.reset(); }}, true);
    
option("dragDrop"truedragDropChanged);
    
option("allowDropFileTypes"null);

    
option("cursorBlinkRate"530);
    
option("cursorScrollMargin"0);
    
option("cursorHeight"1updateSelectiontrue);
    
option("singleCursorHeightPerLine"trueupdateSelectiontrue);
    
option("workTime"100);
    
option("workDelay"100);
    
option("flattenSpans"trueresetModeStatetrue);
    
option("addModeClass"falseresetModeStatetrue);
    
option("pollInterval"100);
    
option("undoDepth"200, function (cmval) { return cm.doc.history.undoDepth val; });
    
option("historyEventDelay"1250);
    
option("viewportMargin"10, function (cm) { return cm.refresh(); }, true);
    
option("maxHighlightLength"10000resetModeStatetrue);
    
option("moveInputWithCursor"true, function (cmval) {
      if (!
val) { cm.display.input.resetPosition(); }
    });

    
option("tabindex"null, function (cmval) { return cm.display.input.getField().tabIndex val || ""; });
    
option("autofocus"null);
    
option("direction""ltr", function (cmval) { return cm.doc.setDirection(val); }, true);
    
option("phrases"null);
  }

  function 
dragDropChanged(cmvalueold) {
    var 
wasOn old && old != Init;
    if (!
value != !wasOn) {
      var 
funcs cm.display.dragFunctions;
      var 
toggle value on off;
      
toggle(cm.display.scroller"dragstart"funcs.start);
      
toggle(cm.display.scroller"dragenter"funcs.enter);
      
toggle(cm.display.scroller"dragover"funcs.over);
      
toggle(cm.display.scroller"dragleave"funcs.leave);
      
toggle(cm.display.scroller"drop"funcs.drop);
    }
  }

  function 
wrappingChanged(cm) {
    if (
cm.options.lineWrapping) {
      
addClass(cm.display.wrapper"CodeMirror-wrap");
      
cm.display.sizer.style.minWidth "";
      
cm.display.sizerWidth null;
    } else {
      
rmClass(cm.display.wrapper"CodeMirror-wrap");
      
findMaxLine(cm);
    }
    
estimateLineHeights(cm);
    
regChange(cm);
    
clearCaches(cm);
    
setTimeout(function () { return updateScrollbars(cm); }, 100);
  }

  
// A CodeMirror instance represents an editor. This is the object
  // that user code is usually dealing with.

  
function CodeMirror(placeoptions) {
    var 
this$this;

    if (!(
this instanceof CodeMirror)) { return new CodeMirror(placeoptions) }

    
this.options options options copyObj(options) : {};
    
// Determine effective options based on given values and defaults.
    
copyObj(defaultsoptionsfalse);

    var 
doc options.value;
    if (
typeof doc == "string") { doc = new Doc(docoptions.modenulloptions.lineSeparatoroptions.direction); }
    else if (
options.mode) { doc.modeOption options.mode; }
    
this.doc doc;

    var 
input = new CodeMirror.inputStyles[options.inputStyle](this);
    var 
display this.display = new Display(placedocinputoptions);
    
display.wrapper.CodeMirror this;
    
themeChanged(this);
    if (
options.lineWrapping)
      { 
this.display.wrapper.className += " CodeMirror-wrap"; }
    
initScrollbars(this);

    
this.state = {
      
keyMaps: [],  // stores maps added by addKeyMap
      
overlays: [], // highlighting overlays, as added by addOverlay
      
modeGen0,   // bumped when mode/overlay changes, used to invalidate highlighting info
      
overwritefalse,
      
delayingBlurEventfalse,
      
focusedfalse,
      
suppressEditsfalse// used to disable editing during key handlers when in readOnly mode
      
pasteIncoming: -1cutIncoming: -1// help recognize paste/cut edits in input.poll
      
selectingTextfalse,
      
draggingTextfalse,
      
highlight: new Delayed(), // stores highlight worker timeout
      
keySeqnull,  // Unfinished key sequence
      
specialCharsnull
    
};

    if (
options.autofocus && !mobile) { display.input.focus(); }

    
// Override magic textarea content restore that IE sometimes does
    // on our hidden textarea on reload
    
if (ie && ie_version 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }

    
registerEventHandlers(this);
    
ensureGlobalHandlers();

    
startOperation(this);
    
this.curOp.forceUpdate true;
    
attachDoc(thisdoc);

    if ((
options.autofocus && !mobile) || this.hasFocus())
      { 
setTimeout(bind(onFocusthis), 20); }
    else
      { 
onBlur(this); }

    for (var 
opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
      { 
optionHandlers[opt](thisoptions[opt], Init); } }
    
maybeUpdateLineNumberWidth(this);
    if (
options.finishInit) { options.finishInit(this); }
    for (var 
0initHooks.length; ++i) { initHooks[i](this); }
    
endOperation(this);
    
// Suppress optimizelegibility in Webkit, since it breaks text
    // measuring on line wrapping boundaries.
    
if (webkit && options.lineWrapping &&
        
getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
      { 
display.lineDiv.style.textRendering "auto"; }
  }

  
// The default configuration options.
  
CodeMirror.defaults defaults;
  
// Functions to run when options are changed.
  
CodeMirror.optionHandlers optionHandlers;

  
// Attach the necessary event handlers when initializing the editor
  
function registerEventHandlers(cm) {
    var 
cm.display;
    
on(d.scroller"mousedown"operation(cmonMouseDown));
    
// Older IE's will not fire a second mousedown for a double click
    
if (ie && ie_version 11)
      { 
on(d.scroller"dblclick"operation(cm, function (e) {
        if (
signalDOMEvent(cme)) { return }
        var 
pos posFromMouse(cme);
        if (!
pos || clickInGutter(cme) || eventInWidget(cm.displaye)) { return }
        
e_preventDefault(e);
        var 
word cm.findWordAt(pos);
        
extendSelection(cm.docword.anchorword.head);
      })); }
    else
      { 
on(d.scroller"dblclick", function (e) { return signalDOMEvent(cme) || e_preventDefault(e); }); }
    
// Some browsers fire contextmenu *after* opening the menu, at
    // which point we can't mess with it anymore. Context menu is
    // handled in onMouseDown for these browsers.
    
on(d.scroller"contextmenu", function (e) { return onContextMenu(cme); });
    
on(d.input.getField(), "contextmenu", function (e) {
      if (!
d.scroller.contains(e.target)) { onContextMenu(cme); }
    });

    
// Used to suppress mouse event handling when a touch happens
    
var touchFinishedprevTouch = {end0};
    function 
finishTouch() {
      if (
d.activeTouch) {
        
touchFinished setTimeout(function () { return d.activeTouch null; }, 1000);
        
prevTouch d.activeTouch;
        
prevTouch.end = +new Date;
      }
    }
    function 
isMouseLikeTouchEvent(e) {
      if (
e.touches.length != 1) { return false }
      var 
touch e.touches[0];
      return 
touch.radiusX <= && touch.radiusY <= 1
    
}
    function 
farAway(touchother) {
      if (
other.left == null) { return true }
      var 
dx other.left touch.leftdy other.top touch.top;
      return 
dx dx dy dy 20 20
    
}
    
on(d.scroller"touchstart", function (e) {
      if (!
signalDOMEvent(cme) && !isMouseLikeTouchEvent(e) && !clickInGutter(cme)) {
        
d.input.ensurePolled();
        
clearTimeout(touchFinished);
        var 
now = +new Date;
        
d.activeTouch = {startnowmovedfalse,
                         
prevnow prevTouch.end <= 300 prevTouch null};
        if (
e.touches.length == 1) {
          
d.activeTouch.left e.touches[0].pageX;
          
d.activeTouch.top e.touches[0].pageY;
        }
      }
    });
    
on(d.scroller"touchmove", function () {
      if (
d.activeTouch) { d.activeTouch.moved true; }
    });
    
on(d.scroller"touchend", function (e) {
      var 
touch d.activeTouch;
      if (
touch && !eventInWidget(de) && touch.left != null &&
          !
touch.moved && new Date touch.start 300) {
        var 
pos cm.coordsChar(d.activeTouch"page"), range;
        if (!
touch.prev || farAway(touchtouch.prev)) // Single tap
          
range = new Range(pospos); }
        else if (!
touch.prev.prev || farAway(touchtouch.prev.prev)) // Double tap
          
range cm.findWordAt(pos); }
        else 
// Triple tap
          
range = new Range(Pos(pos.line0), clipPos(cm.docPos(pos.line 10))); }
        
cm.setSelection(range.anchorrange.head);
        
cm.focus();
        
e_preventDefault(e);
      }
      
finishTouch();
    });
    
on(d.scroller"touchcancel"finishTouch);

    
// Sync scrolling between fake scrollbars and real scrollable
    // area, ensure viewport is updated when scrolling.
    
on(d.scroller"scroll", function () {
      if (
d.scroller.clientHeight) {
        
updateScrollTop(cmd.scroller.scrollTop);
        
setScrollLeft(cmd.scroller.scrollLefttrue);
        
signal(cm"scroll"cm);
      }
    });

    
// Listen to wheel events in order to try and update the viewport on time.
    
on(d.scroller"mousewheel", function (e) { return onScrollWheel(cme); });
    
on(d.scroller"DOMMouseScroll", function (e) { return onScrollWheel(cme); });

    
// Prevent wrapper from ever scrolling
    
on(d.wrapper"scroll", function () { return d.wrapper.scrollTop d.wrapper.scrollLeft 0; });

    
d.dragFunctions = {
      
enter: function (e) {if (!signalDOMEvent(cme)) { e_stop(e); }},
      
over: function (e) {if (!signalDOMEvent(cme)) { onDragOver(cme); e_stop(e); }},
      
start: function (e) { return onDragStart(cme); },
      
dropoperation(cmonDrop),
      
leave: function (e) {if (!signalDOMEvent(cme)) { clearDragCursor(cm); }}
    };

    var 
inp d.input.getField();
    
on(inp"keyup", function (e) { return onKeyUp.call(cme); });
    
on(inp"keydown"operation(cmonKeyDown));
    
on(inp"keypress"operation(cmonKeyPress));
    
on(inp"focus", function (e) { return onFocus(cme); });
    
on(inp"blur", function (e) { return onBlur(cme); });
  }

  var 
initHooks = [];
  
CodeMirror.defineInitHook = function (f) { return initHooks.push(f); };

  
// Indent the given line. The how parameter can be "smart",
  // "add"/null, "subtract", or "prev". When aggressive is false
  // (typically set to true for forced single-line indents), empty
  // lines are not indented, and places where the mode returns Pass
  // are left alone.
  
function indentLine(cmnhowaggressive) {
    var 
doc cm.docstate;
    if (
how == null) { how "add"; }
    if (
how == "smart") {
      
// Fall back to "prev" when the mode doesn't have an indentation
      // method.
      
if (!doc.mode.indent) { how "prev"; }
      else { 
state getContextBefore(cmn).state; }
    }

    var 
tabSize cm.options.tabSize;
    var 
line getLine(docn), curSpace countColumn(line.textnulltabSize);
    if (
line.stateAfter) { line.stateAfter null; }
    var 
curSpaceString line.text.match(/^s*/)[0], indentation;
    if (!
aggressive && !/S/.test(line.text)) {
      
indentation 0;
      
how "not";
    } else if (
how == "smart") {
      
indentation doc.mode.indent(stateline.text.slice(curSpaceString.length), line.text);
      if (
indentation == Pass || indentation 150) {
        if (!
aggressive) { return }
        
how "prev";
      }
    }
    if (
how == "prev") {
      if (
doc.first) { indentation countColumn(getLine(docn-1).textnulltabSize); }
      else { 
indentation 0; }
    } else if (
how == "add") {
      
indentation curSpace cm.options.indentUnit;
    } else if (
how == "subtract") {
      
indentation curSpace cm.options.indentUnit;
    } else if (
typeof how == "number") {
      
indentation curSpace how;
    }
    
indentation Math.max(0indentation);

    var 
indentString ""pos 0;
    if (
cm.options.indentWithTabs)
      { for (var 
Math.floor(indentation tabSize); i; --i) {pos += tabSizeindentString += "t";} }
    if (
pos indentation) { indentString += spaceStr(indentation pos); }

    if (
indentString != curSpaceString) {
      
replaceRange(docindentStringPos(n0), Pos(ncurSpaceString.length), "+input");
      
line.stateAfter null;
      return 
true
    
} else {
      
// Ensure that, if the cursor was in the whitespace at the start
      // of the line, it is moved to the end of that space.
      
for (var i$0i$doc.sel.ranges.lengthi$1++) {
        var 
range doc.sel.ranges[i$1];
        if (
range.head.line == && range.head.ch curSpaceString.length) {
          var 
pos$Pos(ncurSpaceString.length);
          
replaceOneSelection(doci$1, new Range(pos$1pos$1));
          break
        }
      }
    }
  }

  
// This will be set to a {lineWise: bool, text: [string]} object, so
  // that, when pasting, we know what kind of selections the copied
  // text was made out of.
  
var lastCopied null;

  function 
setLastCopied(newLastCopied) {
    
lastCopied newLastCopied;
  }

  function 
applyTextInput(cminserteddeletedselorigin) {
    var 
doc cm.doc;
    
cm.display.shift false;
    if (!
sel) { sel doc.sel; }

    var 
recent = +new Date 200;
    var 
paste origin == "paste" || cm.state.pasteIncoming recent;
    var 
textLines splitLinesAuto(inserted), multiPaste null;
    
// When pasting N lines into N selections, insert one line per selection
    
if (paste && sel.ranges.length 1) {
      if (
lastCopied && lastCopied.text.join("n") == inserted) {
        if (
sel.ranges.length lastCopied.text.length == 0) {
          
multiPaste = [];
          for (var 
0lastCopied.text.lengthi++)
            { 
multiPaste.push(doc.splitLines(lastCopied.text[i])); }
        }
      } else if (
textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
        
multiPaste map(textLines, function (l) { return [l]; });
      }
    }

    var 
updateInput cm.curOp.updateInput;
    
// Normal behavior is to insert the new text into every selection
    
for (var i$sel.ranges.length 1i$>= 0i$1--) {
      var 
range sel.ranges[i$1];
      var 
from range.from(), to range.to();
      if (
range.empty()) {
        if (
deleted && deleted 0// Handle deletion
          
from Pos(from.linefrom.ch deleted); }
        else if (
cm.state.overwrite && !paste// Handle overwrite
          
to Pos(to.lineMath.min(getLine(docto.line).text.lengthto.ch lst(textLines).length)); }
        else if (
paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("n") == inserted)
          { 
from to Pos(from.line0); }
      }
      var 
changeEvent = {fromfromtototextmultiPaste multiPaste[i$multiPaste.length] : textLines,
                         
originorigin || (paste "paste" cm.state.cutIncoming recent "cut" "+input")};
      
makeChange(cm.docchangeEvent);
      
signalLater(cm"inputRead"cmchangeEvent);
    }
    if (
inserted && !paste)
      { 
triggerElectric(cminserted); }

    
ensureCursorVisible(cm);
    if (
cm.curOp.updateInput 2) { cm.curOp.updateInput updateInput; }
    
cm.curOp.typing true;
    
cm.state.pasteIncoming cm.state.cutIncoming = -1;
  }

  function 
handlePaste(ecm) {
    var 
pasted e.clipboardData && e.clipboardData.getData("Text");
    if (
pasted) {
      
e.preventDefault();
      if (!
cm.isReadOnly() && !cm.options.disableInput)
        { 
runInOp(cm, function () { return applyTextInput(cmpasted0null"paste"); }); }
      return 
true
    
}
  }

  function 
triggerElectric(cminserted) {
    
// When an 'electric' character is inserted, immediately trigger a reindent
    
if (!cm.options.electricChars || !cm.options.smartIndent) { return }
    var 
sel cm.doc.sel;

    for (var 
sel.ranges.length 1>= 0i--) {
      var 
range sel.ranges[i];
      if (
range.head.ch 100 || (&& sel.ranges[1].head.line == range.head.line)) { continue }
      var 
mode cm.getModeAt(range.head);
      var 
indented false;
      if (
mode.electricChars) {
        for (var 
0mode.electricChars.lengthj++)
          { if (
inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
            
indented indentLine(cmrange.head.line"smart");
            break
          } }
      } else if (
mode.electricInput) {
        if (
mode.electricInput.test(getLine(cm.docrange.head.line).text.slice(0range.head.ch)))
          { 
indented indentLine(cmrange.head.line"smart"); }
      }
      if (
indented) { signalLater(cm"electricInput"cmrange.head.line); }
    }
  }

  function 
copyableRanges(cm) {
    var 
text = [], ranges = [];
    for (var 
0cm.doc.sel.ranges.lengthi++) {
      var 
line cm.doc.sel.ranges[i].head.line;
      var 
lineRange = {anchorPos(line0), headPos(line 10)};
      
ranges.push(lineRange);
      
text.push(cm.getRange(lineRange.anchorlineRange.head));
    }
    return {
texttextrangesranges}
  }

  function 
disableBrowserMagic(fieldspellcheckautocorrectautocapitalize) {
    
field.setAttribute("autocorrect"autocorrect "" "off");
    
field.setAttribute("autocapitalize"autocapitalize "" "off");
    
field.setAttribute("spellcheck", !!spellcheck);
  }

  function 
hiddenTextarea() {
    var 
te elt("textarea"nullnull"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
    var 
div elt("div", [te], null"overflow: hidden; position: relative; width: 3px; height: 0px;");
    
// The textarea is kept positioned near the cursor to prevent the
    // fact that it'll be scrolled into view on input from scrolling
    // our fake cursor out of view. On webkit, when wrap=off, paste is
    // very slow. So make the area wide instead.
    
if (webkit) { te.style.width "1000px"; }
    else { 
te.setAttribute("wrap""off"); }
    
// If border: 0; -- iOS fails to open keyboard (issue #1287)
    
if (ios) { te.style.border "1px solid black"; }
    
disableBrowserMagic(te);
    return 
div
  
}

  
// The publicly visible API. Note that methodOp(f) means
  // 'wrap f in an operation, performed on its `this` parameter'.

  // This is not the complete set of editor methods. Most of the
  // methods defined on the Doc type are also injected into
  // CodeMirror.prototype, for backwards compatibility and
  // convenience.

  
function addEditorMethods(CodeMirror) {
    var 
optionHandlers CodeMirror.optionHandlers;

    var 
helpers CodeMirror.helpers = {};

    
CodeMirror.prototype = {
      
constructorCodeMirror,
      
focus: function(){window.focus(); this.display.input.focus();},

      
setOption: function(optionvalue) {
        var 
options this.optionsold options[option];
        if (
options[option] == value && option != "mode") { return }
        
options[option] = value;
        if (
optionHandlers.hasOwnProperty(option))
          { 
operation(thisoptionHandlers[option])(thisvalueold); }
        
signal(this"optionChange"thisoption);
      },

      
getOption: function(option) {return this.options[option]},
      
getDoc: function() {return this.doc},

      
addKeyMap: function(mapbottom) {
        
this.state.keyMaps[bottom "push" "unshift"](getKeyMap(map));
      },
      
removeKeyMap: function(map) {
        var 
maps this.state.keyMaps;
        for (var 
0maps.length; ++i)
          { if (
maps[i] == map || maps[i].name == map) {
            
maps.splice(i1);
            return 
true
          
} }
      },

      
addOverlaymethodOp(function(specoptions) {
        var 
mode spec.token spec CodeMirror.getMode(this.optionsspec);
        if (
mode.startState) { throw new Error("Overlays may not be stateful.") }
        
insertSorted(this.state.overlays,
                     {
modemodemodeSpecspecopaqueoptions && options.opaque,
                      
priority: (options && options.priority) || 0},
                     function (
overlay) { return overlay.priority; });
        
this.state.modeGen++;
        
regChange(this);
      }),
      
removeOverlaymethodOp(function(spec) {
        var 
overlays this.state.overlays;
        for (var 
0overlays.length; ++i) {
          var 
cur overlays[i].modeSpec;
          if (
cur == spec || typeof spec == "string" && cur.name == spec) {
            
overlays.splice(i1);
            
this.state.modeGen++;
            
regChange(this);
            return
          }
        }
      }),

      
indentLinemethodOp(function(ndiraggressive) {
        if (
typeof dir != "string" && typeof dir != "number") {
          if (
dir == null) { dir this.options.smartIndent "smart" "prev"; }
          else { 
dir dir "add" "subtract"; }
        }
        if (
isLine(this.docn)) { indentLine(thisndiraggressive); }
      }),
      
indentSelectionmethodOp(function(how) {
        var 
ranges this.doc.sel.rangesend = -1;
        for (var 
0ranges.lengthi++) {
          var 
range ranges[i];
          if (!
range.empty()) {
            var 
from range.from(), to range.to();
            var 
start Math.max(endfrom.line);
            
end Math.min(this.lastLine(), to.line - (to.ch 1)) + 1;
            for (var 
startend; ++j)
              { 
indentLine(thisjhow); }
            var 
newRanges this.doc.sel.ranges;
            if (
from.ch == && ranges.length == newRanges.length && newRanges[i].from().ch 0)
              { 
replaceOneSelection(this.doci, new Range(fromnewRanges[i].to()), sel_dontScroll); }
          } else if (
range.head.line end) {
            
indentLine(thisrange.head.linehowtrue);
            
end range.head.line;
            if (
== this.doc.sel.primIndex) { ensureCursorVisible(this); }
          }
        }
      }),

      
// Fetch the parser token for a given character. Useful for hacks
      // that want to inspect the mode state (say, for completion).
      
getTokenAt: function(posprecise) {
        return 
takeToken(thisposprecise)
      },

      
getLineTokens: function(lineprecise) {
        return 
takeToken(thisPos(line), precisetrue)
      },

      
getTokenTypeAt: function(pos) {
        
pos clipPos(this.docpos);
        var 
styles getLineStyles(thisgetLine(this.docpos.line));
        var 
before 0after = (styles.length 1) / 2ch pos.ch;
        var 
type;
        if (
ch == 0) { type styles[2]; }
        else { for (;;) {
          var 
mid = (before after) >> 1;
          if ((
mid styles[mid 1] : 0) >= ch) { after mid; }
          else if (
styles[mid 1] < ch) { before mid 1; }
          else { 
type styles[mid 2]; break }
        } }
        var 
cut type type.indexOf("overlay ") : -1;
        return 
cut type cut == null type.slice(0cut 1)
      },

      
getModeAt: function(pos) {
        var 
mode this.doc.mode;
        if (!
mode.innerMode) { return mode }
        return 
CodeMirror.innerMode(modethis.getTokenAt(pos).state).mode
      
},

      
getHelper: function(postype) {
        return 
this.getHelpers(postype)[0]
      },

      
getHelpers: function(postype) {
        var 
found = [];
        if (!
helpers.hasOwnProperty(type)) { return found }
        var 
help helpers[type], mode this.getModeAt(pos);
        if (
typeof mode[type] == "string") {
          if (
help[mode[type]]) { found.push(help[mode[type]]); }
        } else if (
mode[type]) {
          for (var 
0mode[type].lengthi++) {
            var 
val help[mode[type][i]];
            if (
val) { found.push(val); }
          }
        } else if (
mode.helperType && help[mode.helperType]) {
          
found.push(help[mode.helperType]);
        } else if (
help[mode.name]) {
          
found.push(help[mode.name]);
        }
        for (var 
i$0i$help._global.lengthi$1++) {
          var 
cur help._global[i$1];
          if (
cur.pred(modethis) && indexOf(foundcur.val) == -1)
            { 
found.push(cur.val); }
        }
        return 
found
      
},

      
getStateAfter: function(lineprecise) {
        var 
doc this.doc;
        
line clipLine(docline == null doc.first doc.size 1line);
        return 
getContextBefore(thisline 1precise).state
      
},

      
cursorCoords: function(startmode) {
        var 
posrange this.doc.sel.primary();
        if (
start == null) { pos range.head; }
        else if (
typeof start == "object") { pos clipPos(this.docstart); }
        else { 
pos start range.from() : range.to(); }
        return 
cursorCoords(thisposmode || "page")
      },

      
charCoords: function(posmode) {
        return 
charCoords(thisclipPos(this.docpos), mode || "page")
      },

      
coordsChar: function(coordsmode) {
        
coords fromCoordSystem(thiscoordsmode || "page");
        return 
coordsChar(thiscoords.leftcoords.top)
      },

      
lineAtHeight: function(heightmode) {
        
height fromCoordSystem(this, {topheightleft0}, mode || "page").top;
        return 
lineAtHeight(this.docheight this.display.viewOffset)
      },
      
heightAtLine: function(linemodeincludeWidgets) {
        var 
end falselineObj;
        if (
typeof line == "number") {
          var 
last this.doc.first this.doc.size 1;
          if (
line this.doc.first) { line this.doc.first; }
          else if (
line last) { line lastend true; }
          
lineObj getLine(this.docline);
        } else {
          
lineObj line;
        }
        return 
intoCoordSystem(thislineObj, {top0left0}, mode || "page"includeWidgets || end).top +
          (
end this.doc.height heightAtLine(lineObj) : 0)
      },

      
defaultTextHeight: function() { return textHeight(this.display) },
      
defaultCharWidth: function() { return charWidth(this.display) },

      
getViewport: function() { return {fromthis.display.viewFromtothis.display.viewTo}},

      
addWidget: function(posnodescrollverthoriz) {
        var 
display this.display;
        
pos cursorCoords(thisclipPos(this.docpos));
        var 
top pos.bottomleft pos.left;
        
node.style.position "absolute";
        
node.setAttribute("cm-ignore-events""true");
        
this.display.input.setUneditable(node);
        
display.sizer.appendChild(node);
        if (
vert == "over") {
          
top pos.top;
        } else if (
vert == "above" || vert == "near") {
          var 
vspace Math.max(display.wrapper.clientHeightthis.doc.height),
          
hspace Math.max(display.sizer.clientWidthdisplay.lineSpace.clientWidth);
          
// Default to positioning above (if specified and possible); otherwise default to positioning below
          
if ((vert == 'above' || pos.bottom node.offsetHeight vspace) && pos.top node.offsetHeight)
            { 
top pos.top node.offsetHeight; }
          else if (
pos.bottom node.offsetHeight <= vspace)
            { 
top pos.bottom; }
          if (
left node.offsetWidth hspace)
            { 
left hspace node.offsetWidth; }
        }
        
node.style.top top "px";
        
node.style.left node.style.right "";
        if (
horiz == "right") {
          
left display.sizer.clientWidth node.offsetWidth;
          
node.style.right "0px";
        } else {
          if (
horiz == "left") { left 0; }
          else if (
horiz == "middle") { left = (display.sizer.clientWidth node.offsetWidth) / 2; }
          
node.style.left left "px";
        }
        if (
scroll)
          { 
scrollIntoView(this, {leftlefttoptoprightleft node.offsetWidthbottomtop node.offsetHeight}); }
      },

      
triggerOnKeyDownmethodOp(onKeyDown),
      
triggerOnKeyPressmethodOp(onKeyPress),
      
triggerOnKeyUponKeyUp,
      
triggerOnMouseDownmethodOp(onMouseDown),

      
execCommand: function(cmd) {
        if (
commands.hasOwnProperty(cmd))
          { return 
commands[cmd].call(nullthis) }
      },

      
triggerElectricmethodOp(function(text) { triggerElectric(thistext); }),

      
findPosH: function(fromamountunitvisually) {
        var 
dir 1;
        if (
amount 0) { dir = -1amount = -amount; }
        var 
cur clipPos(this.docfrom);
        for (var 
0amount; ++i) {
          
cur findPosH(this.doccurdirunitvisually);
          if (
cur.hitSide) { break }
        }
        return 
cur
      
},

      
moveHmethodOp(function(dirunit) {
        var 
this$this;

        
this.extendSelectionsBy(function (range) {
          if (
this$1.display.shift || this$1.doc.extend || range.empty())
            { return 
findPosH(this$1.docrange.headdirunitthis$1.options.rtlMoveVisually) }
          else
            { return 
dir range.from() : range.to() }
        }, 
sel_move);
      }),

      
deleteHmethodOp(function(dirunit) {
        var 
sel this.doc.seldoc this.doc;
        if (
sel.somethingSelected())
          { 
doc.replaceSelection(""null"+delete"); }
        else
          { 
deleteNearSelection(this, function (range) {
            var 
other findPosH(docrange.headdirunitfalse);
            return 
dir ? {fromothertorange.head} : {fromrange.headtoother}
          }); }
      }),

      
findPosV: function(fromamountunitgoalColumn) {
        var 
dir 1goalColumn;
        if (
amount 0) { dir = -1amount = -amount; }
        var 
cur clipPos(this.docfrom);
        for (var 
0amount; ++i) {
          var 
coords cursorCoords(thiscur"div");
          if (
== null) { coords.left; }
          else { 
coords.left x; }
          
cur findPosV(thiscoordsdirunit);
          if (
cur.hitSide) { break }
        }
        return 
cur
      
},

      
moveVmethodOp(function(dirunit) {
        var 
this$this;

        var 
doc this.docgoals = [];
        var 
collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
        
doc.extendSelectionsBy(function (range) {
          if (
collapse)
            { return 
dir range.from() : range.to() }
          var 
headPos cursorCoords(this$1range.head"div");
          if (
range.goalColumn != null) { headPos.left range.goalColumn; }
          
goals.push(headPos.left);
          var 
pos findPosV(this$1headPosdirunit);
          if (
unit == "page" && range == doc.sel.primary())
            { 
addToScrollTop(this$1charCoords(this$1pos"div").top headPos.top); }
          return 
pos
        
}, sel_move);
        if (
goals.length) { for (var 0doc.sel.ranges.lengthi++)
          { 
doc.sel.ranges[i].goalColumn goals[i]; } }
      }),

      
// Find the word at the given position (as returned by coordsChar).
      
findWordAt: function(pos) {
        var 
doc this.docline getLine(docpos.line).text;
        var 
start pos.chend pos.ch;
        if (
line) {
          var 
helper this.getHelper(pos"wordChars");
          if ((
pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
          var 
startChar line.charAt(start);
          var 
check isWordChar(startCharhelper)
            ? function (
ch) { return isWordChar(chhelper); }
            : /
s/.test(startChar) ? function (ch) { return /s/.test(ch); }
            : function (
ch) { return (!/s/.test(ch) && !isWordChar(ch)); };
          while (
start && check(line.charAt(start 1))) { --start; }
          while (
end line.length && check(line.charAt(end))) { ++end; }
        }
        return new 
Range(Pos(pos.linestart), Pos(pos.lineend))
      },

      
toggleOverwrite: function(value) {
        if (
value != null && value == this.state.overwrite) { return }
        if (
this.state.overwrite = !this.state.overwrite)
          { 
addClass(this.display.cursorDiv"CodeMirror-overwrite"); }
        else
          { 
rmClass(this.display.cursorDiv"CodeMirror-overwrite"); }

        
signal(this"overwriteToggle"thisthis.state.overwrite);
      },
      
hasFocus: function() { return this.display.input.getField() == activeElt() },
      
isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },

      
scrollTomethodOp(function (xy) { scrollToCoords(thisxy); }),
      
getScrollInfo: function() {
        var 
scroller this.display.scroller;
        return {
leftscroller.scrollLefttopscroller.scrollTop,
                
heightscroller.scrollHeight scrollGap(this) - this.display.barHeight,
                
widthscroller.scrollWidth scrollGap(this) - this.display.barWidth,
                
clientHeightdisplayHeight(this), clientWidthdisplayWidth(this)}
      },

      
scrollIntoViewmethodOp(function(rangemargin) {
        if (
range == null) {
          
range = {fromthis.doc.sel.primary().headtonull};
          if (
margin == null) { margin this.options.cursorScrollMargin; }
        } else if (
typeof range == "number") {
          
range = {fromPos(range0), tonull};
        } else if (
range.from == null) {
          
range = {fromrangetonull};
        }
        if (!
range.to) { range.to range.from; }
        
range.margin margin || 0;

        if (
range.from.line != null) {
          
scrollToRange(thisrange);
        } else {
          
scrollToCoordsRange(thisrange.fromrange.torange.margin);
        }
      }),

      
setSizemethodOp(function(widthheight) {
        var 
this$this;

        var 
interpret = function (val) { return typeof val == "number" || /^d+$/.test(String(val)) ? val "px" val; };
        if (
width != null) { this.display.wrapper.style.width interpret(width); }
        if (
height != null) { this.display.wrapper.style.height interpret(height); }
        if (
this.options.lineWrapping) { clearLineMeasurementCache(this); }
        var 
lineNo this.display.viewFrom;
        
this.doc.iter(lineNothis.display.viewTo, function (line) {
          if (
line.widgets) { for (var 0line.widgets.lengthi++)
            { if (
line.widgets[i].noHScroll) { regLineChange(this$1lineNo"widget"); break } } }
          ++
lineNo;
        });
        
this.curOp.forceUpdate true;
        
signal(this"refresh"this);
      }),

      
operation: function(f){return runInOp(thisf)},
      
startOperation: function(){return startOperation(this)},
      
endOperation: function(){return endOperation(this)},

      
refreshmethodOp(function() {
        var 
oldHeight this.display.cachedTextHeight;
        
regChange(this);
        
this.curOp.forceUpdate true;
        
clearCaches(this);
        
scrollToCoords(thisthis.doc.scrollLeftthis.doc.scrollTop);
        
updateGutterSpace(this.display);
        if (
oldHeight == null || Math.abs(oldHeight textHeight(this.display)) > .5 || this.options.lineWrapping)
          { 
estimateLineHeights(this); }
        
signal(this"refresh"this);
      }),

      
swapDocmethodOp(function(doc) {
        var 
old this.doc;
        
old.cm null;
        
// Cancel the current text selection if any (#5821)
        
if (this.state.selectingText) { this.state.selectingText(); }
        
attachDoc(thisdoc);
        
clearCaches(this);
        
this.display.input.reset();
        
scrollToCoords(thisdoc.scrollLeftdoc.scrollTop);
        
this.curOp.forceScroll true;
        
signalLater(this"swapDoc"thisold);
        return 
old
      
}),

      
phrase: function(phraseText) {
        var 
phrases this.options.phrases;
        return 
phrases && Object.prototype.hasOwnProperty.call(phrasesphraseText) ? phrases[phraseText] : phraseText
      
},

      
getInputField: function(){return this.display.input.getField()},
      
getWrapperElement: function(){return this.display.wrapper},
      
getScrollerElement: function(){return this.display.scroller},
      
getGutterElement: function(){return this.display.gutters}
    };
    
eventMixin(CodeMirror);

    
CodeMirror.registerHelper = function(typenamevalue) {
      if (!
helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
      
helpers[type][name] = value;
    };
    
CodeMirror.registerGlobalHelper = function(typenamepredicatevalue) {
      
CodeMirror.registerHelper(typenamevalue);
      
helpers[type]._global.push({predpredicatevalvalue});
    };
  }

  
// Used for horizontal relative motion. Dir is -1 or 1 (left or
  // right), unit can be "char", "column" (like char, but doesn't
  // cross line boundaries), "word" (across next word), or "group" (to
  // the start of next group of word or non-word-non-whitespace
  // chars). The visually param controls whether, in right-to-left
  // text, direction 1 means to move towards the next index in the
  // string, or towards the character to the right of the current
  // position. The resulting position will have a hitSide=true
  // property if it reached the end of the document.
  
function findPosH(docposdirunitvisually) {
    var 
oldPos pos;
    var 
origDir dir;
    var 
lineObj getLine(docpos.line);
    var 
lineDir visually && doc.direction == "rtl" ? -dir dir;
    function 
findNextLine() {
      var 
pos.line lineDir;
      if (
doc.first || >= doc.first doc.size) { return false }
      
pos = new Pos(lpos.chpos.sticky);
      return 
lineObj getLine(docl)
    }
    function 
moveOnce(boundToLine) {
      var 
next;
      if (
visually) {
        
next moveVisually(doc.cmlineObjposdir);
      } else {
        
next moveLogically(lineObjposdir);
      }
      if (
next == null) {
        if (!
boundToLine && findNextLine())
          { 
pos endOfLine(visuallydoc.cmlineObjpos.linelineDir); }
        else
          { return 
false }
      } else {
        
pos next;
      }
      return 
true
    
}

    if (
unit == "char") {
      
moveOnce();
    } else if (
unit == "column") {
      
moveOnce(true);
    } else if (
unit == "word" || unit == "group") {
      var 
sawType nullgroup unit == "group";
      var 
helper doc.cm && doc.cm.getHelper(pos"wordChars");
      for (var 
first true;; first false) {
        if (
dir && !moveOnce(!first)) { break }
        var 
cur lineObj.text.charAt(pos.ch) || "n";
        var 
type isWordChar(curhelper) ? "w"
          
group && cur == "n" "n"
          
: !group || /s/.test(cur) ? null
          
"p";
        if (
group && !first && !type) { type "s"; }
        if (
sawType && sawType != type) {
          if (
dir 0) {dir 1moveOnce(); pos.sticky "after";}
          break
        }

        if (
type) { sawType type; }
        if (
dir && !moveOnce(!first)) { break }
      }
    }
    var 
result skipAtomic(docposoldPosorigDirtrue);
    if (
equalCursorPos(oldPosresult)) { result.hitSide true; }
    return 
result
  
}

  
// For relative vertical movement. Dir may be -1 or 1. Unit can be
  // "page" or "line". The resulting position will have a hitSide=true
  // property if it reached the end of the document.
  
function findPosV(cmposdirunit) {
    var 
doc cm.docpos.lefty;
    if (
unit == "page") {
      var 
pageSize Math.min(cm.display.wrapper.clientHeightwindow.innerHeight || document.documentElement.clientHeight);
      var 
moveAmount Math.max(pageSize .5 textHeight(cm.display), 3);
      
= (dir pos.bottom pos.top) + dir moveAmount;

    } else if (
unit == "line") {
      
dir pos.bottom pos.top 3;
    }
    var 
target;
    for (;;) {
      
target coordsChar(cmxy);
      if (!
target.outside) { break }
      if (
dir <= >= doc.height) { target.hitSide true; break }
      
+= dir 5;
    }
    return 
target
  
}

  
// CONTENTEDITABLE INPUT STYLE

  
var ContentEditableInput = function(cm) {
    
this.cm cm;
    
this.lastAnchorNode this.lastAnchorOffset this.lastFocusNode this.lastFocusOffset null;
    
this.polling = new Delayed();
    
this.composing null;
    
this.gracePeriod false;
    
this.readDOMTimeout null;
  };

  
ContentEditableInput.prototype.init = function (display) {
      var 
this$this;

    var 
input thiscm input.cm;
    var 
div input.div display.lineDiv;
    
disableBrowserMagic(divcm.options.spellcheckcm.options.autocorrectcm.options.autocapitalize);

    function 
belongsToInput(e) {
      for (var 
e.targettt.parentNode) {
        if (
== div) { return true }
        if (/
bCodeMirror-(?:line)?widgetb/.test(t.className)) { break }
      }
      return 
false
    
}

    
on(div"paste", function (e) {
      if (!
belongsToInput(e) || signalDOMEvent(cme) || handlePaste(ecm)) { return }
      
// IE doesn't fire input events, so we schedule a read for the pasted content in this way
      
if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
    });

    
on(div"compositionstart", function (e) {
      
this$1.composing = {datae.datadonefalse};
    });
    
on(div"compositionupdate", function (e) {
      if (!
this$1.composing) { this$1.composing = {datae.datadonefalse}; }
    });
    
on(div"compositionend", function (e) {
      if (
this$1.composing) {
        if (
e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
        
this$1.composing.done true;
      }
    });

    
on(div"touchstart", function () { return input.forceCompositionEnd(); });

    
on(div"input", function () {
      if (!
this$1.composing) { this$1.readFromDOMSoon(); }
    });

    function 
onCopyCut(e) {
      if (!
belongsToInput(e) || signalDOMEvent(cme)) { return }
      if (
cm.somethingSelected()) {
        
setLastCopied({lineWisefalsetextcm.getSelections()});
        if (
e.type == "cut") { cm.replaceSelection(""null"cut"); }
      } else if (!
cm.options.lineWiseCopyCut) {
        return
      } else {
        var 
ranges copyableRanges(cm);
        
setLastCopied({lineWisetruetextranges.text});
        if (
e.type == "cut") {
          
cm.operation(function () {
            
cm.setSelections(ranges.ranges0sel_dontScroll);
            
cm.replaceSelection(""null"cut");
          });
        }
      }
      if (
e.clipboardData) {
        
e.clipboardData.clearData();
        var 
content lastCopied.text.join("n");
        
// iOS exposes the clipboard API, but seems to discard content inserted into it
        
e.clipboardData.setData("Text"content);
        if (
e.clipboardData.getData("Text") == content) {
          
e.preventDefault();
          return
        }
      }
      
// Old-fashioned briefly-focus-a-textarea hack
      
var kludge hiddenTextarea(), te kludge.firstChild;
      
cm.display.lineSpace.insertBefore(kludgecm.display.lineSpace.firstChild);
      
te.value lastCopied.text.join("n");
      var 
hadFocus document.activeElement;
      
selectInput(te);
      
setTimeout(function () {
        
cm.display.lineSpace.removeChild(kludge);
        
hadFocus.focus();
        if (
hadFocus == div) { input.showPrimarySelection(); }
      }, 
50);
    }
    
on(div"copy"onCopyCut);
    
on(div"cut"onCopyCut);
  };

  
ContentEditableInput.prototype.screenReaderLabelChanged = function (label) {
    
// Label for screenreaders, accessibility
    
if(label) {
      
this.div.setAttribute('aria-label'label);
    } else {
      
this.div.removeAttribute('aria-label');
    }
  };

  
ContentEditableInput.prototype.prepareSelection = function () {
    var 
result prepareSelection(this.cmfalse);
    
result.focus document.activeElement == this.div;
    return 
result
  
};

  
ContentEditableInput.prototype.showSelection = function (infotakeFocus) {
    if (!
info || !this.cm.display.view.length) { return }
    if (
info.focus || takeFocus) { this.showPrimarySelection(); }
    
this.showMultipleSelections(info);
  };

  
ContentEditableInput.prototype.getSelection = function () {
    return 
this.cm.display.wrapper.ownerDocument.getSelection()
  };

  
ContentEditableInput.prototype.showPrimarySelection = function () {
    var 
sel this.getSelection(), cm this.cmprim cm.doc.sel.primary();
    var 
from prim.from(), to prim.to();

    if (
cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line cm.display.viewFrom) {
      
sel.removeAllRanges();
      return
    }

    var 
curAnchor domToPos(cmsel.anchorNodesel.anchorOffset);
    var 
curFocus domToPos(cmsel.focusNodesel.focusOffset);
    if (
curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
        
cmp(minPos(curAnchorcurFocus), from) == &&
        
cmp(maxPos(curAnchorcurFocus), to) == 0)
      { return }

    var 
view cm.display.view;
    var 
start = (from.line >= cm.display.viewFrom && posToDOM(cmfrom)) ||
        {
nodeview[0].measure.map[2], offset0};
    var 
end to.line cm.display.viewTo && posToDOM(cmto);
    if (!
end) {
      var 
measure view[view.length 1].measure;
      var 
map measure.maps measure.maps[measure.maps.length 1] : measure.map;
      
end = {nodemap[map.length 1], offsetmap[map.length 2] - map[map.length 3]};
    }

    if (!
start || !end) {
      
sel.removeAllRanges();
      return
    }

    var 
old sel.rangeCount && sel.getRangeAt(0), rng;
    try { 
rng range(start.nodestart.offsetend.offsetend.node); }
    catch(
e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
    
if (rng) {
      if (!
gecko && cm.state.focused) {
        
sel.collapse(start.nodestart.offset);
        if (!
rng.collapsed) {
          
sel.removeAllRanges();
          
sel.addRange(rng);
        }
      } else {
        
sel.removeAllRanges();
        
sel.addRange(rng);
      }
      if (
old && sel.anchorNode == null) { sel.addRange(old); }
      else if (
gecko) { this.startGracePeriod(); }
    }
    
this.rememberSelection();
  };

  
ContentEditableInput.prototype.startGracePeriod = function () {
      var 
this$this;

    
clearTimeout(this.gracePeriod);
    
this.gracePeriod setTimeout(function () {
      
this$1.gracePeriod false;
      if (
this$1.selectionChanged())
        { 
this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged true; }); }
    }, 
20);
  };

  
ContentEditableInput.prototype.showMultipleSelections = function (info) {
    
removeChildrenAndAdd(this.cm.display.cursorDivinfo.cursors);
    
removeChildrenAndAdd(this.cm.display.selectionDivinfo.selection);
  };

  
ContentEditableInput.prototype.rememberSelection = function () {
    var 
sel this.getSelection();
    
this.lastAnchorNode sel.anchorNodethis.lastAnchorOffset sel.anchorOffset;
    
this.lastFocusNode sel.focusNodethis.lastFocusOffset sel.focusOffset;
  };

  
ContentEditableInput.prototype.selectionInEditor = function () {
    var 
sel this.getSelection();
    if (!
sel.rangeCount) { return false }
    var 
node sel.getRangeAt(0).commonAncestorContainer;
    return 
contains(this.divnode)
  };

  
ContentEditableInput.prototype.focus = function () {
    if (
this.cm.options.readOnly != "nocursor") {
      if (!
this.selectionInEditor() || document.activeElement != this.div)
        { 
this.showSelection(this.prepareSelection(), true); }
      
this.div.focus();
    }
  };
  
ContentEditableInput.prototype.blur = function () { this.div.blur(); };
  
ContentEditableInput.prototype.getField = function () { return this.div };

  
ContentEditableInput.prototype.supportsTouch = function () { return true };

  
ContentEditableInput.prototype.receivedFocus = function () {
    var 
input this;
    if (
this.selectionInEditor())
      { 
this.pollSelection(); }
    else
      { 
runInOp(this.cm, function () { return input.cm.curOp.selectionChanged true; }); }

    function 
poll() {
      if (
input.cm.state.focused) {
        
input.pollSelection();
        
input.polling.set(input.cm.options.pollIntervalpoll);
      }
    }
    
this.polling.set(this.cm.options.pollIntervalpoll);
  };

  
ContentEditableInput.prototype.selectionChanged = function () {
    var 
sel this.getSelection();
    return 
sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
      
sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
  
};

  
ContentEditableInput.prototype.pollSelection = function () {
    if (
this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
    var 
sel this.getSelection(), cm this.cm;
    
// On Android Chrome (version 56, at least), backspacing into an
    // uneditable block element will put the cursor in that element,
    // and then, because it's not editable, hide the virtual keyboard.
    // Because Android doesn't allow us to actually detect backspace
    // presses in a sane way, this code checks for when that happens
    // and simulates a backspace press in this case.
    
if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) {
      
this.cm.triggerOnKeyDown({type"keydown"keyCode8preventDefaultMath.abs});
      
this.blur();
      
this.focus();
      return
    }
    if (
this.composing) { return }
    
this.rememberSelection();
    var 
anchor domToPos(cmsel.anchorNodesel.anchorOffset);
    var 
head domToPos(cmsel.focusNodesel.focusOffset);
    if (
anchor && head) { runInOp(cm, function () {
      
setSelection(cm.docsimpleSelection(anchorhead), sel_dontScroll);
      if (
anchor.bad || head.bad) { cm.curOp.selectionChanged true; }
    }); }
  };

  
ContentEditableInput.prototype.pollContent = function () {
    if (
this.readDOMTimeout != null) {
      
clearTimeout(this.readDOMTimeout);
      
this.readDOMTimeout null;
    }

    var 
cm this.cmdisplay cm.displaysel cm.doc.sel.primary();
    var 
from sel.from(), to sel.to();
    if (
from.ch == && from.line cm.firstLine())
      { 
from Pos(from.line 1getLine(cm.docfrom.line 1).length); }
    if (
to.ch == getLine(cm.docto.line).text.length && to.line cm.lastLine())
      { 
to Pos(to.line 10); }
    if (
from.line display.viewFrom || to.line display.viewTo 1) { return false }

    var 
fromIndexfromLinefromNode;
    if (
from.line == display.viewFrom || (fromIndex findViewIndex(cmfrom.line)) == 0) {
      
fromLine lineNo(display.view[0].line);
      
fromNode display.view[0].node;
    } else {
      
fromLine lineNo(display.view[fromIndex].line);
      
fromNode display.view[fromIndex 1].node.nextSibling;
    }
    var 
toIndex findViewIndex(cmto.line);
    var 
toLinetoNode;
    if (
toIndex == display.view.length 1) {
      
toLine display.viewTo 1;
      
toNode display.lineDiv.lastChild;
    } else {
      
toLine lineNo(display.view[toIndex 1].line) - 1;
      
toNode display.view[toIndex 1].node.previousSibling;
    }

    if (!
fromNode) { return false }
    var 
newText cm.doc.splitLines(domTextBetween(cmfromNodetoNodefromLinetoLine));
    var 
oldText getBetween(cm.docPos(fromLine0), Pos(toLinegetLine(cm.doctoLine).text.length));
    while (
newText.length && oldText.length 1) {
      if (
lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
      else if (
newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
      else { break }
    }

    var 
cutFront 0cutEnd 0;
    var 
newTop newText[0], oldTop oldText[0], maxCutFront Math.min(newTop.lengtholdTop.length);
    while (
cutFront maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
      { ++
cutFront; }
    var 
newBot lst(newText), oldBot lst(oldText);
    var 
maxCutEnd Math.min(newBot.length - (newText.length == cutFront 0),
                             
oldBot.length - (oldText.length == cutFront 0));
    while (
cutEnd maxCutEnd &&
           
newBot.charCodeAt(newBot.length cutEnd 1) == oldBot.charCodeAt(oldBot.length cutEnd 1))
      { ++
cutEnd; }
    
// Try to move start of change to start of selection if ambiguous
    
if (newText.length == && oldText.length == && fromLine == from.line) {
      while (
cutFront && cutFront from.ch &&
             
newBot.charCodeAt(newBot.length cutEnd 1) == oldBot.charCodeAt(oldBot.length cutEnd 1)) {
        
cutFront--;
        
cutEnd++;
      }
    }

    
newText[newText.length 1] = newBot.slice(0newBot.length cutEnd).replace(/^u200b+/, "");
    
newText[0] = newText[0].slice(cutFront).replace(/u200b+$/, "");

    var 
chFrom Pos(fromLinecutFront);
    var 
chTo Pos(toLineoldText.length lst(oldText).length cutEnd 0);
    if (
newText.length || newText[0] || cmp(chFromchTo)) {
      
replaceRange(cm.docnewTextchFromchTo"+input");
      return 
true
    
}
  };

  
ContentEditableInput.prototype.ensurePolled = function () {
    
this.forceCompositionEnd();
  };
  
ContentEditableInput.prototype.reset = function () {
    
this.forceCompositionEnd();
  };
  
ContentEditableInput.prototype.forceCompositionEnd = function () {
    if (!
this.composing) { return }
    
clearTimeout(this.readDOMTimeout);
    
this.composing null;
    
this.updateFromDOM();
    
this.div.blur();
    
this.div.focus();
  };
  
ContentEditableInput.prototype.readFromDOMSoon = function () {
      var 
this$this;

    if (
this.readDOMTimeout != null) { return }
    
this.readDOMTimeout setTimeout(function () {
      
this$1.readDOMTimeout null;
      if (
this$1.composing) {
        if (
this$1.composing.done) { this$1.composing null; }
        else { return }
      }
      
this$1.updateFromDOM();
    }, 
80);
  };

  
ContentEditableInput.prototype.updateFromDOM = function () {
      var 
this$this;

    if (
this.cm.isReadOnly() || !this.pollContent())
      { 
runInOp(this.cm, function () { return regChange(this$1.cm); }); }
  };

  
ContentEditableInput.prototype.setUneditable = function (node) {
    
node.contentEditable "false";
  };

  
ContentEditableInput.prototype.onKeyPress = function (e) {
    if (
e.charCode == || this.composing) { return }
    
e.preventDefault();
    if (!
this.cm.isReadOnly())
      { 
operation(this.cmapplyTextInput)(this.cmString.fromCharCode(e.charCode == null e.keyCode e.charCode), 0); }
  };

  
ContentEditableInput.prototype.readOnlyChanged = function (val) {
    
this.div.contentEditable String(val != "nocursor");
  };

  
ContentEditableInput.prototype.onContextMenu = function () {};
  
ContentEditableInput.prototype.resetPosition = function () {};

  
ContentEditableInput.prototype.needsContentAttribute true;

  function 
posToDOM(cmpos) {
    var 
view findViewForLine(cmpos.line);
    if (!
view || view.hidden) { return null }
    var 
line getLine(cm.docpos.line);
    var 
info mapFromLineView(viewlinepos.line);

    var 
order getOrder(linecm.doc.direction), side "left";
    if (
order) {
      var 
partPos getBidiPartAt(orderpos.ch);
      
side partPos "right" "left";
    }
    var 
result nodeAndOffsetInLineMap(info.mappos.chside);
    
result.offset result.collapse == "right" result.end result.start;
    return 
result
  
}

  function 
isInGutter(node) {
    for (var 
scan nodescanscan scan.parentNode)
      { if (/
CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
    return 
false
  
}

  function 
badPos(posbad) { if (bad) { pos.bad true; } return pos }

  function 
domTextBetween(cmfromtofromLinetoLine) {
    var 
text ""closing falselineSep cm.doc.lineSeparator(), extraLinebreak false;
    function 
recognizeMarker(id) { return function (marker) { return marker.id == id; } }
    function 
close() {
      if (
closing) {
        
text += lineSep;
        if (
extraLinebreak) { text += lineSep; }
        
closing extraLinebreak false;
      }
    }
    function 
addText(str) {
      if (
str) {
        
close();
        
text += str;
      }
    }
    function 
walk(node) {
      if (
node.nodeType == 1) {
        var 
cmText node.getAttribute("cm-text");
        if (
cmText) {
          
addText(cmText);
          return
        }
        var 
markerID node.getAttribute("cm-marker"), range;
        if (
markerID) {
          var 
found cm.findMarks(Pos(fromLine0), Pos(toLine 10), recognizeMarker(+markerID));
          if (
found.length && (range found[0].find(0)))
            { 
addText(getBetween(cm.docrange.fromrange.to).join(lineSep)); }
          return
        }
        if (
node.getAttribute("contenteditable") == "false") { return }
        var 
isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName);
        if (!/^
br$/i.test(node.nodeName) && node.textContent.length == 0) { return }

        if (
isBlock) { close(); }
        for (var 
0node.childNodes.lengthi++)
          { 
walk(node.childNodes[i]); }

        if (/^(
pre|p)$/i.test(node.nodeName)) { extraLinebreak true; }
        if (
isBlock) { closing true; }
      } else if (
node.nodeType == 3) {
        
addText(node.nodeValue.replace(/u200b/g"").replace(/u00a0/g" "));
      }
    }
    for (;;) {
      
walk(from);
      if (
from == to) { break }
      
from from.nextSibling;
      
extraLinebreak false;
    }
    return 
text
  
}

  function 
domToPos(cmnodeoffset) {
    var 
lineNode;
    if (
node == cm.display.lineDiv) {
      
lineNode cm.display.lineDiv.childNodes[offset];
      if (!
lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo 1)), true) }
      
node nulloffset 0;
    } else {
      for (
lineNode node;; lineNode lineNode.parentNode) {
        if (!
lineNode || lineNode == cm.display.lineDiv) { return null }
        if (
lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
      }
    }
    for (var 
0cm.display.view.lengthi++) {
      var 
lineView cm.display.view[i];
      if (
lineView.node == lineNode)
        { return 
locateNodeInLineView(lineViewnodeoffset) }
    }
  }

  function 
locateNodeInLineView(lineViewnodeoffset) {
    var 
wrapper lineView.text.firstChildbad false;
    if (!
node || !contains(wrappernode)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
    if (
node == wrapper) {
      
bad true;
      
node wrapper.childNodes[offset];
      
offset 0;
      if (!
node) {
        var 
line lineView.rest lst(lineView.rest) : lineView.line;
        return 
badPos(Pos(lineNo(line), line.text.length), bad)
      }
    }

    var 
textNode node.nodeType == node nulltopNode node;
    if (!
textNode && node.childNodes.length == && node.firstChild.nodeType == 3) {
      
textNode node.firstChild;
      if (
offset) { offset textNode.nodeValue.length; }
    }
    while (
topNode.parentNode != wrapper) { topNode topNode.parentNode; }
    var 
measure lineView.measuremaps measure.maps;

    function 
find(textNodetopNodeoffset) {
      for (var 
= -1< (maps maps.length 0); i++) {
        var 
map measure.map maps[i];
        for (var 
0map.length+= 3) {
          var 
curNode map[2];
          if (
curNode == textNode || curNode == topNode) {
            var 
line lineNo(lineView.line lineView.rest[i]);
            var 
ch map[j] + offset;
            if (
offset || curNode != textNode) { ch map[+ (offset 0)]; }
            return 
Pos(linech)
          }
        }
      }
    }
    var 
found find(textNodetopNodeoffset);
    if (
found) { return badPos(foundbad) }

    
// FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
    
for (var after topNode.nextSiblingdist textNode textNode.nodeValue.length offset 0afterafter after.nextSibling) {
      
found find(afterafter.firstChild0);
      if (
found)
        { return 
badPos(Pos(found.linefound.ch dist), bad) }
      else
        { 
dist += after.textContent.length; }
    }
    for (var 
before topNode.previousSiblingdist$offsetbeforebefore before.previousSibling) {
      
found find(beforebefore.firstChild, -1);
      if (
found)
        { return 
badPos(Pos(found.linefound.ch dist$1), bad) }
      else
        { 
dist$+= before.textContent.length; }
    }
  }

  
// TEXTAREA INPUT STYLE

  
var TextareaInput = function(cm) {
    
this.cm cm;
    
// See input.poll and input.reset
    
this.prevInput "";

    
// Flag that indicates whether we expect input to appear real soon
    // now (after some event like 'keypress' or 'input') and are
    // polling intensively.
    
this.pollingFast false;
    
// Self-resetting timeout for the poller
    
this.polling = new Delayed();
    
// Used to work around IE issue with selection being forgotten when focus moves away from textarea
    
this.hasSelection false;
    
this.composing null;
  };

  
TextareaInput.prototype.init = function (display) {
      var 
this$this;

    var 
input thiscm this.cm;
    
this.createField(display);
    var 
te this.textarea;

    
display.wrapper.insertBefore(this.wrapperdisplay.wrapper.firstChild);

    
// Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
    
if (ios) { te.style.width "0px"; }

    
on(te"input", function () {
      if (
ie && ie_version >= && this$1.hasSelection) { this$1.hasSelection null; }
      
input.poll();
    });

    
on(te"paste", function (e) {
      if (
signalDOMEvent(cme) || handlePaste(ecm)) { return }

      
cm.state.pasteIncoming = +new Date;
      
input.fastPoll();
    });

    function 
prepareCopyCut(e) {
      if (
signalDOMEvent(cme)) { return }
      if (
cm.somethingSelected()) {
        
setLastCopied({lineWisefalsetextcm.getSelections()});
      } else if (!
cm.options.lineWiseCopyCut) {
        return
      } else {
        var 
ranges copyableRanges(cm);
        
setLastCopied({lineWisetruetextranges.text});
        if (
e.type == "cut") {
          
cm.setSelections(ranges.rangesnullsel_dontScroll);
        } else {
          
input.prevInput "";
          
te.value ranges.text.join("n");
          
selectInput(te);
        }
      }
      if (
e.type == "cut") { cm.state.cutIncoming = +new Date; }
    }
    
on(te"cut"prepareCopyCut);
    
on(te"copy"prepareCopyCut);

    
on(display.scroller"paste", function (e) {
      if (
eventInWidget(displaye) || signalDOMEvent(cme)) { return }
      if (!
te.dispatchEvent) {
        
cm.state.pasteIncoming = +new Date;
        
input.focus();
        return
      }

      
// Pass the `paste` event to the textarea so it's handled by its event listener.
      
var event = new Event("paste");
      
event.clipboardData e.clipboardData;
      
te.dispatchEvent(event);
    });

    
// Prevent normal selection in the editor (we handle our own)
    
on(display.lineSpace"selectstart", function (e) {
      if (!
eventInWidget(displaye)) { e_preventDefault(e); }
    });

    
on(te"compositionstart", function () {
      var 
start cm.getCursor("from");
      if (
input.composing) { input.composing.range.clear(); }
      
input.composing = {
        
startstart,
        
rangecm.markText(startcm.getCursor("to"), {className"CodeMirror-composing"})
      };
    });
    
on(te"compositionend", function () {
      if (
input.composing) {
        
input.poll();
        
input.composing.range.clear();
        
input.composing null;
      }
    });
  };

  
TextareaInput.prototype.createField = function (_display) {
    
// Wraps and hides input textarea
    
this.wrapper hiddenTextarea();
    
// The semihidden textarea that is focused when the editor is
    // focused, and receives input.
    
this.textarea this.wrapper.firstChild;
  };

  
TextareaInput.prototype.screenReaderLabelChanged = function (label) {
    
// Label for screenreaders, accessibility
    
if(label) {
      
this.textarea.setAttribute('aria-label'label);
    } else {
      
this.textarea.removeAttribute('aria-label');
    }
  };

  
TextareaInput.prototype.prepareSelection = function () {
    
// Redraw the selection and/or cursor
    
var cm this.cmdisplay cm.displaydoc cm.doc;
    var 
result prepareSelection(cm);

    
// Move the hidden textarea near the cursor to prevent scrolling artifacts
    
if (cm.options.moveInputWithCursor) {
      var 
headPos cursorCoords(cmdoc.sel.primary().head"div");
      var 
wrapOff display.wrapper.getBoundingClientRect(), lineOff display.lineDiv.getBoundingClientRect();
      
result.teTop Math.max(0Math.min(display.wrapper.clientHeight 10,
                                          
headPos.top lineOff.top wrapOff.top));
      
result.teLeft Math.max(0Math.min(display.wrapper.clientWidth 10,
                                           
headPos.left lineOff.left wrapOff.left));
    }

    return 
result
  
};

  
TextareaInput.prototype.showSelection = function (drawn) {
    var 
cm this.cmdisplay cm.display;
    
removeChildrenAndAdd(display.cursorDivdrawn.cursors);
    
removeChildrenAndAdd(display.selectionDivdrawn.selection);
    if (
drawn.teTop != null) {
      
this.wrapper.style.top drawn.teTop "px";
      
this.wrapper.style.left drawn.teLeft "px";
    }
  };

  
// Reset the input to correspond to the selection (or to be empty,
  // when not typing and nothing is selected)
  
TextareaInput.prototype.reset = function (typing) {
    if (
this.contextMenuPending || this.composing) { return }
    var 
cm this.cm;
    if (
cm.somethingSelected()) {
      
this.prevInput "";
      var 
content cm.getSelection();
      
this.textarea.value content;
      if (
cm.state.focused) { selectInput(this.textarea); }
      if (
ie && ie_version >= 9) { this.hasSelection content; }
    } else if (!
typing) {
      
this.prevInput this.textarea.value "";
      if (
ie && ie_version >= 9) { this.hasSelection null; }
    }
  };

  
TextareaInput.prototype.getField = function () { return this.textarea };

  
TextareaInput.prototype.supportsTouch = function () { return false };

  
TextareaInput.prototype.focus = function () {
    if (
this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
      try { 
this.textarea.focus(); }
      catch (
e) {} // IE8 will throw if the textarea is display: none or not in DOM
    
}
  };

  
TextareaInput.prototype.blur = function () { this.textarea.blur(); };

  
TextareaInput.prototype.resetPosition = function () {
    
this.wrapper.style.top this.wrapper.style.left 0;
  };

  
TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };

  
// Poll for input changes, using the normal rate of polling. This
  // runs as long as the editor is focused.
  
TextareaInput.prototype.slowPoll = function () {
      var 
this$this;

    if (
this.pollingFast) { return }
    
this.polling.set(this.cm.options.pollInterval, function () {
      
this$1.poll();
      if (
this$1.cm.state.focused) { this$1.slowPoll(); }
    });
  };

  
// When an event has just come in that is likely to add or change
  // something in the input textarea, we poll faster, to ensure that
  // the change appears on the screen quickly.
  
TextareaInput.prototype.fastPoll = function () {
    var 
missed falseinput this;
    
input.pollingFast true;
    function 
p() {
      var 
changed input.poll();
      if (!
changed && !missed) {missed trueinput.polling.set(60p);}
      else {
input.pollingFast falseinput.slowPoll();}
    }
    
input.polling.set(20p);
  };

  
// Read input from the textarea, and update the document to match.
  // When something is selected, it is present in the textarea, and
  // selected (unless it is huge, in which case a placeholder is
  // used). When nothing is selected, the cursor sits after previously
  // seen text (can be empty), which is stored in prevInput (we must
  // not reset the textarea when typing, because that breaks IME).
  
TextareaInput.prototype.poll = function () {
      var 
this$this;

    var 
cm this.cminput this.textareaprevInput this.prevInput;
    
// Since this is called a *lot*, try to bail out as cheaply as
    // possible when it is clear that nothing happened. hasSelection
    // will be the case when there is a lot of text in the textarea,
    // in which case reading its value would be expensive.
    
if (this.contextMenuPending || !cm.state.focused ||
        (
hasSelection(input) && !prevInput && !this.composing) ||
        
cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
      { return 
false }

    var 
text input.value;
    
// If nothing changed, bail.
    
if (text == prevInput && !cm.somethingSelected()) { return false }
    
// Work around nonsensical selection resetting in IE9/10, and
    // inexplicable appearance of private area unicode characters on
    // some key combos in Mac (#2689).
    
if (ie && ie_version >= && this.hasSelection === text ||
        
mac && /[uf700-uf7ff]/.test(text)) {
      
cm.display.input.reset();
      return 
false
    
}

    if (
cm.doc.sel == cm.display.selForContextMenu) {
      var 
first text.charCodeAt(0);
      if (
first == 0x200b && !prevInput) { prevInput "u200b"; }
      if (
first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
    }
    
// Find the part of the input that is actually new
    
var same 0Math.min(prevInput.lengthtext.length);
    while (
same && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }

    
runInOp(cm, function () {
      
applyTextInput(cmtext.slice(same), prevInput.length same,
                     
nullthis$1.composing "*compose" null);

      
// Don't leave long text in the textarea, since it makes further polling slow
      
if (text.length 1000 || text.indexOf("n") > -1) { input.value this$1.prevInput ""; }
      else { 
this$1.prevInput text; }

      if (
this$1.composing) {
        
this$1.composing.range.clear();
        
this$1.composing.range cm.markText(this$1.composing.startcm.getCursor("to"),
                                           {
className"CodeMirror-composing"});
      }
    });
    return 
true
  
};

  
TextareaInput.prototype.ensurePolled = function () {
    if (
this.pollingFast && this.poll()) { this.pollingFast false; }
  };

  
TextareaInput.prototype.onKeyPress = function () {
    if (
ie && ie_version >= 9) { this.hasSelection null; }
    
this.fastPoll();
  };

  
TextareaInput.prototype.onContextMenu = function (e) {
    var 
input thiscm input.cmdisplay cm.displayte input.textarea;
    if (
input.contextMenuPending) { input.contextMenuPending(); }
    var 
pos posFromMouse(cme), scrollPos display.scroller.scrollTop;
    if (!
pos || presto) { return } // Opera is difficult.

    // Reset the current text selection only if the click is done outside of the selection
    // and 'resetSelectionOnContextMenu' option is true.
    
var reset cm.options.resetSelectionOnContextMenu;
    if (
reset && cm.doc.sel.contains(pos) == -1)
      { 
operation(cmsetSelection)(cm.docsimpleSelection(pos), sel_dontScroll); }

    var 
oldCSS te.style.cssTextoldWrapperCSS input.wrapper.style.cssText;
    var 
wrapperBox input.wrapper.offsetParent.getBoundingClientRect();
    
input.wrapper.style.cssText "position: static";
    
te.style.cssText "position: absolute; width: 30px; height: 30px;n      top: " + (e.clientY wrapperBox.top 5) + "px; left: " + (e.clientX wrapperBox.left 5) + "px;n      z-index: 1000; background: " + (ie "rgba(255, 255, 255, .05)" "transparent") + ";n      outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
    var 
oldScrollY;
    if (
webkit) { oldScrollY window.scrollY; } // Work around Chrome issue (#2712)
    
display.input.focus();
    if (
webkit) { window.scrollTo(nulloldScrollY); }
    
display.input.reset();
    
// Adds "Select all" to context menu in FF
    
if (!cm.somethingSelected()) { te.value input.prevInput " "; }
    
input.contextMenuPending rehide;
    
display.selForContextMenu cm.doc.sel;
    
clearTimeout(display.detectingSelectAll);

    
// Select-all will be greyed out if there's nothing to select, so
    // this adds a zero-width space so that we can later check whether
    // it got selected.
    
function prepareSelectAllHack() {
      if (
te.selectionStart != null) {
        var 
selected cm.somethingSelected();
        var 
extval "u200b" + (selected te.value "");
        
te.value "u21da"// Used to catch context-menu undo
        
te.value extval;
        
input.prevInput selected "" "u200b";
        
te.selectionStart 1te.selectionEnd extval.length;
        
// Re-set this, in case some other handler touched the
        // selection in the meantime.
        
display.selForContextMenu cm.doc.sel;
      }
    }
    function 
rehide() {
      if (
input.contextMenuPending != rehide) { return }
      
input.contextMenuPending false;
      
input.wrapper.style.cssText oldWrapperCSS;
      
te.style.cssText oldCSS;
      if (
ie && ie_version 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop scrollPos); }

      
// Try to detect the user choosing select-all
      
if (te.selectionStart != null) {
        if (!
ie || (ie && ie_version 9)) { prepareSelectAllHack(); }
        var 
0poll = function () {
          if (
display.selForContextMenu == cm.doc.sel && te.selectionStart == &&
              
te.selectionEnd && input.prevInput == "u200b") {
            
operation(cmselectAll)(cm);
          } else if (
i++ < 10) {
            
display.detectingSelectAll setTimeout(poll500);
          } else {
            
display.selForContextMenu null;
            
display.input.reset();
          }
        };
        
display.detectingSelectAll setTimeout(poll200);
      }
    }

    if (
ie && ie_version >= 9) { prepareSelectAllHack(); }
    if (
captureRightClick) {
      
e_stop(e);
      var 
mouseup = function () {
        
off(window"mouseup"mouseup);
        
setTimeout(rehide20);
      };
      
on(window"mouseup"mouseup);
    } else {
      
setTimeout(rehide50);
    }
  };

  
TextareaInput.prototype.readOnlyChanged = function (val) {
    if (!
val) { this.reset(); }
    
this.textarea.disabled val == "nocursor";
  };

  
TextareaInput.prototype.setUneditable = function () {};

  
TextareaInput.prototype.needsContentAttribute false;

  function 
fromTextArea(textareaoptions) {
    
options options copyObj(options) : {};
    
options.value textarea.value;
    if (!
options.tabindex && textarea.tabIndex)
      { 
options.tabindex textarea.tabIndex; }
    if (!
options.placeholder && textarea.placeholder)
      { 
options.placeholder textarea.placeholder; }
    
// Set autofocus to true if this textarea is focused, or if it has
    // autofocus and no other element is focused.
    
if (options.autofocus == null) {
      var 
hasFocus activeElt();
      
options.autofocus hasFocus == textarea ||
        
textarea.getAttribute("autofocus") != null && hasFocus == document.body;
    }

    function 
save() {textarea.value cm.getValue();}

    var 
realSubmit;
    if (
textarea.form) {
      
on(textarea.form"submit"save);
      
// Deplorable hack to make the submit method do the right thing.
      
if (!options.leaveSubmitMethodAlone) {
        var 
form textarea.form;
        
realSubmit form.submit;
        try {
          var 
wrappedSubmit form.submit = function () {
            
save();
            
form.submit realSubmit;
            
form.submit();
            
form.submit wrappedSubmit;
          };
        } catch(
e) {}
      }
    }

    
options.finishInit = function (cm) {
      
cm.save save;
      
cm.getTextArea = function () { return textarea; };
      
cm.toTextArea = function () {
        
cm.toTextArea isNaN// Prevent this from being ran twice
        
save();
        
textarea.parentNode.removeChild(cm.getWrapperElement());
        
textarea.style.display "";
        if (
textarea.form) {
          
off(textarea.form"submit"save);
          if (!
options.leaveSubmitMethodAlone && typeof textarea.form.submit == "function")
            { 
textarea.form.submit realSubmit; }
        }
      };
    };

    
textarea.style.display "none";
    var 
cm CodeMirror(function (node) { return textarea.parentNode.insertBefore(nodetextarea.nextSibling); },
      
options);
    return 
cm
  
}

  function 
addLegacyProps(CodeMirror) {
    
CodeMirror.off off;
    
CodeMirror.on on;
    
CodeMirror.wheelEventPixels wheelEventPixels;
    
CodeMirror.Doc Doc;
    
CodeMirror.splitLines splitLinesAuto;
    
CodeMirror.countColumn countColumn;
    
CodeMirror.findColumn findColumn;
    
CodeMirror.isWordChar isWordCharBasic;
    
CodeMirror.Pass Pass;
    
CodeMirror.signal signal;
    
CodeMirror.Line Line;
    
CodeMirror.changeEnd changeEnd;
    
CodeMirror.scrollbarModel scrollbarModel;
    
CodeMirror.Pos Pos;
    
CodeMirror.cmpPos cmp;
    
CodeMirror.modes modes;
    
CodeMirror.mimeModes mimeModes;
    
CodeMirror.resolveMode resolveMode;
    
CodeMirror.getMode getMode;
    
CodeMirror.modeExtensions modeExtensions;
    
CodeMirror.extendMode extendMode;
    
CodeMirror.copyState copyState;
    
CodeMirror.startState startState;
    
CodeMirror.innerMode innerMode;
    
CodeMirror.commands commands;
    
CodeMirror.keyMap keyMap;
    
CodeMirror.keyName keyName;
    
CodeMirror.isModifierKey isModifierKey;
    
CodeMirror.lookupKey lookupKey;
    
CodeMirror.normalizeKeyMap normalizeKeyMap;
    
CodeMirror.StringStream StringStream;
    
CodeMirror.SharedTextMarker SharedTextMarker;
    
CodeMirror.TextMarker TextMarker;
    
CodeMirror.LineWidget LineWidget;
    
CodeMirror.e_preventDefault e_preventDefault;
    
CodeMirror.e_stopPropagation e_stopPropagation;
    
CodeMirror.e_stop e_stop;
    
CodeMirror.addClass addClass;
    
CodeMirror.contains contains;
    
CodeMirror.rmClass rmClass;
    
CodeMirror.keyNames keyNames;
  }

  
// EDITOR CONSTRUCTOR

  
defineOptions(CodeMirror);

  
addEditorMethods(CodeMirror);

  
// Set up methods on CodeMirror's prototype to redirect to the editor's document.
  
var dontDelegate "iter insert remove copy getEditor constructor".split(" ");
  for (var 
prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegateprop) < 0)
    { 
CodeMirror.prototype[prop] = (function(method) {
      return function() {return 
method.apply(this.docarguments)}
    })(
Doc.prototype[prop]); } }

  
eventMixin(Doc);
  
CodeMirror.inputStyles = {"textarea"TextareaInput"contenteditable"ContentEditableInput};

  
// Extra arguments are stored as the mode's dependencies, which is
  // used by (legacy) mechanisms like loadmode.js to automatically
  // load a mode. (Preferred mechanism is the require/define calls.)
  
CodeMirror.defineMode = function(name/*, mode, …*/) {
    if (!
CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode name; }
    
defineMode.apply(thisarguments);
  };

  
CodeMirror.defineMIME defineMIME;

  
// Minimal default mode.
  
CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
  
CodeMirror.defineMIME("text/plain""null");

  
// EXTENSIONS

  
CodeMirror.defineExtension = function (namefunc) {
    
CodeMirror.prototype[name] = func;
  };
  
CodeMirror.defineDocExtension = function (namefunc) {
    
Doc.prototype[name] = func;
  };

  
CodeMirror.fromTextArea fromTextArea;

  
addLegacyProps(CodeMirror);

  
CodeMirror.version "5.54.0";

  return 
CodeMirror;

})));
?>
Онлайн: 1
Реклама