Full Code of AlloyTeam/omix for AI

master 5c6dab86edb0 cached
19 files
690.5 KB
200.3k tokens
542 symbols
1 requests
Download .txt
Showing preview only (712K chars total). Download the full file or copy to clipboard to get everything.
Repository: AlloyTeam/omix
Branch: master
Commit: 5c6dab86edb0
Files: 19
Total size: 690.5 KB

Directory structure:
gitextract_1jlpki56/

├── .eslintrc
├── .gitignore
├── README-CN.md
├── README.md
├── asset/
│   ├── codemirror.css
│   ├── codemirror.js
│   ├── show-hint.js
│   ├── sql-hint.js
│   └── sql-qone.js
├── index.html
├── package.json
├── qone.js
└── test/
    ├── clone.html
    ├── index.html
    ├── index.ie.html
    ├── lib/
    │   ├── qunit.css
    │   └── qunit.js
    ├── test.ie.js
    └── test.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc
================================================
{
    "extends": "standard",
    "rules": {
        "indent": [
            "error",
            4
        ],
        "space-before-function-paren": [
            "error",
            "never"
        ],
        "one-var": 0,
        "no-undef": 0,
        "eqeqeq": 0,
        "no-mixed-operators": 0,
        "camelcase": 0,
        "no-return-assign": 0
    }
}

================================================
FILE: .gitignore
================================================
/node_modules

================================================
FILE: README-CN.md
================================================
[English](./README.md) | 简体中文

<a href="##qone"><img src="./asset/qone.png" alt="qone"></a>
==============================
[![npm version](https://badge.fury.io/js/qone.svg)](https://www.npmjs.com/package/qone) 

.NET LINQ 在 javascript 中的实现

## 缘由

最近刚好修改了腾讯文档 Excel 表格公式的一些 bug,主要是修改公式的 parser 。比如下面的脚本怎么转成 javascript 运行?

``` js
= IF(SUM(J6:J7) + SUM(J6:J7) > 10, "A2 是 foo", "A2 不是 foo")
```

公式或一些脚本语言的实现包含几个主要步骤:

    scanner > lexer > parser > ast > code string

得到 code string 之后可以动态运行,比如 js 里使用 eval ,eval 能保留上下文信息,缺点是执行代码包含编译器代码,eval 的安全性等。
得到 code string 之后也可直接使用生成的 code string 运行,缺点是依赖构建工具或者编辑器插件去动态替换源代码。

比如 wind 同时支持 JIT 和 AOT, qone 的思路和上面类似,但不完全相同, qone 的如下:

    scanner > lexer > parser > ast > method(ast)

这个后面写原理时候再细说。

总的来说,因为腾讯文档公式相关工作、早年的 kmdjs 开发 (uglify2) 和 .NET 开发,所以有了 qone 。    

- [LINQ](#linq)
- [qone 安装](#qone-安装)
- [qone 关键字与运算符](#qone-关键字与运算符)
- [qone 方法注入](#qone-方法注入)      
- [qone select 输出](#qone-select-输出)   
- [qone orderby](#qone-orderby)
- [qone groupby](#qone-groupby)
- [qone 多数据源](#qone-多数据源)
- [qone 嵌套子数据源](#qone-嵌套子数据源)
- [qone limit 与分页查询](#qone-limit-与分页查询)
- [links](#star--fork--pr--repl--follow-me)
---

## LINQ

 LINQ (语言集成查询) 是 .NET Framework 3.5 版中引入的一项创新功能。在 Visual Studio 中,可以用 Visual Basic 或 C# 为以下数据源编写 LINQ 查询:SQL Server 数据库、XML 文档、ADO.NET 数据集,以及可枚举的 Objects(即 LINQ to Objects)。

qone 是一款让 Web 前端工程师在 javascript 使用 .NET 平台下类似 LINQ 语法的前端库。qone 让 Web 前端工程师通过字符串的形式实现了 LINQ to Objects 的调用(下面统一叫做 qone to objects),Objects即 JSON 组成的 Array。举个简单的例子(qone 远比下面的例子强大):

``` js
var list = [
    { name: 'qone', age: 1 },
    { name: 'linq', age: 18 },
    { name: 'dntzhang', age: 28 }
]

var result = qone({ list }).query(`
            from n in list   
            where n.age > 18
            select n
        `)

assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
```

与 LINQ 一样,和 SQL 不同,qone 的 from 也在前面,为后面语句能够有智能提示,qone 是基于 string 的实时编译,不是 javasript 的原生语法,所以虽然 from 写在前面但不支持智能提示,但可以专门为 qone 写个编辑器插件去实现智能提示,所以 qone 语法设计上依然把 from 放在前面。

从根本上说,qone to objects 表示一种新的处理集合的方法。 采用旧方法,您必须编写指定如何从集合检索数据的复杂的 foreach 循环。 而采用 qone 方法,您只需编写描述要检索的内容的声明性代码。
另外,与传统的 foreach 循环相比,qone 查询具有三大优势:

* 它们更简明、更易读,尤其在筛选多个条件时
* 它们使用最少的应用程序代码提供强大的筛选、排序和分组功能
* 无需修改或只需做很小的修改即可将它们移植到其他数据源

通常,您要对数据执行的操作越复杂,就越能体会到 qone 相较于传统迭代技术的优势。

## qone 安装

``` bash
npm install qone
```

CDN:

* [https://unpkg.com/qone@1.0.0/qone.js](https://unpkg.com/qone@1.0.0/qone.js)
* [https://unpkg.com/qone@1.0.0/qone.min.js](https://unpkg.com/qone@1.0.0/qone.min.js)

## qone 关键字与运算符

* from
* in
* where
* select
* orderby 
* desc
* asc
* groupby
* limit

其中 from 和 in 一起使用,orderby 和 desc 或者 asc 一起使用。

from 也可以把子属性作为 dataSource:

``` js
from n in data.list   
```

qone 支持下面三类运算符:

* 括号:( )
* 比较运算符: = , > , < , >= , <= , != 
* 与或非: && , || , !

条件判断语句也支持 null, undefined, true, false。

通过上面各种组合,你可以写出很复杂的查询条件。比如:

``` js
qone({ list }).query(`
    from n in list   
    where !(n.age > 17 || n.age < 2) && n.name != 'dntzhang'
    select n
`)
```

也支持 bool 类型的查询:

``` js
var list = [
    { name: 'qone', age: 1, isBaby: true },
    { name: 'linq', age: 18 },
    { name: 'dntzhang', age: 28 }]

var result = qone({ list }).query(`
        from a in list       
        where a.isBaby && n.name = 'qone'
        select a
    `)

assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }])
```

其中 isBaby 是 bool 类型,同样的写法:
a.isBaby = true   (等同于: a.isBaby)
a.isBaby = false  (等同于: !a.isBaby)

## qone 方法注入

通过上面介绍发现 qone 不支持加减乘除位求模运算?怎么才能图灵完备?方法注入搞定一切!如下所示:

``` js
QUnit.test("Method test 8", function (assert) {
    var arr = [1, 2, 3, 4, 5]

    qone('square', function (num) {
        return num * num
    })

    qone('sqrt', function (num) {
        return Math.sqrt(num)
    })

    var result = qone({ arr }).query(`
      from n in arr   
      where  sqrt(n) >= 2 
      select { squareValue : square(n) }
  `)

    assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }])
})
```

方法也是支持多参数传入,所以可以写出任意的查询条件。其中select, where, orderby, groupby 语句都支持方法注入。

## qone select 输出

通过 select 可以输出各种格式和字段的数据:

``` js
QUnit.test("Select JSON test", function (assert) {
    var list = [
        { name: 'qone', age: 1 },
        { name: 'linq', age: 18 },
        { name: 'dntzhang', age: 28 }
    ]

    var result = qone({ list }).query(`
                from n in list   
                where n.age < 20
                select {n.age, n.name}
            `)

    assert.deepEqual(result, [
        { "age": 1 , "name": "qone" },
        { "age": 18, "name": "linq" }
    ])

})
``` 

把所有场景列举一下:

* `select n` 输出源 item
* `select n.name` 输出一维表
* `select n.name, n.age` 输出二维表
* `select { n.age, n.name }` 缺省方式输出 JSON Array(key自动使用 age 和 name)
* `select { a: n.age, b: n.name }` 指定 key 输出 JSON Array
* `select { a: methodName(n.age), b: n.name }` 注入方法
* `select methodName(n.age), n.name` 注入方法
* `select methodName(n.age, n.name, 1, true, 'abc')` 注入方法并传递参数


## qone orderby


``` js
var result = qone({ list }).query(`
                from n in list   
                where n.age > 0
                orderby n.age asc, n.name desc
                select n
            `)

``` 

如果没有标记 asc 或者 desc,使用默认排序 asc。

## qone groupby

``` js
QUnit.test("Simple groupby test 1", function (assert) {
    var list = [
        { name: 'qone', age: 1 },
        { name: 'linq', age: 18 },
        { name: 'dntzhang1', age: 28 },
        { name: 'dntzhang2', age: 28 },
        { name: 'dntzhang3', age: 29 }
    ]

    var result = qone({ list }).query(`
                from n in list   
                where n.age > 18
                groupby n.age
            `)

    assert.deepEqual(result, [
        [{ "name": "dntzhang1", "age": 28 }, { "name": "dntzhang2", "age": 28 }],
        [{ "name": "dntzhang3", "age": 29 }]])

})
```

groupby 可以作为结束语句,不用跟着也不能跟着 select 语句,groupby 也可以支持方法注入。

## qone 多数据源 

``` js
QUnit.test("Multi datasource with props condition", function (assert) {

    var listA = [
        { name: 'qone', age: 1 },
        { name: 'linq', age: 18 },
        { name: 'dntzhang', age: 28 }]


    var listB = [
        { name: 'x', age: 11 },
        { name: 'xx', age: 18 },
        { name: 'xxx', age: 13 }
    ]

    var result = qone({ listA, listB }).query(`
            from a in listA     
            from b in listB      
            where a.age = b.age
            select a, b
        `)

    assert.deepEqual(result, [[{ "name": "linq", "age": 18 }, { "name": "xx", "age": 18 }]])
})
```

多数据源会产生笛卡儿积。

## qone 嵌套子数据源

``` js
QUnit.test("Multi deep from test ", function (assert) {

    var list = [
        { name: 'qone', age: 1, isBaby: true, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] },
        { name: 'linq', age: 18, colors: [{ xx: [100, 2, 3] }, { xx: [11, 2, 3] }] },
        { name: 'dntzhang', age: 28, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] }]

    var result = qone({ list }).query(`
            from a in list   
            from c in a.colors   
            from d in c.xx  
            where d === 100
            select a.name, c,d
        `)

    assert.deepEqual(result, [["linq", { "xx": [100, 2, 3] }, 100]])
})
```

也可以和自身的数据源会产生笛卡儿积。

## qone limit 与分页查询

通过 limit 可以应付最常见的两种查询场景 - top N 和 分页。

查询top3:

``` js
QUnit.test("Limit top 3", function (assert) {
    var list = [
        { name: 'dntzhang1', age: 1 },
        { name: 'dntzhang2', age: 2 },
        { name: 'dntzhang3', age: 3 },
        { name: 'dntzhang4', age: 4 },
        { name: 'dntzhang5', age: 5 },
        { name: 'dntzhang6', age: 6 },
        { name: 'dntzhang7', age: 7 },
        { name: 'dntzhang8', age: 8 },
        { name: 'dntzhang9', age: 9 },
        { name: 'dntzhang10', age: 10 }
    ]

    var pageIndex = 1,
        pageSize = 4
    var result = qone({ list }).query(`
                    from n in list   
                    select n
                    limit 0, 3
                `)


    assert.deepEqual(result, [

        { name: 'dntzhang1', age: 1 },
        { name: 'dntzhang2', age: 2 },
        { name: 'dntzhang3', age: 3 }
    ])

})
``` 

分页查询:

``` js
QUnit.test("Limit one page test", function (assert) {
    var list = [
        { name: 'dntzhang1', age: 1 },
        { name: 'dntzhang2', age: 2 },
        { name: 'dntzhang3', age: 3 },
        { name: 'dntzhang4', age: 4 },
        { name: 'dntzhang5', age: 5 },
        { name: 'dntzhang6', age: 6 },
        { name: 'dntzhang7', age: 7 },
        { name: 'dntzhang8', age: 8 },
        { name: 'dntzhang9', age: 9 },
        { name: 'dntzhang10', age: 10 }
    ]

    var pageIndex = 1,
        pageSize = 4
    var result = qone({ list }).query(`
                    from n in list   
                    where n.age > 0
                    select n
                    limit ${pageIndex * pageSize}, ${pageSize}
                `)


    assert.deepEqual(result, [
    { name: 'dntzhang5', age: 5 },
    { name: 'dntzhang6', age: 6 },
    { name: 'dntzhang7', age: 7 },
    { name: 'dntzhang8', age: 8 }])

})
``` 

## star & fork & pr & repl & follow me

* [https://github.com/dntzhang/qone](https://github.com/dntzhang/qone)
* [https://dntzhang.github.io/qone](https://dntzhang.github.io/qone)
* [https://github.com/dntzhang](https://github.com/dntzhang)


================================================
FILE: README.md
================================================

English | [简体中文](./README-CN.md) 


<a href="##qone"><img src="./asset/qone.png" alt="qone"></a>
==============================
[![npm version](https://badge.fury.io/js/qone.svg)](https://www.npmjs.com/package/qone) 

.NET LINQ in javascript


## The reason

Recently, it has just changed some bug of the Excel formula of the Tencent document, mainly modifying the parser of the formula.

For example, how can the following script be transformed to JavaScript?

``` js
= IF(SUM(J6:J7) + SUM(J6:J7) > 10, "A2 is foo", "A2 is not foo")
```

The implementation of formulas or scripting languages includes several main steps:

Scanner > lexer > parser > ast > code string

After getting code string, you can run (JIT) dynamically, such as using Eval in JS, Eval can retain context information, the disadvantage is that the execution code contains compiler code, and it is unsafe, and so on.
After getting code string, you can also use the generated code string to run (AOT) directly, and the disadvantage is to rely on the build tool or editor plug-in to dynamically replace the source code.

For example, wind supports JIT and AOT at the same time. Qone's thinking is similar to that above, but not exactly the same. Qone is as follows:

Scanner > lexer > parser > ast > method(ast)

The detailed principles will be written later. In general, the reasons are the work of the Tencent document formula, early kmdjs development (uglify2) and.NET development, so there is Qone.

- [LINQ](#linq)
- [qone install](#qone-install)
- [qone keyword and operator](#qone-keyword-and-operator)
- [qone method](#qone-method)      
- [qone select](#qone-select)   
- [qone orderby](#qone-orderby)
- [qone groupby](#qone-groupby) 
- [qone multiple data source](#qone-multiple-data-source)
- [qone subdata source](#qone-subdata-source)
- [qone limit and pagination](#qone-limit-and-pagination)
- [links](#star--fork--pr--repl--follow-me)
---

## LINQ

LINQ (language integrated query) is an innovative function introduced in.NET Framework 3.5. In Visual Studio, you can write LINQ queries with Visual Basic or C# for the following data sources: the SQL Server database, XML document, ADO.NET data set, and enumerable Objects.

Qone allows Web front-end engineers to use LINQ to Objects through js string or js template string, Objects is an array of JSON. Let me give you a simple example (Qone is much stronger than the following example):


``` js
var list = [
    { name: 'qone', age: 1 },
    { name: 'linq', age: 18 },
    { name: 'dntzhang', age: 28 }
]

var result = qone({ list }).query(`
            from n in list   
            where n.age > 18
            select n
        `)

assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
```

Qone's `from` keyword is also in front like LINQ, with intelligent prompts for the later statements,but qone is real-time compilation based on string, not the native syntax of javasript, so although from is written in the front but does not support intelligent hints.

## qone install

``` bash
npm install qone
```

or get it by CDN:

* [https://unpkg.com/qone@1.0.0/qone.js](https://unpkg.com/qone@1.0.0/qone.js)
* [https://unpkg.com/qone@1.0.0/qone.min.js](https://unpkg.com/qone@1.0.0/qone.min.js)

## qone keyword and operator

* from
* in
* where
* select
* orderby 
* desc
* asc
* groupby
* limit

from and in are used together, orderby and desc or asc are used together.

from can also take the sub attributes as dataSource:

``` js
from n in data.list   
```

Qone supports the following three class operators:

* brackets:( )
* comparison operator: = , > , < , >= , <= , != 
* and or not: && , || , !

Conditional judgement also supports null, undefined, true, false.

Through the above combinations, you can write complex query conditions. For example:

``` js
qone({ list }).query(`
    from n in list   
    where !(n.age > 17 || n.age < 2) && n.name != 'dntzhang'
    select n
`)
```

The bool type of query is also supported:

``` js
var list = [
    { name: 'qone', age: 1, isBaby: true },
    { name: 'linq', age: 18 },
    { name: 'dntzhang', age: 28 }]

var result = qone({ list }).query(`
        from a in list       
        where a.isBaby && n.name = 'qone'
        select a
    `)

assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }])
```

isBaby is the bool type, and the same way:
a.isBaby = true (equivalent to: a.isBaby)
a.isBaby = false (equivalent to: !a.isBaby)

## qone method

From the above, it is found that QOne does not support arithmetic operations of addition, subtraction, multiplication and division. How can be turing-complete ? Method injection to do everything! As shown below:

``` js
QUnit.test("Method test 8", function (assert) {
    var arr = [1, 2, 3, 4, 5]

    qone('square', function (num) {
        return num * num
    })

    qone('sqrt', function (num) {
        return Math.sqrt(num)
    })

    var result = qone({ arr }).query(`
      from n in arr   
      where  sqrt(n) >= 2 
      select { squareValue : square(n) }
  `)

    assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }])
})
```

The method also supports the introduction of multiple parameters, so it can write arbitrary query conditions. select, where, orderby, groupby statements support method injection.

## qone select

select can output data of various formats and fields:

``` js
QUnit.test("Select JSON test", function (assert) {
    var list = [
        { name: 'qone', age: 1 },
        { name: 'linq', age: 18 },
        { name: 'dntzhang', age: 28 }
    ]

    var result = qone({ list }).query(`
                from n in list   
                where n.age < 20
                select {n.age, n.name}
            `)

    assert.deepEqual(result, [
        { "age": 1 , "name": "qone" },
        { "age": 18, "name": "linq" }
    ])

})
``` 

List all the scenes:

* `select n` Output source item
* `select n.name` Output one-dimensional table
* `select n.name, n.age` Output two-dimensional table
* `select { n.age, n.name }` Output JSON Array by default (key automatically uses age and name).
* `select { a: n.age, b: n.name }` Specify the key output JSON Array
* `select { a: methodName(n.age), b: n.name }` Injection method
* `select methodName(n.age), n.name` Injection method
* `select methodName(n.age, n.name, 1, true, 'abc')` Injection method and transfer parameters



## qone orderby


``` js
var result = qone({ list }).query(`
                from n in list   
                where n.age > 0
                orderby n.age asc, n.name desc
                select n
            `)

``` 

If no asc or desc is marked, use the default sort asc.

## qone groupby

``` js
QUnit.test("Simple groupby test 1", function (assert) {
    var list = [
        { name: 'qone', age: 1 },
        { name: 'linq', age: 18 },
        { name: 'dntzhang1', age: 28 },
        { name: 'dntzhang2', age: 28 },
        { name: 'dntzhang3', age: 29 }
    ]

    var result = qone({ list }).query(`
                from n in list   
                where n.age > 18
                groupby n.age
            `)

    assert.deepEqual(result, [
        [{ "name": "dntzhang1", "age": 28 }, { "name": "dntzhang2", "age": 28 }],
        [{ "name": "dntzhang3", "age": 29 }]])

})
```

groupby can be used as an ending statement, without following or following select statements. groupby can also support method injection.

## qone multiple data source

``` js
QUnit.test("Multi datasource with props condition", function (assert) {

    var listA = [
        { name: 'qone', age: 1 },
        { name: 'linq', age: 18 },
        { name: 'dntzhang', age: 28 }]


    var listB = [
        { name: 'x', age: 11 },
        { name: 'xx', age: 18 },
        { name: 'xxx', age: 13 }
    ]

    var result = qone({ listA, listB }).query(`
            from a in listA     
            from b in listB      
            where a.age = b.age
            select a, b
        `)

    assert.deepEqual(result, [[{ "name": "linq", "age": 18 }, { "name": "xx", "age": 18 }]])
})
```

The multi data source produces Cartesian product.

## qone subdata source

``` js
QUnit.test("Multi deep from test ", function (assert) {

    var list = [
        { name: 'qone', age: 1, isBaby: true, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] },
        { name: 'linq', age: 18, colors: [{ xx: [100, 2, 3] }, { xx: [11, 2, 3] }] },
        { name: 'dntzhang', age: 28, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] }]

    var result = qone({ list }).query(`
            from a in list   
            from c in a.colors   
            from d in c.xx  
            where d === 100
            select a.name, c,d
        `)

    assert.deepEqual(result, [["linq", { "xx": [100, 2, 3] }, 100]])
})
```

It can also produce Cartesian product with its own data source.

## qone limit and pagination

Limit can cope with the two most common query scenarios - top N and paging.

Query top3:

``` js
QUnit.test("Limit top 3", function (assert) {
    var list = [
        { name: 'dntzhang1', age: 1 },
        { name: 'dntzhang2', age: 2 },
        { name: 'dntzhang3', age: 3 },
        { name: 'dntzhang4', age: 4 },
        { name: 'dntzhang5', age: 5 },
        { name: 'dntzhang6', age: 6 },
        { name: 'dntzhang7', age: 7 },
        { name: 'dntzhang8', age: 8 },
        { name: 'dntzhang9', age: 9 },
        { name: 'dntzhang10', age: 10 }
    ]

    var pageIndex = 1,
        pageSize = 4
    var result = qone({ list }).query(`
                    from n in list   
                    select n
                    limit 0, 3
                `)


    assert.deepEqual(result, [

        { name: 'dntzhang1', age: 1 },
        { name: 'dntzhang2', age: 2 },
        { name: 'dntzhang3', age: 3 }
    ])

})
``` 

Paging query:

``` js
QUnit.test("Limit one page test", function (assert) {
    var list = [
        { name: 'dntzhang1', age: 1 },
        { name: 'dntzhang2', age: 2 },
        { name: 'dntzhang3', age: 3 },
        { name: 'dntzhang4', age: 4 },
        { name: 'dntzhang5', age: 5 },
        { name: 'dntzhang6', age: 6 },
        { name: 'dntzhang7', age: 7 },
        { name: 'dntzhang8', age: 8 },
        { name: 'dntzhang9', age: 9 },
        { name: 'dntzhang10', age: 10 }
    ]

    var pageIndex = 1,
        pageSize = 4
    var result = qone({ list }).query(`
                    from n in list   
                    where n.age > 0
                    select n
                    limit ${pageIndex * pageSize}, ${pageSize}
                `)


    assert.deepEqual(result, [
    { name: 'dntzhang5', age: 5 },
    { name: 'dntzhang6', age: 6 },
    { name: 'dntzhang7', age: 7 },
    { name: 'dntzhang8', age: 8 }])

})
``` 

## star & fork & pr & repl & follow me

* [https://github.com/dntzhang/qone](https://github.com/dntzhang/qone)
* [https://dntzhang.github.io/qone](https://dntzhang.github.io/qone)
* [https://github.com/dntzhang](https://github.com/dntzhang)


================================================
FILE: asset/codemirror.css
================================================
/* BASICS */

.CodeMirror {
  /* Set height, width, borders, and global font properties here */
  font-family: monospace;
  height: 300px;
  color: black;
  direction: ltr;
}

/* PADDING */

.CodeMirror-lines {
  padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
  padding: 0 4px; /* Horizontal padding of content */
}

.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
  background-color: white; /* The little square between H and V scrollbars */
}

/* GUTTER */

.CodeMirror-gutters {
  border-right: 1px solid #ddd;
  background-color: #f7f7f7;
  white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
  padding: 0 3px 0 5px;
  min-width: 20px;
  text-align: right;
  color: #999;
  white-space: nowrap;
}

.CodeMirror-guttermarker { color: black; }
.CodeMirror-guttermarker-subtle { color: #999; }

/* CURSOR */

.CodeMirror-cursor {
  border-left: 1px solid black;
  border-right: none;
  width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
  border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
  width: auto;
  border: 0 !important;
  background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
  z-index: 1;
}
.cm-fat-cursor-mark {
  background-color: rgba(20, 255, 20, 0.5);
  -webkit-animation: blink 1.06s steps(1) infinite;
  -moz-animation: blink 1.06s steps(1) infinite;
  animation: blink 1.06s steps(1) infinite;
}
.cm-animate-fat-cursor {
  width: auto;
  border: 0;
  -webkit-animation: blink 1.06s steps(1) infinite;
  -moz-animation: blink 1.06s steps(1) infinite;
  animation: blink 1.06s steps(1) infinite;
  background-color: #7e7;
}
@-moz-keyframes blink {
  0% {}
  50% { background-color: transparent; }
  100% {}
}
@-webkit-keyframes blink {
  0% {}
  50% { background-color: transparent; }
  100% {}
}
@keyframes blink {
  0% {}
  50% { background-color: transparent; }
  100% {}
}

/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror-overwrite .CodeMirror-cursor {}

.cm-tab { display: inline-block; text-decoration: inherit; }

.CodeMirror-rulers {
  position: absolute;
  left: 0; right: 0; top: -50px; bottom: -20px;
  overflow: hidden;
}
.CodeMirror-ruler {
  border-left: 1px solid #ccc;
  top: 0; bottom: 0;
  position: absolute;
}

/* DEFAULT THEME */

.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-strikethrough {text-decoration: line-through;}

.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable,
.cm-s-default .cm-punctuation,
.cm-s-default .cm-property,
.cm-s-default .cm-operator {}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}

.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}

.CodeMirror-composing { border-bottom: 2px solid; }

/* Default styles for common addons */

div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
.CodeMirror-activeline-background {background: #e8f2ff;}

/* STOP */

/* The rest of this file contains styles related to the mechanics of
   the editor. You probably shouldn't touch them. */

.CodeMirror {
  position: relative;
  overflow: hidden;
  background: white;
}

.CodeMirror-scroll {
  overflow: scroll !important; /* Things will break if this is overridden */
  /* 30px is the magic margin used to hide the element's real scrollbars */
  /* See overflow: hidden in .CodeMirror */
  margin-bottom: -30px; margin-right: -30px;
  padding-bottom: 30px;
  height: 100%;
  outline: none; /* Prevent dragging from highlighting the element */
  position: relative;
}
.CodeMirror-sizer {
  position: relative;
  border-right: 30px solid transparent;
}

/* The fake, visible scrollbars. Used to force redraw during scrolling
   before actual scrolling happens, thus preventing shaking and
   flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
  position: absolute;
  z-index: 6;
  display: none;
}
.CodeMirror-vscrollbar {
  right: 0; top: 0;
  overflow-x: hidden;
  overflow-y: scroll;
}
.CodeMirror-hscrollbar {
  bottom: 0; left: 0;
  overflow-y: hidden;
  overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
  right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
  left: 0; bottom: 0;
}

.CodeMirror-gutters {
  position: absolute; left: 0; top: 0;
  min-height: 100%;
  z-index: 3;
}
.CodeMirror-gutter {
  white-space: normal;
  height: 100%;
  display: inline-block;
  vertical-align: top;
  margin-bottom: -30px;
}
.CodeMirror-gutter-wrapper {
  position: absolute;
  z-index: 4;
  background: none !important;
  border: none !important;
}
.CodeMirror-gutter-background {
  position: absolute;
  top: 0; bottom: 0;
  z-index: 4;
}
.CodeMirror-gutter-elt {
  position: absolute;
  cursor: default;
  z-index: 4;
}
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }

.CodeMirror-lines {
  cursor: text;
  min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre {
  /* Reset some styles that the rest of the page might have set */
  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
  border-width: 0;
  background: transparent;
  font-family: inherit;
  font-size: inherit;
  margin: 0;
  white-space: pre;
  word-wrap: normal;
  line-height: inherit;
  color: inherit;
  z-index: 2;
  position: relative;
  overflow: visible;
  -webkit-tap-highlight-color: transparent;
  -webkit-font-variant-ligatures: contextual;
  font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre {
  word-wrap: break-word;
  white-space: pre-wrap;
  word-break: normal;
}

.CodeMirror-linebackground {
  position: absolute;
  left: 0; right: 0; top: 0; bottom: 0;
  z-index: 0;
}

.CodeMirror-linewidget {
  position: relative;
  z-index: 2;
  padding: 0.1px; /* Force widget margins to stay inside of the container */
}

.CodeMirror-widget {}

.CodeMirror-rtl pre { direction: rtl; }

.CodeMirror-code {
  outline: none;
}

/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
}

.CodeMirror-measure {
  position: absolute;
  width: 100%;
  height: 0;
  overflow: hidden;
  visibility: hidden;
}

.CodeMirror-cursor {
  position: absolute;
  pointer-events: none;
}
.CodeMirror-measure pre { position: static; }

div.CodeMirror-cursors {
  visibility: hidden;
  position: relative;
  z-index: 3;
}
div.CodeMirror-dragcursors {
  visibility: visible;
}

.CodeMirror-focused div.CodeMirror-cursors {
  visibility: visible;
}

.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }

.cm-searching {
  background-color: #ffa;
  background-color: rgba(255, 255, 0, .4);
}

/* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; }

@media print {
  /* Hide the cursor when printing */
  .CodeMirror div.CodeMirror-cursors {
    visibility: hidden;
  }
}

/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }

/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }


================================================
FILE: asset/codemirror.js
================================================
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// This is CodeMirror (http://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.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 ie = ie_upto10 || ie_11up
  var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1])
  var webkit = /WebKit\//.test(userAgent)
  var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent)
  var chrome = /Chrome\//.test(userAgent)
  var presto = /Opera\//.test(userAgent)
  var safari = /Apple Computer/.test(navigator.vendor)
  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent)
  var phantom = /PhantomJS/.test(userAgent)
  
  var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.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 = /\bCrOS\b/.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 = false; webkit = 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(node, cls) {
	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(0, match.index) + (after ? match[1] + after : "")
	}
  }
  
  function removeChildren(e) {
	for (var count = e.childNodes.length; count > 0; --count)
	  { e.removeChild(e.firstChild) }
	return e
  }
  
  function removeChildrenAndAdd(parent, e) {
	return removeChildren(parent).appendChild(e)
  }
  
  function elt(tag, content, className, style) {
	var e = 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 i = 0; i < content.length; ++i) { e.appendChild(content[i]) } }
	return e
  }
  
  var range
  if (document.createRange) { range = function(node, start, end, endNode) {
	var r = document.createRange()
	r.setEnd(endNode || node, end)
	r.setStart(node, start)
	return r
  } }
  else { range = function(node, start, end) {
	var r = document.body.createTextRange()
	try { r.moveToElementText(node.parentNode) }
	catch(e) { return r }
	r.collapse(true)
	r.moveEnd("character", end)
	r.moveStart("character", start)
	return r
  } }
  
  function contains(parent, child) {
	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)
  }
  
  var activeElt = function() {
	var activeElement = document.activeElement
	while (activeElement && activeElement.root && activeElement.root.activeElement)
	  { activeElement = activeElement.root.activeElement }
	return activeElement
  }
  // Older versions of IE throws unspecified error when touching
  // document.activeElement in some cases (during loading, in iframe)
  if (ie && ie_version < 11) { activeElt = function() {
	try { return document.activeElement }
	catch(e) { return document.body }
  } }
  
  function addClass(node, cls) {
	var current = node.className
	if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls }
  }
  function joinClasses(a, b) {
	var as = a.split(" ")
	for (var i = 0; i < as.length; i++)
	  { if (as[i] && !classTest(as[i]).test(b)) { 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 = 0; node.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(arguments, 1)
	return function(){return f.apply(null, args)}
  }
  
  function copyObj(obj, target, overwrite) {
	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(string, end, tabSize, startIndex, startValue) {
	if (end == null) {
	  end = string.search(/[^\s\u00a0]/)
	  if (end == -1) { end = string.length }
	}
	for (var i = startIndex || 0, n = startValue || 0;;) {
	  var nextTab = string.indexOf("\t", i)
	  if (nextTab < 0 || nextTab >= end)
		{ return n + (end - i) }
	  n += nextTab - i
	  n += tabSize - (n % tabSize)
	  i = nextTab + 1
	}
  }
  
  function Delayed() {this.id = null}
  Delayed.prototype.set = function(ms, f) {
	clearTimeout(this.id)
	this.id = setTimeout(f, ms)
  }
  
  function indexOf(array, elt) {
	for (var i = 0; i < array.length; ++i)
	  { if (array[i] == elt) { return i } }
	return -1
  }
  
  // Number of pixels added to scroller and sizer to hide scrollbar
  var scrollerGap = 30
  
  // 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 = {scroll: false};
  var sel_mouse = {origin: "*mouse"};
  var sel_move = {origin: "+move"};
  // The inverse of countColumn -- find the offset that corresponds to
  // a particular column.
  function findColumn(string, goal, tabSize) {
	for (var pos = 0, col = 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(skipped, goal - 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 i = 0; i < array.length; i++) { out[i] = f(array[i], i) }
	return out
  }
  
  function insertSorted(array, value, score) {
	var pos = 0, priority = score(value)
	while (pos < array.length && score(array[pos]) <= priority) { pos++ }
	array.splice(pos, 0, value)
  }
  
  function nothing() {}
  
  function createObj(base, props) {
	var inst
	if (Object.create) {
	  inst = Object.create(base)
	} else {
	  nothing.prototype = base
	  inst = new nothing()
	}
	if (props) { copyObj(props, inst) }
	return inst
  }
  
  var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/
  function isWordCharBasic(ch) {
	return /\w/.test(ch) || ch > "\x80" &&
	  (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
  }
  function isWordChar(ch, helper) {
	if (!helper) { return isWordCharBasic(ch) }
	if (helper.source.indexOf("\\w") > -1 && 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-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/
  function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
  
  // 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(place, doc, input) {
	var d = 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 = elt("div", null, "CodeMirror-code")
	// Elements are added to these to represent selection and cursors.
	d.selectionDiv = elt("div", null, null, "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 = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
					  null, "position: relative; outline: none")
	// Moved around its parent to cover visible view.
	d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-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", null, null, "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.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll")
	d.scroller.setAttribute("tabIndex", "-1")
	// The element in which the editor lives.
	d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.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 = -1; d.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
  
	input.init(d)
  }
  
  // Find the line object corresponding to the given line number.
  function getLine(doc, n) {
	n -= doc.first
	if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
	var chunk = doc
	while (!chunk.lines) {
	  for (var i = 0;; ++i) {
		var child = chunk.children[i], sz = child.chunkSize()
		if (n < sz) { chunk = child; break }
		n -= sz
	  }
	}
	return chunk.lines[n]
  }
  
  // Get the part of a document between two positions, as an array of
  // strings.
  function getBetween(doc, start, end) {
	var out = [], n = start.line
	doc.iter(start.line, end.line + 1, function (line) {
	  var text = line.text
	  if (n == end.line) { text = text.slice(0, end.ch) }
	  if (n == 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(doc, from, to) {
	var out = []
	doc.iter(from, to, 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(line, height) {
	var diff = height - line.height
	if (diff) { for (var n = line; n; n = n.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.parent, no = indexOf(cur.lines, line)
	for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
	  for (var i = 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(chunk, h) {
	var n = chunk.first
	outer: do {
	  for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
		var child = chunk.children[i$1], ch = child.height
		if (h < ch) { chunk = child; continue outer }
		h -= ch
		n += child.chunkSize()
	  }
	  return n
	} while (!chunk.lines)
	var i = 0
	for (; i < chunk.lines.length; ++i) {
	  var line = chunk.lines[i], lh = line.height
	  if (h < lh) { break }
	  h -= lh
	}
	return n + i
  }
  
  function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
  
  function lineNumberFor(options, i) {
	return String(options.lineNumberFormatter(i + options.firstLineNumber))
  }
  
  // A Pos instance represents a position within the text.
  function Pos (line, ch) {
	if (!(this instanceof Pos)) { return new Pos(line, ch) }
	this.line = line; this.ch = ch
  }
  
  // Compare two positions, return 0 if they are the same, a negative
  // number when a is less, and a positive number otherwise.
  function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
  
  function copyPos(x) {return Pos(x.line, x.ch)}
  function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
  function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
  
  // Most of the external API clips given positions to make sure they
  // actually exist within the document.
  function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
  function clipPos(doc, pos) {
	if (pos.line < doc.first) { return Pos(doc.first, 0) }
	var last = doc.first + doc.size - 1
	if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
	return clipToLen(pos, getLine(doc, pos.line).text.length)
  }
  function clipToLen(pos, linelen) {
	var ch = pos.ch
	if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
	else if (ch < 0) { return Pos(pos.line, 0) }
	else { return pos }
  }
  function clipPosArray(doc, array) {
	var out = []
	for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]) }
	return out
  }
  
  // Optimize some code when these features are not used.
  var sawReadOnlySpans = false;
  var sawCollapsedSpans = false;
  function seeReadOnlySpans() {
	sawReadOnlySpans = true
  }
  
  function seeCollapsedSpans() {
	sawCollapsedSpans = true
  }
  
  // TEXTMARKER SPANS
  
  function MarkedSpan(marker, from, to) {
	this.marker = marker
	this.from = from; this.to = to
  }
  
  // Search an array of spans for a span matching the given marker.
  function getMarkedSpanFor(spans, marker) {
	if (spans) { for (var i = 0; i < spans.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(spans, span) {
	var r
	for (var i = 0; i < spans.length; ++i)
	  { if (spans[i] != span) { (r || (r = [])).push(spans[i]) } }
	return r
  }
  // Add a span to a line.
  function addMarkedSpan(line, span) {
	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(old, startCh, isInsert) {
	var nw
	if (old) { for (var i = 0; i < old.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(marker, span.from, endsAfter ? null : span.to))
	  }
	} }
	return nw
  }
  function markedSpansAfter(old, endCh, isInsert) {
	var nw
	if (old) { for (var i = 0; i < old.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(marker, startsBefore ? 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(doc, change) {
	if (change.full) { return null }
	var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans
	var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans
	if (!oldFirst && !oldLast) { return null }
  
	var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0
	// Get the spans that 'stick out' on both sides
	var first = markedSpansBefore(oldFirst, startCh, isInsert)
	var last = markedSpansAfter(oldLast, endCh, isInsert)
  
	// Next, merge those two ends
	var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0)
	if (first) {
	  // Fix up .to properties of first
	  for (var i = 0; i < first.length; ++i) {
		var span = first[i]
		if (span.to == null) {
		  var found = getMarkedSpanFor(last, span.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$1 = 0; i$1 < last.length; ++i$1) {
		var span$1 = last[i$1]
		if (span$1.to != null) { span$1.to += offset }
		if (span$1.from == null) {
		  var found$1 = getMarkedSpanFor(first, span$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 - 2, gapMarkers
	  if (gap > 0 && first)
		{ for (var i$2 = 0; i$2 < first.length; ++i$2)
		  { if (first[i$2].to == null)
			{ (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)) } } }
	  for (var i$3 = 0; i$3 < 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 i = 0; i < spans.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(doc, from, to) {
	var markers = null
	doc.iter(from.line, to.line + 1, function (line) {
	  if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
		var mark = line.markedSpans[i].marker
		if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
		  { (markers || (markers = [])).push(mark) }
	  } }
	})
	if (!markers) { return null }
	var parts = [{from: from, to: to}]
	for (var i = 0; i < markers.length; ++i) {
	  var mk = markers[i], m = mk.find(0)
	  for (var j = 0; j < parts.length; ++j) {
		var p = parts[j]
		if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
		var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to)
		if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
		  { newParts.push({from: p.from, to: m.from}) }
		if (dto > 0 || !mk.inclusiveRight && !dto)
		  { newParts.push({from: m.to, to: p.to}) }
		parts.splice.apply(parts, newParts)
		j += newParts.length - 1
	  }
	}
	return parts
  }
  
  // Connect or disconnect spans from a line.
  function detachMarkedSpans(line) {
	var spans = line.markedSpans
	if (!spans) { return }
	for (var i = 0; i < spans.length; ++i)
	  { spans[i].marker.detachLine(line) }
	line.markedSpans = null
  }
  function attachMarkedSpans(line, spans) {
	if (!spans) { return }
	for (var i = 0; i < spans.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 ? -1 : 0 }
  function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
  
  // 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(a, b) {
	var lenDiff = a.lines.length - b.lines.length
	if (lenDiff != 0) { return lenDiff }
	var aPos = a.find(), bPos = b.find()
	var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b)
	if (fromCmp) { return -fromCmp }
	var toCmp = cmp(aPos.to, bPos.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(line, start) {
	var sps = sawCollapsedSpans && line.markedSpans, found
	if (sps) { for (var sp = void 0, i = 0; i < sps.length; ++i) {
	  sp = sps[i]
	  if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
		  (!found || compareCollapsedMarkers(found, sp.marker) < 0))
		{ found = sp.marker }
	} }
	return found
  }
  function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
  function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
  
  // 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(doc, lineNo, from, to, marker) {
	var line = getLine(doc, lineNo)
	var sps = sawCollapsedSpans && line.markedSpans
	if (sps) { for (var i = 0; i < sps.length; ++i) {
	  var sp = sps[i]
	  if (!sp.marker.collapsed) { continue }
	  var found = sp.marker.find(0)
	  var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker)
	  var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker)
	  if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
	  if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
		  fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 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(-1, true).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 merged, lines
	while (merged = collapsedSpanAtEnd(line)) {
	  line = merged.find(1, true).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(doc, lineN) {
	var line = getLine(doc, lineN), 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(doc, lineN) {
	if (lineN > doc.lastLine()) { return lineN }
	var line = getLine(doc, lineN), merged
	if (!lineIsHidden(doc, line)) { return lineN }
	while (merged = collapsedSpanAtEnd(line))
	  { line = merged.find(1, true).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(doc, line) {
	var sps = sawCollapsedSpans && line.markedSpans
	if (sps) { for (var sp = void 0, i = 0; i < sps.length; ++i) {
	  sp = sps[i]
	  if (!sp.marker.collapsed) { continue }
	  if (sp.from == null) { return true }
	  if (sp.marker.widgetNode) { continue }
	  if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
		{ return true }
	} }
  }
  function lineIsHiddenInner(doc, line, span) {
	if (span.to == null) {
	  var end = span.marker.find(1, true)
	  return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
	}
	if (span.marker.inclusiveRight && span.to == line.text.length)
	  { return true }
	for (var sp = void 0, i = 0; i < line.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(doc, line, sp)) { return true }
	}
  }
  
  // Find the height above the given line.
  function heightAtLine(lineObj) {
	lineObj = visualLine(lineObj)
  
	var h = 0, chunk = lineObj.parent
	for (var i = 0; i < chunk.lines.length; ++i) {
	  var line = chunk.lines[i]
	  if (line == lineObj) { break }
	  else { h += line.height }
	}
	for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
	  for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
		var cur = p.children[i$1]
		if (cur == chunk) { break }
		else { h += 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 0 }
	var len = line.text.length, merged, cur = line
	while (merged = collapsedSpanAtStart(cur)) {
	  var found = merged.find(0, true)
	  cur = found.from.line
	  len += found.from.ch - found.to.ch
	}
	cur = line
	while (merged = collapsedSpanAtEnd(cur)) {
	  var found$1 = merged.find(0, true)
	  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 d = cm.display, doc = cm.doc
	d.maxLine = getLine(doc, doc.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
	  }
	})
  }
  
  // BIDI HELPERS
  
  function iterateBidiSections(order, from, to, f) {
	if (!order) { return f(from, to, "ltr") }
	var found = false
	for (var i = 0; i < order.length; ++i) {
	  var part = order[i]
	  if (part.from < to && part.to > from || from == to && part.to == from) {
		f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr")
		found = true
	  }
	}
	if (!found) { f(from, to, "ltr") }
  }
  
  function bidiLeft(part) { return part.level % 2 ? part.to : part.from }
  function bidiRight(part) { return part.level % 2 ? part.from : part.to }
  
  function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0 }
  function lineRight(line) {
	var order = getOrder(line)
	if (!order) { return line.text.length }
	return bidiRight(lst(order))
  }
  
  function compareBidiLevel(order, a, b) {
	var linedir = order[0].level
	if (a == linedir) { return true }
	if (b == linedir) { return false }
	return a < b
  }
  
  var bidiOther = null
  function getBidiPartAt(order, pos) {
	var found
	bidiOther = null
	for (var i = 0; i < order.length; ++i) {
	  var cur = order[i]
	  if (cur.from < pos && cur.to > pos) { return i }
	  if ((cur.from == pos || cur.to == pos)) {
		if (found == null) {
		  found = i
		} else if (compareBidiLevel(order, cur.level, order[found].level)) {
		  if (cur.from != cur.to) { bidiOther = found }
		  return i
		} else {
		  if (cur.from != cur.to) { bidiOther = i }
		  return found
		}
	  }
	}
	return found
  }
  
  function moveInLine(line, pos, dir, byUnit) {
	if (!byUnit) { return pos + dir }
	do { pos += dir }
	while (pos > 0 && isExtendingChar(line.text.charAt(pos)))
	return pos
  }
  
  // This is needed in order to move 'visually' through bi-directional
  // text -- i.e., pressing left should make the cursor go left, even
  // when in RTL text. The tricky part is the 'jumps', where RTL and
  // LTR text touch each other. This often requires the cursor offset
  // to move more than one unit, in order to visually move one unit.
  function moveVisually(line, start, dir, byUnit) {
	var bidi = getOrder(line)
	if (!bidi) { return moveLogically(line, start, dir, byUnit) }
	var pos = getBidiPartAt(bidi, start), part = bidi[pos]
	var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit)
  
	for (;;) {
	  if (target > part.from && target < part.to) { return target }
	  if (target == part.from || target == part.to) {
		if (getBidiPartAt(bidi, target) == pos) { return target }
		part = bidi[pos += dir]
		return (dir > 0) == part.level % 2 ? part.to : part.from
	  } else {
		part = bidi[pos += dir]
		if (!part) { return null }
		if ((dir > 0) == part.level % 2)
		  { target = moveInLine(line, part.to, -1, byUnit) }
		else
		  { target = moveInLine(line, part.from, 1, byUnit) }
	  }
	}
  }
  
  function moveLogically(line, start, dir, byUnit) {
	var target = start + dir
	if (byUnit) { while (target > 0 && isExtendingChar(line.text.charAt(target))) { target += dir } }
	return target < 0 || target > line.text.length ? null : target
  }
  
  // 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 0x6ff
	var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"
	function charType(code) {
	  if (code <= 0xf7) { return lowTypes.charAt(code) }
	  else if (0x590 <= code && code <= 0x5f4) { return "R" }
	  else if (0x600 <= code && code <= 0x6ed) { 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-\u05f4\u0600-\u06ff\u0700-\u08ac]/
	var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/
	// Browsers seem to always treat the boundaries of block elements as being L.
	var outerType = "L"
  
	function BidiSpan(level, from, to) {
	  this.level = level
	  this.from = from; this.to = to
	}
  
	return function(str) {
	  if (!bidiRE.test(str)) { return false }
	  var len = str.length, types = []
	  for (var i = 0; i < len; ++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$1 = 0, prev = outerType; i$1 < 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$2 = 0, cur = outerType; i$2 < len; ++i$2) {
		var type$1 = types[i$2]
		if (type$1 == "1" && cur == "r") { types[i$2] = "n" }
		else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "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$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
		var type$2 = types[i$3]
		if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1" }
		else if (type$2 == "," && prev$1 == types[i$3+1] &&
				 (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1 }
		prev$1 = 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$4 = 0; i$4 < len; ++i$4) {
		var type$3 = types[i$4]
		if (type$3 == ",") { types[i$4] = "N" }
		else if (type$3 == "%") {
		  var end = void 0
		  for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
		  var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"
		  for (var j = i$4; j < end; ++j) { types[j] = replace }
		  i$4 = 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$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
		var type$4 = types[i$5]
		if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L" }
		else if (isStrong.test(type$4)) { cur$1 = 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$6 = 0; i$6 < len; ++i$6) {
		if (isNeutral.test(types[i$6])) {
		  var end$1 = void 0
		  for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
		  var before = (i$6 ? types[i$6-1] : outerType) == "L"
		  var after = (end$1 < len ? types[end$1] : outerType) == "L"
		  var replace$1 = before || after ? "L" : "R"
		  for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1 }
		  i$6 = end$1 - 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$7 = 0; i$7 < len;) {
		if (countsAsLeft.test(types[i$7])) {
		  var start = i$7
		  for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
		  order.push(new BidiSpan(0, start, i$7))
		} else {
		  var pos = i$7, at = order.length
		  for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
		  for (var j$2 = pos; j$2 < i$7;) {
			if (countsAsNum.test(types[j$2])) {
			  if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)) }
			  var nstart = j$2
			  for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
			  order.splice(at, 0, new BidiSpan(2, nstart, j$2))
			  pos = j$2
			} else { ++j$2 }
		  }
		  if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)) }
		}
	  }
	  if (order[0].level == 1 && (m = str.match(/^\s+/))) {
		order[0].from = m[0].length
		order.unshift(new BidiSpan(0, 0, m[0].length))
	  }
	  if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
		lst(order).to -= m[0].length
		order.push(new BidiSpan(0, len - m[0].length, len))
	  }
	  if (order[0].level == 2)
		{ order.unshift(new BidiSpan(1, order[0].to, order[0].to)) }
	  if (order[0].level != lst(order).level)
		{ order.push(new BidiSpan(order[0].level, len, len)) }
  
	  return 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(line) {
	var order = line.order
	if (order == null) { order = line.order = bidiOrdering(line.text) }
	return order
  }
  
  // EVENT HANDLING
  
  // Lightweight event framework. on/off also work on DOM nodes,
  // registering native DOM handlers.
  
  var on = function(emitter, type, f) {
	if (emitter.addEventListener)
	  { emitter.addEventListener(type, f, false) }
	else if (emitter.attachEvent)
	  { emitter.attachEvent("on" + type, f) }
	else {
	  var map = emitter._handlers || (emitter._handlers = {})
	  var arr = map[type] || (map[type] = [])
	  arr.push(f)
	}
  }
  
  var noHandlers = []
  function getHandlers(emitter, type, copy) {
	var arr = emitter._handlers && emitter._handlers[type]
	if (copy) { return arr && arr.length > 0 ? arr.slice() : noHandlers }
	else { return arr || noHandlers }
  }
  
  function off(emitter, type, f) {
	if (emitter.removeEventListener)
	  { emitter.removeEventListener(type, f, false) }
	else if (emitter.detachEvent)
	  { emitter.detachEvent("on" + type, f) }
	else {
	  var handlers = getHandlers(emitter, type, false)
	  for (var i = 0; i < handlers.length; ++i)
		{ if (handlers[i] == f) { handlers.splice(i, 1); break } }
	}
  }
  
  function signal(emitter, type /*, values...*/) {
	var handlers = getHandlers(emitter, type, true)
	if (!handlers.length) { return }
	var args = Array.prototype.slice.call(arguments, 2)
	for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args) }
  }
  
  // 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(cm, e, override) {
	if (typeof e == "string")
	  { e = {type: e, preventDefault: function() { this.defaultPrevented = true }} }
	signal(cm, override || e.type, cm, e)
	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 i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
	  { set.push(arr[i]) } }
  }
  
  function hasHandler(emitter, type) {
	return getHandlers(emitter, type).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(type, f) {on(this, type, f)}
	ctor.prototype.off = function(type, f) {off(this, type, f)}
  }
  
  // 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 b = e.which
	if (b == null) {
	  if (e.button & 1) { b = 1 }
	  else if (e.button & 2) { b = 3 }
	  else if (e.button & 4) { b = 2 }
	}
	if (mac && e.ctrlKey && b == 1) { b = 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(measure, elt("span", [test, document.createTextNode("x")]))
	  if (measure.firstChild.offsetHeight != 0)
		{ zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(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(measure, document.createTextNode("A\u062eA"))
	var r0 = range(txt, 0, 1).getBoundingClientRect()
	var r1 = range(txt, 1, 2).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 = "\n\nb".split(/\n/).length != 3 ? function (string) {
	var pos = 0, result = [], l = string.length
	while (pos <= l) {
	  var nl = string.indexOf("\n", pos)
	  if (nl == -1) { nl = string.length }
	  var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl)
	  var rt = line.indexOf("\r")
	  if (rt != -1) {
		result.push(line.slice(0, rt))
		pos += rt + 1
	  } else {
		result.push(line)
		pos = nl + 1
	  }
	}
	return result
  } : function (string) { return string.split(/\r\n?|\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 e = 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(measure, elt("span", "x"))
	var normal = node.getBoundingClientRect()
	var fromRange = range(node, 0, 1).getBoundingClientRect()
	return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
  }
  
  var modes = {};
  var 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(name, mode) {
	if (arguments.length > 2)
	  { mode.dependencies = Array.prototype.slice.call(arguments, 2) }
	modes[name] = mode
  }
  
  function defineMIME(mime, spec) {
	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 = {name: found} }
	  spec = createObj(found, spec)
	  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 {name: spec} }
	else { return spec || {name: "null"} }
  }
  
  // Given a mode spec (anything that resolveMode accepts), find and
  // initialize an actual mode object.
  function getMode(options, spec) {
	spec = resolveMode(spec)
	var mfactory = modes[spec.name]
	if (!mfactory) { return getMode(options, "text/plain") }
	var modeObj = mfactory(options, spec)
	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(mode, properties) {
	var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {})
	copyObj(properties, exts)
  }
  
  function copyState(mode, state) {
	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(mode, state) {
	var info
	while (mode.innerMode) {
	  info = mode.innerMode(state)
	  if (!info || info.mode == mode) { break }
	  state = info.state
	  mode = info.mode
	}
	return info || {mode: mode, state: state}
  }
  
  function startState(mode, a1, a2) {
	return mode.startState ? mode.startState(a1, a2) : true
  }
  
  // STRING STREAM
  
  // Fed to the mode parsers, provides helper functions to make
  // parsers more succinct.
  
  var StringStream = function(string, tabSize) {
	this.pos = this.start = 0
	this.string = string
	this.tabSize = tabSize || 8
	this.lastColumnPos = this.lastColumnValue = 0
	this.lineStart = 0
  }
  
  StringStream.prototype = {
	eol: function() {return this.pos >= this.string.length},
	sol: function() {return this.pos == this.lineStart},
	peek: function() {return this.string.charAt(this.pos) || undefined},
	next: function() {
	  if (this.pos < this.string.length)
		{ return this.string.charAt(this.pos++) }
	},
	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}
	},
	eatWhile: function(match) {
	  var start = this.pos
	  while (this.eat(match)){}
	  return this.pos > start
	},
	eatSpace: function() {
	  var this$1 = this;
  
	  var start = this.pos
	  while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos }
	  return this.pos > start
	},
	skipToEnd: function() {this.pos = this.string.length},
	skipTo: function(ch) {
	  var found = this.string.indexOf(ch, this.pos)
	  if (found > -1) {this.pos = found; return true}
	},
	backUp: function(n) {this.pos -= n},
	column: function() {
	  if (this.lastColumnPos < this.start) {
		this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue)
		this.lastColumnPos = this.start
	  }
	  return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
	},
	indentation: function() {
	  return countColumn(this.string, null, this.tabSize) -
		(this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
	},
	match: function(pattern, consume, caseInsensitive) {
	  if (typeof pattern == "string") {
		var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }
		var substr = this.string.substr(this.pos, pattern.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
	  }
	},
	current: function(){return this.string.slice(this.start, this.pos)},
	hideFirstChars: function(n, inner) {
	  this.lineStart += n
	  try { return inner() }
	  finally { this.lineStart -= n }
	}
  }
  
  // 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(cm, line, state, forceToEnd) {
	// 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(cm, line.text, cm.doc.mode, state, function (end, style) { return st.push(end, style); },
	  lineClasses, forceToEnd)
  
	// Run overlays, adjust style array.
	var loop = function ( o ) {
	  var overlay = cm.state.overlays[o], i = 1, at = 0
	  runMode(cm, line.text, overlay.mode, true, function (end, style) {
		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(i, 1, end, st[i+1], i_end) }
		  i += 2
		  at = Math.min(end, i_end)
		}
		if (!style) { return }
		if (overlay.opaque) {
		  st.splice(start, i - start, end, "overlay " + style)
		  i = start + 2
		} else {
		  for (; start < i; start += 2) {
			var cur = st[start+1]
			st[start+1] = (cur ? cur + " " : "") + "overlay " + style
		  }
		}
	  }, lineClasses)
	};
  
	for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
  
	return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
  }
  
  function getLineStyles(cm, line, updateFrontier) {
	if (!line.styles || line.styles[0] != cm.state.modeGen) {
	  var state = getStateBefore(cm, lineNo(line))
	  var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state)
	  line.stateAfter = state
	  line.styles = result.styles
	  if (result.classes) { line.styleClasses = result.classes }
	  else if (line.styleClasses) { line.styleClasses = null }
	  if (updateFrontier === cm.doc.frontier) { cm.doc.frontier++ }
	}
	return line.styles
  }
  
  function getStateBefore(cm, n, precise) {
	var doc = cm.doc, display = cm.display
	if (!doc.mode.startState) { return true }
	var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter
	if (!state) { state = startState(doc.mode) }
	else { state = copyState(doc.mode, state) }
	doc.iter(pos, n, function (line) {
	  processLine(cm, line.text, state)
	  var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo
	  line.stateAfter = save ? copyState(doc.mode, state) : null
	  ++pos
	})
	if (precise) { doc.frontier = pos }
	return state
  }
  
  // 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(cm, text, state, startAt) {
	var mode = cm.doc.mode
	var stream = new StringStream(text, cm.options.tabSize)
	stream.start = stream.pos = startAt || 0
	if (text == "") { callBlankLine(mode, state) }
	while (!stream.eol()) {
	  readToken(mode, stream, state)
	  stream.start = stream.pos
	}
  }
  
  function callBlankLine(mode, state) {
	if (mode.blankLine) { return mode.blankLine(state) }
	if (!mode.innerMode) { return }
	var inner = innerMode(mode, state)
	if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
  }
  
  function readToken(mode, stream, state, inner) {
	for (var i = 0; i < 10; i++) {
	  if (inner) { inner[0] = innerMode(mode, state).mode }
	  var style = mode.token(stream, state)
	  if (stream.pos > stream.start) { return style }
	}
	throw new Error("Mode " + mode.name + " failed to advance stream.")
  }
  
  // Utility for getTokenAt and getLineTokens
  function takeToken(cm, pos, precise, asArray) {
	var getObj = function (copy) { return ({
	  start: stream.start, end: stream.pos,
	  string: stream.current(),
	  type: style || null,
	  state: copy ? copyState(doc.mode, state) : state
	}); }
  
	var doc = cm.doc, mode = doc.mode, style
	pos = clipPos(doc, pos)
	var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise)
	var stream = new StringStream(line.text, cm.options.tabSize), tokens
	if (asArray) { tokens = [] }
	while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
	  stream.start = stream.pos
	  style = readToken(mode, stream, state)
	  if (asArray) { tokens.push(getObj(true)) }
	}
	return asArray ? tokens : getObj()
  }
  
  function extractLineClasses(type, output) {
	if (type) { for (;;) {
	  var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/)
	  if (!lineClass) { break }
	  type = type.slice(0, lineClass.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(cm, text, mode, state, f, lineClasses, forceToEnd) {
	var flattenSpans = mode.flattenSpans
	if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans }
	var curStart = 0, curStyle = null
	var stream = new StringStream(text, cm.options.tabSize), style
	var inner = cm.options.addModeClass && [null]
	if (text == "") { extractLineClasses(callBlankLine(mode, state), lineClasses) }
	while (!stream.eol()) {
	  if (stream.pos > cm.options.maxHighlightLength) {
		flattenSpans = false
		if (forceToEnd) { processLine(cm, text, state, stream.pos) }
		stream.pos = text.length
		style = null
	  } else {
		style = extractLineClasses(readToken(mode, stream, state, inner), 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.start, curStart + 5000)
		  f(curStart, curStyle)
		}
		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.pos, curStart + 5000)
	  f(pos, curStyle)
	  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(cm, n, precise) {
	var minindent, minline, doc = cm.doc
	var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100)
	for (var search = n; search > lim; --search) {
	  if (search <= doc.first) { return doc.first }
	  var line = getLine(doc, search - 1)
	  if (line.stateAfter && (!precise || search <= doc.frontier)) { return search }
	  var indented = countColumn(line.text, null, cm.options.tabSize)
	  if (minline == null || minindent > indented) {
		minline = search - 1
		minindent = indented
	  }
	}
	return minline
  }
  
  // LINE DATA STRUCTURE
  
  // Line objects. These hold state related to a line, including
  // highlighting info (the styles array).
  function Line(text, markedSpans, estimateHeight) {
	this.text = text
	attachMarkedSpans(this, markedSpans)
	this.height = estimateHeight ? estimateHeight(this) : 1
  }
  eventMixin(Line)
  Line.prototype.lineNo = function() { return lineNo(this) }
  
  // Change the content (text, markers) of a line. Automatically
  // invalidates cached information and tries to re-estimate the
  // line's height.
  function updateLine(line, text, markedSpans, estimateHeight) {
	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(line, markedSpans)
	var estHeight = estimateHeight ? estimateHeight(line) : 1
	if (estHeight != line.height) { updateLineHeight(line, estHeight) }
  }
  
  // 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 = {};
  var styleToClassCacheWithMode = {};
  function interpretTokenStyle(style, options) {
	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(cm, lineView) {
	// 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 = elt("span", null, null, webkit ? "padding-right: .1px" : null)
	var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
				   col: 0, pos: 0, cm: cm,
				   trailingSpace: false,
				   splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}
	lineView.measure = {}
  
	// Iterate over the logical lines that make up this visual line.
	for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
	  var line = i ? lineView.rest[i - 1] : lineView.line, order = 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(line)))
		{ builder.addToken = buildTokenBadBidi(builder.addToken, order) }
	  builder.map = []
	  var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line)
	  insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate))
	  if (line.styleClasses) {
		if (line.styleClasses.bgClass)
		  { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "") }
		if (line.styleClasses.textClass)
		  { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "") }
	  }
  
	  // Ensure at least a single node is present, for measuring.
	  if (builder.map.length == 0)
		{ builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))) }
  
	  // Store the map and a cache object for the current logical line
	  if (i == 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-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
		{ builder.content.className = "cm-tab-wrap-hack" }
	}
  
	signal(cm, "renderLine", cm, lineView.line, builder.pre)
	if (builder.pre.className)
	  { builder.textClass = joinClasses(builder.pre.className, builder.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(builder, text, style, startStyle, endStyle, title, css) {
	if (!text) { return }
	var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text
	var special = builder.cm.state.specialChars, mustWrap = false
	var content
	if (!special.test(text)) {
	  builder.col += text.length
	  content = document.createTextNode(displayText)
	  builder.map.push(builder.pos, builder.pos + text.length, content)
	  if (ie && ie_version < 9) { mustWrap = true }
	  builder.pos += text.length
	} else {
	  content = document.createDocumentFragment()
	  var pos = 0
	  while (true) {
		special.lastIndex = pos
		var m = special.exec(text)
		var skipped = m ? m.index - pos : text.length - pos
		if (skipped) {
		  var txt = document.createTextNode(displayText.slice(pos, pos + skipped))
		  if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])) }
		  else { content.appendChild(txt) }
		  builder.map.push(builder.pos, builder.pos + skipped, txt)
		  builder.col += skipped
		  builder.pos += skipped
		}
		if (!m) { break }
		pos += skipped + 1
		var txt$1 = void 0
		if (m[0] == "\t") {
		  var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize
		  txt$1 = 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$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"))
		  txt$1.setAttribute("cm-text", m[0])
		  builder.col += 1
		} else {
		  txt$1 = 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.pos, builder.pos + 1, txt$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], fullStyle, css)
	  if (title) { token.title = title }
	  return builder.content.appendChild(token)
	}
	builder.content.appendChild(content)
  }
  
  function splitSpaces(text, trailingBefore) {
	if (text.length > 1 && !/  /.test(text)) { return text }
	var spaceBefore = trailingBefore, result = ""
	for (var i = 0; i < text.length; i++) {
	  var ch = text.charAt(i)
	  if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 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(inner, order) {
	return function (builder, text, style, startStyle, endStyle, title, css) {
	  style = style ? style + " cm-force-border" : "cm-force-border"
	  var start = builder.pos, end = start + text.length
	  for (;;) {
		// Find the part that overlaps with the start of this text
		var part = void 0
		for (var i = 0; i < order.length; i++) {
		  part = order[i]
		  if (part.to > start && part.from <= start) { break }
		}
		if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
		inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css)
		startStyle = null
		text = text.slice(part.to - start)
		start = part.to
	  }
	}
  }
  
  function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
	var widget = !ignoreWidget && marker.widgetNode
	if (widget) { builder.map.push(builder.pos, builder.pos + size, widget) }
	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(line, builder, styles) {
	var spans = line.markedSpans, allText = line.text, at = 0
	if (!spans) {
	  for (var i$1 = 1; i$1 < styles.length; i$1+=2)
		{ builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)) }
	  return
	}
  
	var len = allText.length, pos = 0, i = 1, text = "", style, css
	var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed
	for (;;) {
	  if (nextChange == pos) { // Update current marker set
		spanStyle = spanEndStyle = spanStartStyle = title = css = ""
		collapsed = null; nextChange = Infinity
		var foundBookmarks = [], endStyles = void 0
		for (var j = 0; j < spans.length; ++j) {
		  var sp = spans[j], m = 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.endStyle, sp.to) }
			if (m.title && !title) { title = m.title }
			if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
			  { collapsed = sp }
		  } else if (sp.from > pos && nextChange > sp.from) {
			nextChange = sp.from
		  }
		}
		if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
		  { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1] } } }
  
		if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
		  { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]) } }
		if (collapsed && (collapsed.from || 0) == pos) {
		  buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
							 collapsed.marker, collapsed.from == null)
		  if (collapsed.to == null) { return }
		  if (collapsed.to == pos) { collapsed = false }
		}
	  }
	  if (pos >= len) { break }
  
	  var upto = Math.min(len, nextChange)
	  while (true) {
		if (text) {
		  var end = pos + text.length
		  if (!collapsed) {
			var tokenText = end > upto ? text.slice(0, upto - pos) : text
			builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
							 spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css)
		  }
		  if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
		  pos = end
		  spanStartStyle = ""
		}
		text = allText.slice(at, at = 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(doc, line, lineN) {
	// 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 : 1
	this.node = this.text = null
	this.hidden = lineIsHidden(doc, line)
  }
  
  // Create a range of LineView objects for the given lines.
  function buildViewArray(cm, from, to) {
	var array = [], nextPos
	for (var pos = from; pos < to; pos = nextPos) {
	  var view = new LineView(cm.doc, getLine(cm.doc, pos), 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.delayedCallbacks, i = 0
	do {
	  for (; i < callbacks.length; i++)
		{ callbacks[i].call(null) }
	  for (var j = 0; j < group.ops.length; j++) {
		var op = group.ops[j]
		if (op.cursorActivityHandlers)
		  { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
			{ op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } }
	  }
	} while (i < callbacks.length)
  }
  
  function finishOperation(op, endCb) {
	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(emitter, type /*, values...*/) {
	var arr = getHandlers(emitter, type, false)
	if (!arr.length) { return }
	var args = Array.prototype.slice.call(arguments, 2), list
	if (operationGroup) {
	  list = operationGroup.delayedCallbacks
	} else if (orphanDelayedCallbacks) {
	  list = orphanDelayedCallbacks
	} else {
	  list = orphanDelayedCallbacks = []
	  setTimeout(fireOrphanDelayed, 0)
	}
	var loop = function ( i ) {
	  list.push(function () { return arr[i].apply(null, args); })
	};
  
	for (var i = 0; i < arr.length; ++i)
	  loop( i );
  }
  
  function fireOrphanDelayed() {
	var delayed = orphanDelayedCallbacks
	orphanDelayedCallbacks = null
	for (var i = 0; i < delayed.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(cm, lineView, lineN, dims) {
	for (var j = 0; j < lineView.changes.length; j++) {
	  var type = lineView.changes[j]
	  if (type == "text") { updateLineText(cm, lineView) }
	  else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims) }
	  else if (type == "class") { updateLineClasses(lineView) }
	  else if (type == "widget") { updateLineWidgets(cm, lineView, dims) }
	}
	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", null, null, "position: relative")
	  if (lineView.text.parentNode)
		{ lineView.text.parentNode.replaceChild(lineView.node, lineView.text) }
	  lineView.node.appendChild(lineView.text)
	  if (ie && ie_version < 8) { lineView.node.style.zIndex = 2 }
	}
	return lineView.node
  }
  
  function updateLineBackground(lineView) {
	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", null, cls), wrap.firstChild)
	}
  }
  
  // Wrapper around buildLineContent which will reuse the structure
  // in display.externalMeasured when possible.
  function getLineContent(cm, lineView) {
	var ext = cm.display.externalMeasured
	if (ext && ext.line == lineView.line) {
	  cm.display.externalMeasured = null
	  lineView.measure = ext.measure
	  return ext.built
	}
	return buildLineContent(cm, lineView)
  }
  
  // Redraw the line's text. Interacts with the background and text
  // classes because the mode may output tokens that influence these
  // classes.
  function updateLineText(cm, lineView) {
	var cls = lineView.text.className
	var built = getLineContent(cm, lineView)
	if (lineView.text == lineView.node) { lineView.node = built.pre }
	lineView.text.parentNode.replaceChild(built.pre, lineView.text)
	lineView.text = built.pre
	if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
	  lineView.bgClass = built.bgClass
	  lineView.textClass = built.textClass
	  updateLineClasses(lineView)
	} else if (cls) {
	  lineView.text.className = cls
	}
  }
  
  function updateLineClasses(lineView) {
	updateLineBackground(lineView)
	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(cm, lineView, lineN, dims) {
	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"))
	  wrap.insertBefore(lineView.gutterBackground, lineView.text)
	}
	var markers = lineView.line.gutterMarkers
	if (cm.options.lineNumbers || markers) {
	  var wrap$1 = 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(gutterWrap, lineView.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.options, lineN),
			  "CodeMirror-linenumber CodeMirror-gutter-elt",
			  ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))) }
	  if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
		var id = cm.options.gutters[k], found = 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(cm, lineView, dims) {
	if (lineView.alignable) { lineView.alignable = null }
	for (var node = lineView.node.firstChild, next = void 0; node; node = next) {
	  next = node.nextSibling
	  if (node.className == "CodeMirror-linewidget")
		{ lineView.node.removeChild(node) }
	}
	insertLineWidgets(cm, lineView, dims)
  }
  
  // Build a line's DOM representation from scratch
  function buildLineElement(cm, lineView, lineN, dims) {
	var built = getLineContent(cm, lineView)
	lineView.text = lineView.node = built.pre
	if (built.bgClass) { lineView.bgClass = built.bgClass }
	if (built.textClass) { lineView.textClass = built.textClass }
  
	updateLineClasses(lineView)
	updateLineGutter(cm, lineView, lineN, dims)
	insertLineWidgets(cm, lineView, dims)
	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(cm, lineView, dims) {
	insertLineWidgetsFor(cm, lineView.line, lineView, dims, true)
	if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
	  { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } }
  }
  
  function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
	if (!line.widgets) { return }
	var wrap = ensureLineWrapped(lineView)
	for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
	  var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget")
	  if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true") }
	  positionLineWidget(widget, node, lineView, dims)
	  cm.display.input.setUneditable(node)
	  if (allowAbove && widget.above)
		{ wrap.insertBefore(node, lineView.gutter || lineView.text) }
	  else
		{ wrap.appendChild(node) }
	  signalLater(widget, "redraw")
	}
  }
  
  function positionLineWidget(widget, node, lineView, dims) {
	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 0 }
	if (!contains(document.body, widget.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.measure, elt("div", [widget.node], null, parentStyle))
	}
	return widget.height = widget.node.parentNode.offsetHeight
  }
  
  // Return true when the given mouse event happened in a widget
  function eventInWidget(display, e) {
	for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
	  if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
		  (n.parentNode == display.sizer && n != 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 e = removeChildrenAndAdd(display.measure, elt("pre", "x"))
	var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle
	var data = {left: parseInt(style.paddingLeft), right: parseInt(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(cm, lineView, rect) {
	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 i = 0; i < rects.length - 1; i++) {
		  var cur = rects[i], next = rects[i + 1]
		  if (Math.abs(cur.bottom - next.bottom) > 2)
			{ heights.push((cur.bottom + next.top) / 2 - 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(lineView, line, lineN) {
	if (lineView.line == line)
	  { return {map: lineView.measure.map, cache: lineView.measure.cache} }
	for (var i = 0; i < lineView.rest.length; i++)
	  { if (lineView.rest[i] == line)
		{ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
	for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
	  { if (lineNo(lineView.rest[i$1]) > lineN)
		{ return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
  }
  
  // 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(cm, line) {
	line = visualLine(line)
	var lineN = lineNo(line)
	var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN)
	view.lineN = lineN
	var built = view.built = buildLineContent(cm, view)
	view.text = built.pre
	removeChildrenAndAdd(cm.display.lineMeasure, built.pre)
	return view
  }
  
  // Get a {top, bottom, left, right} box (in line-local coordinates)
  // for a given character.
  function measureChar(cm, line, ch, bias) {
	return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
  }
  
  // Find a line view that corresponds to the given line number.
  function findViewForLine(cm, lineN) {
	if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
	  { return cm.display.view[findViewIndex(cm, lineN)] }
	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(cm, line) {
	var lineN = lineNo(line)
	var view = findViewForLine(cm, lineN)
	if (view && !view.text) {
	  view = null
	} else if (view && view.changes) {
	  updateLineForChanges(cm, view, lineN, getDimensions(cm))
	  cm.curOp.forceUpdate = true
	}
	if (!view)
	  { view = updateExternalMeasurement(cm, line) }
  
	var info = mapFromLineView(view, line, lineN)
	return {
	  line: line, view: view, rect: null,
	  map: info.map, cache: info.cache, before: info.before,
	  hasHeights: false
	}
  }
  
  // Given a prepared measurement object, measures the position of an
  // actual character (or fetches it from the cache).
  function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
	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(cm, prepared.view, prepared.rect)
		prepared.hasHeights = true
	  }
	  found = measureCharInner(cm, prepared, ch, bias)
	  if (!found.bogus) { prepared.cache[key] = found }
	}
	return {left: found.left, right: found.right,
			top: varHeight ? found.rtop : found.top,
			bottom: varHeight ? found.rbottom : found.bottom}
  }
  
  var nullRect = {left: 0, right: 0, top: 0, bottom: 0}
  
  function nodeAndOffsetInLineMap(map, ch, bias) {
	var node, start, end, collapse, mStart, mEnd
	// First, search the line map for the text node corresponding to,
	// or closest to, the target character.
	for (var i = 0; i < map.length; i += 3) {
	  mStart = map[i]
	  mEnd = map[i + 1]
	  if (ch < mStart) {
		start = 0; end = 1
		collapse = "left"
	  } else if (ch < mEnd) {
		start = ch - mStart
		end = start + 1
	  } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
		end = mEnd - mStart
		start = end - 1
		if (ch >= mEnd) { collapse = "right" }
	  }
	  if (start != null) {
		node = map[i + 2]
		if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
		  { collapse = bias }
		if (bias == "left" && start == 0)
		  { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
			node = map[(i -= 3) + 2]
			collapse = "left"
		  } }
		if (bias == "right" && start == mEnd - mStart)
		  { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
			node = map[(i += 3) + 2]
			collapse = "right"
		  } }
		break
	  }
	}
	return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
  }
  
  function getUsefulRect(rects, bias) {
	var rect = nullRect
	if (bias == "left") { for (var i = 0; i < rects.length; i++) {
	  if ((rect = rects[i]).left != rect.right) { break }
	} } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
	  if ((rect = rects[i$1]).left != rect.right) { break }
	} }
	return rect
  }
  
  function measureCharInner(cm, prepared, ch, bias) {
	var place = nodeAndOffsetInLineMap(prepared.map, ch, bias)
	var node = place.node, start = place.start, end = place.end, collapse = place.collapse
  
	var rect
	if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
	  for (var i$1 = 0; i$1 < 4; i$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 < 9 && start == 0 && end == place.coverEnd - place.coverStart)
		  { rect = node.parentNode.getBoundingClientRect() }
		else
		  { rect = getUsefulRect(range(node, start, end).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.measure, rect) }
	} 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 - 1 : 0] }
	  else
		{ rect = node.getBoundingClientRect() }
	}
	if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
	  var rSpan = node.parentNode.getClientRects()[0]
	  if (rSpan)
		{ rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} }
	  else
		{ rect = nullRect }
	}
  
	var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top
	var mid = (rtop + rbot) / 2
	var heights = prepared.view.measure.heights
	var i = 0
	for (; i < heights.length - 1; i++)
	  { if (mid < heights[i]) { break } }
	var top = i ? heights[i - 1] : 0, bot = heights[i]
	var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
				  right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
				  top: top, bottom: bot}
	if (!rect.left && !rect.right) { result.bogus = true }
	if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot }
  
	return result
  }
  
  // Work around problem with bounding client rects on ranges being
  // returned incorrectly when zoomed on IE10 and below.
  function maybeUpdateRectForZooming(measure, rect) {
	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 {left: rect.left * scaleX, right: rect.right * scaleX,
			top: rect.top * scaleY, bottom: rect.bottom * scaleY}
  }
  
  function clearLineMeasurementCacheFor(lineView) {
	if (lineView.measure) {
	  lineView.measure.cache = {}
	  lineView.measure.heights = null
	  if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
		{ lineView.measure.caches[i] = {} } }
	}
  }
  
  function clearLineMeasurementCache(cm) {
	cm.display.externalMeasure = null
	removeChildren(cm.display.lineMeasure)
	for (var i = 0; i < cm.display.view.length; i++)
	  { 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() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft }
  function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop }
  
  // 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(cm, lineObj, rect, context) {
	if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {
	  var size = widgetHeight(lineObj.widgets[i])
	  rect.top += size; rect.bottom += size
	} } }
	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" ? 0 : pageScrollY())
	  var xOff = lOff.left + (context == "window" ? 0 : pageScrollX())
	  rect.left += xOff; rect.right += xOff
	}
	rect.top += yOff; rect.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(cm, coords, context) {
	if (context == "div") { return coords }
	var left = coords.left, top = 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 {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
  }
  
  function charCoords(cm, pos, context, lineObj, bias) {
	if (!lineObj) { lineObj = getLine(cm.doc, pos.line) }
	return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), 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.
  function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
	lineObj = lineObj || getLine(cm.doc, pos.line)
	if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
	function get(ch, right) {
	  var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight)
	  if (right) { m.left = m.right; } else { m.right = m.left }
	  return intoCoordSystem(cm, lineObj, m, context)
	}
	function getBidi(ch, partPos) {
	  var part = order[partPos], right = part.level % 2
	  if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
		part = order[--partPos]
		ch = bidiRight(part) - (part.level % 2 ? 0 : 1)
		right = true
	  } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
		part = order[++partPos]
		ch = bidiLeft(part) - part.level % 2
		right = false
	  }
	  if (right && ch == part.to && ch > part.from) { return get(ch - 1) }
	  return get(ch, right)
	}
	var order = getOrder(lineObj), ch = pos.ch
	if (!order) { return get(ch) }
	var partPos = getBidiPartAt(order, ch)
	var val = getBidi(ch, partPos)
	if (bidiOther != null) { val.other = getBidi(ch, bidiOther) }
	return val
  }
  
  // Used to cheaply estimate the coordinates for a position. Used for
  // intermediate scroll updates.
  function estimateCoords(cm, pos) {
	var left = 0
	pos = clipPos(cm.doc, pos)
	if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch }
	var lineObj = getLine(cm.doc, pos.line)
	var top = heightAtLine(lineObj) + paddingTop(cm.display)
	return {left: left, right: left, top: top, bottom: top + 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(line, ch, outside, xRel) {
	var pos = Pos(line, ch)
	pos.xRel = xRel
	if (outside) { pos.outside = true }
	return pos
  }
  
  // Compute the character position closest to the given coordinates.
  // Input must be lineSpace-local ("div" coordinate system).
  function coordsChar(cm, x, y) {
	var doc = cm.doc
	y += cm.display.viewOffset
	if (y < 0) { return PosWithInfo(doc.first, 0, true, -1) }
	var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1
	if (lineN > last)
	  { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1) }
	if (x < 0) { x = 0 }
  
	var lineObj = getLine(doc, lineN)
	for (;;) {
	  var found = coordsCharInner(cm, lineObj, lineN, x, y)
	  var merged = collapsedSpanAtEnd(lineObj)
	  var mergedPos = merged && merged.find(0, true)
	  if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
		{ lineN = lineNo(lineObj = mergedPos.to.line) }
	  else
		{ return found }
	}
  }
  
  function coordsCharInner(cm, lineObj, lineNo, x, y) {
	var innerOff = y - heightAtLine(lineObj)
	var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth
	var preparedMeasure = prepareMeasureForLine(cm, lineObj)
  
	function getX(ch) {
	  var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure)
	  wrongLine = true
	  if (innerOff > sp.bottom) { return sp.left - adjust }
	  else if (innerOff < sp.top) { return sp.left + adjust }
	  else { wrongLine = false }
	  return sp.left
	}
  
	var bidi = getOrder(lineObj), dist = lineObj.text.length
	var from = lineLeft(lineObj), to = lineRight(lineObj)
	var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine
  
	if (x > toX) { return PosWithInfo(lineNo, to, toOutside, 1) }
	// Do a binary search between these bounds.
	for (;;) {
	  if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
		var ch = x < fromX || x - fromX <= toX - x ? from : to
		var outside = ch == from ? fromOutside : toOutside
		var xDiff = x - (ch == from ? fromX : toX)
		// This is a kludge to handle the case where the coordinates
		// are after a line-wrapped line. We should replace it with a
		// more general handling of cursor positions around line
		// breaks. (Issue #4078)
		if (toOutside && !bidi && !/\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 &&
			ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) {
		  var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right")
		  if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) {
			outside = false
			ch++
			xDiff = x - charSize.right
		  }
		}
		while (isExtendingChar(lineObj.text.charAt(ch))) { ++ch }
		var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0)
		return pos
	  }
	  var step = Math.ceil(dist / 2), middle = from + step
	  if (bidi) {
		middle = from
		for (var i = 0; i < step; ++i) { middle = moveVisually(lineObj, middle, 1) }
	  }
	  var middleX = getX(middle)
	  if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) { toX += 1000; } dist = step}
	  else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step}
	}
  }
  
  var measureText
  // Compute the default text height.
  function textHeight(display) {
	if (display.cachedTextHeight != null) { return display.cachedTextHeight }
	if (measureText == null) {
	  measureText = elt("pre")
	  // Measure a bunch of lines, for browsers that compute
	  // fractional heights.
	  for (var i = 0; i < 49; ++i) {
		measureText.appendChild(document.createTextNode("x"))
		measureText.appendChild(elt("br"))
	  }
	  measureText.appendChild(document.createTextNode("x"))
	}
	removeChildrenAndAdd(display.measure, measureText)
	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])
	removeChildrenAndAdd(display.measure, pre)
	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 d = cm.display, left = {}, width = {}
	var gutterLeft = d.gutters.clientLeft
	for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
	  left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft
	  width[cm.options.gutters[i]] = n.clientWidth
	}
	return {fixedPos: compensateForHScroll(d),
			gutterTotalWidth: d.gutters.offsetWidth,
			gutterLeft: left,
			gutterWidth: width,
			wrapperWidth: d.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(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3)
	return function (line) {
	  if (lineIsHidden(cm.doc, line)) { return 0 }
  
	  var widgetsHeight = 0
	  if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
		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.doc, est = estimateHeight(cm)
	doc.iter(function (line) {
	  var estHeight = est(line)
	  if (estHeight != line.height) { updateLineHeight(line, estHeight) }
	})
  }
  
  // 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(cm, e, liberal, forRect) {
	var display = cm.display
	if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
  
	var x, y, space = display.lineSpace.getBoundingClientRect()
	// Fails unpredictably on IE[67] when mouse is dragged around quickly.
	try { x = e.clientX - space.left; y = e.clientY - space.top }
	catch (e) { return null }
	var coords = coordsChar(cm, x, y), line
	if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
	  var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length
	  coords = Pos(coords.line, Math.max(0, Math.round((x - 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(cm, n) {
	if (n >= cm.display.viewTo) { return null }
	n -= cm.display.viewFrom
	if (n < 0) { return null }
	var view = cm.display.view
	for (var i = 0; i < view.length; i++) {
	  n -= view[i].size
	  if (n < 0) { return i }
	}
  }
  
  function updateSelection(cm) {
	cm.display.input.showSelection(cm.display.input.prepareSelection())
  }
  
  function prepareSelection(cm, primary) {
	var doc = cm.doc, result = {}
	var curFragment = result.cursors = document.createDocumentFragment()
	var selFragment = result.selection = document.createDocumentFragment()
  
	for (var i = 0; i < doc.sel.ranges.length; i++) {
	  if (primary === false && i == 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(cm, range.head, curFragment) }
	  if (!collapsed)
		{ drawSelectionRange(cm, range, selFragment) }
	}
	return result
  }
  
  // Draws a cursor for the given range
  function drawSelectionCursor(cm, head, output) {
	var pos = cursorCoords(cm, head, "div", null, null, !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(0, pos.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"
	}
  }
  
  // Draws the given range as a highlighted selection
  function drawSelectionRange(cm, range, output) {
	var display = cm.display, doc = cm.doc
	var fragment = document.createDocumentFragment()
	var padding = paddingH(cm.display), leftSide = padding.left
	var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right
  
	function add(left, top, width, bottom) {
	  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(line, fromArg, toArg) {
	  var lineObj = getLine(doc, line)
	  var lineLen = lineObj.text.length
	  var start, end
	  function coords(ch, bias) {
		return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
	  }
  
	  iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
		var leftPos = coords(from, "left"), rightPos, left, right
		if (from == to) {
		  rightPos = leftPos
		  left = right = leftPos.left
		} else {
		  rightPos = coords(to - 1, "right")
		  if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp }
		  left = leftPos.left
		  right = rightPos.right
		}
		if (fromArg == null && from == 0) { left = leftSide }
		if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
		  add(left, leftPos.top, null, leftPos.bottom)
		  left = leftSide
		  if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top) }
		}
		if (toArg == null && to == lineLen) { right = rightSide }
		if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
		  { start = leftPos }
		if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
		  { end = rightPos }
		if (left < leftSide + 1) { left = leftSide }
		add(left, rightPos.top, right - left, rightPos.bottom)
	  })
	  return {start: start, end: end}
	}
  
	var sFrom = range.from(), sTo = range.to()
	if (sFrom.line == sTo.line) {
	  drawForLine(sFrom.line, sFrom.ch, sTo.ch)
	} else {
	  var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line)
	  var singleVLine = visualLine(fromLine) == visualLine(toLine)
	  var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end
	  var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start
	  if (singleVLine) {
		if (leftEnd.top < rightStart.top - 2) {
		  add(leftEnd.right, leftEnd.top, null, leftEnd.bottom)
		  add(leftSide, rightStart.top, rightStart.left, rightStart.bottom)
		} else {
		  add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom)
		}
	  }
	  if (leftEnd.bottom < rightStart.top)
		{ add(leftSide, leftEnd.bottom, null, rightStart.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(cm, e) {
	if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false }
  
	if (cm.options.readOnly == "nocursor") { return }
	if (!cm.state.focused) {
	  signal(cm, "focus", cm, e)
	  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(cm, e) {
	if (cm.state.delayingBlurEvent) { return }
  
	if (cm.state.focused) {
	  signal(cm, "blur", cm, e)
	  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)
  }
  
  // Re-align line numbers and gutter marks to compensate for
  // horizontal scrolling.
  function alignHorizontally(cm) {
	var display = cm.display, view = 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.offsetWidth, left = comp + "px"
	for (var i = 0; i < view.length; i++) { 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 j = 0; j < align.length; j++)
		{ 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.doc, last = lineNumberFor(cm.options, doc.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.offsetWidth, padding = test.offsetWidth - innerW
	  display.lineGutter.style.width = ""
	  display.lineNumInnerWidth = Math.max(innerW, display.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)
	  return true
	}
	return false
  }
  
  // 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 i = 0; i < display.view.length; i++) {
	  var cur = display.view[i], height = void 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
	  }
	  var diff = cur.line.height - height
	  if (height < 2) { height = textHeight(display) }
	  if (diff > .001 || diff < -.001) {
		updateLineHeight(cur.line, height)
		updateWidgetHeight(cur.line)
		if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
		  { updateWidgetHeight(cur.rest[j]) } }
	  }
	}
  }
  
  // Read and store the height of line widgets associated with the
  // given line.
  function updateWidgetHeight(line) {
	if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i)
	  { line.widgets[i].height = line.widgets[i].node.parentNode.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(display, doc, viewport) {
	var top = viewport && viewport.top != null ? Math.max(0, viewport.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(doc, top), to = lineAtHeight(doc, bottom)
	// 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.line, ensureTo = viewport.ensure.to.line
	  if (ensureFrom < from) {
		from = ensureFrom
		to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)
	  } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
		from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight)
		to = ensureTo
	  }
	}
	return {from: from, to: Math.max(to, from + 1)}
  }
  
  // Sync the scrollable area and scrollbars, ensure the viewport
  // covers the visible area.
  function setScrollTop(cm, val) {
	if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
	cm.doc.scrollTop = val
	if (!gecko) { updateDisplaySimple(cm, {top: val}) }
	if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val }
	cm.display.scrollbars.setScrollTop(val)
	if (gecko) { updateDisplaySimple(cm) }
	startWorker(cm, 100)
  }
  // Sync scroller and scrollbar, ensure the gutter elements are
  // aligned.
  function setScrollLeft(cm, val, isScroller) {
	if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) { return }
	val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth)
	cm.doc.scrollLeft = val
	alignHorizontally(cm)
	if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val }
	cm.display.scrollbars.setScrollLeft(val)
  }
  
  // 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 = 0;
  var wheelPixelsPerUnit = 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.wheelDeltaX, dy = 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 {x: dx, y: dy}
  }
  function wheelEventPixels(e) {
	var delta = wheelEventDelta(e)
	delta.x *= wheelPixelsPerUnit
	delta.y *= wheelPixelsPerUnit
	return delta
  }
  
  function onScrollWheel(cm, e) {
	var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y
  
	var display = cm.display, scroll = 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.target, view = display.view; cur != scroll; cur = cur.parentNode) {
		for (var i = 0; i < view.length; i++) {
		  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)
		{ setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))) }
	  setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)))
	  // 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.scrollTop, bot = top + display.wrapper.clientHeight
	  if (pixels < 0) { top = Math.max(0, top + pixels - 50) }
	  else { bot = Math.min(cm.doc.height, bot + pixels + 50) }
	  updateDisplaySimple(cm, {top: top, bottom: bot})
	}
  
	if (wheelSamples < 20) {
	  if (display.wheelStartX == null) {
		display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop
		display.wheelDX = dx; display.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 += dx; display.wheelDY += dy
	  }
	}
  }
  
  // SCROLLBARS
  
  // Prepare DOM reads needed to update the scrollbars. Done in one
  // shot to minimize update/measure roundtrips.
  function measureForScrollbars(cm) {
	var d = cm.display, gutterW = d.gutters.offsetWidth
	var docH = Math.round(cm.doc.height + paddingVert(cm.display))
	return {
	  clientHeight: d.scroller.clientHeight,
	  viewHeight: d.wrapper.clientHeight,
	  scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
	  viewWidth: d.wrapper.clientWidth,
	  barLeft: cm.options.fixedGutter ? gutterW : 0,
	  docHeight: docH,
	  scrollHeight: docH + scrollGap(cm) + d.barHeight,
	  nativeBarWidth: d.nativeBarWidth,
	  gutterWidth: gutterW
	}
  }
  
  function NativeScrollbars(place, scroll, cm) {
	this.cm = cm
	var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
	var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
	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 = copyObj({
	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(0, measure.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 =
		  (measure.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 {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
	},
	setScrollLeft: function(pos) {
	  if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos }
	  if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz) }
	},
	setScrollTop: function(pos) {
	  if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos }
	  if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert) }
	},
	zeroWidthHack: function() {
	  var w = 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
	},
	enableZeroWidthBar: function(bar, delay) {
	  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
		// left 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 = document.elementFromPoint(box.left + 1, box.bottom - 1)
		if (elt != bar) { bar.style.pointerEvents = "none" }
		else { delay.set(1000, maybeDisable) }
	  }
	  delay.set(1000, maybeDisable)
	},
	clear: function() {
	  var parent = this.horiz.parentNode
	  parent.removeChild(this.horiz)
	  parent.removeChild(this.vert)
	}
  }, NativeScrollbars.prototype)
  
  function NullScrollbars() {}
  
  NullScrollbars.prototype = copyObj({
	update: function() { return {bottom: 0, right: 0} },
	setScrollLeft: function() {},
	setScrollTop: function() {},
	clear: function() {}
  }, NullScrollbars.prototype)
  
  function updateScrollbars(cm, measure) {
	if (!measure) { measure = measureForScrollbars(cm) }
	var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight
	updateScrollbarsInner(cm, measure)
	for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
	  if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
		{ updateHeightsInViewport(cm) }
	  updateScrollbarsInner(cm, measureForScrollbars(cm))
	  startWidth = cm.display.barWidth; startHeight = cm.display.barHeight
	}
  }
  
  // Re-synchronize the fake scrollbars with the actual size of the
  // content.
  function updateScrollbarsInner(cm, measure) {
	var d = 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.wrapper, cm.display.scrollbars.addClass) }
	}
  
	cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
	  cm.display.wrapper.insertBefore(node, cm.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 (pos, axis) {
	  if (axis == "horizontal") { setScrollLeft(cm, pos) }
	  else { setScrollTop(cm, pos) }
	}, cm)
	if (cm.display.scrollbars.addClass)
	  { addClass(cm.display.wrapper, cm.display.scrollbars.addClass) }
  }
  
  // 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(cm, coords) {
	if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
  
	var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null
	if (coords.top + box.top < 0) { doScroll = true }
	else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false }
	if (doScroll != null && !phantom) {
	  var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n                         top: " + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px;\n                         height: " + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px;\n                         left: " + (coords.left) + "px; width: 2px;"))
	  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(cm, pos, end, margin) {
	if (margin == null) { margin = 0 }
	var coords
	for (var limit = 0; limit < 5; limit++) {
	  var changed = false
	  coords = cursorCoords(cm, pos)
	  var endCoords = !end || end == pos ? coords : cursorCoords(cm, end)
	  var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
										 Math.min(coords.top, endCoords.top) - margin,
										 Math.max(coords.left, endCoords.left),
										 Math.max(coords.bottom, endCoords.bottom) + margin)
	  var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft
	  if (scrollPos.scrollTop != null) {
		setScrollTop(cm, scrollPos.scrollTop)
		if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true }
	  }
	  if (scrollPos.scrollLeft != null) {
		setScrollLeft(cm, scrollPos.scrollLeft)
		if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true }
	  }
	  if (!changed) { break }
	}
	return coords
  }
  
  // Scroll a given set of coordinates into view (immediately).
  function scrollIntoView(cm, x1, y1, x2, y2) {
	var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2)
	if (scrollPos.scrollTop != null) { setScrollTop(cm, scrollPos.scrollTop) }
	if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.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(cm, x1, y1, x2, y2) {
	var display = cm.display, snapMargin = textHeight(cm.display)
	if (y1 < 0) { y1 = 0 }
	var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop
	var screen = displayHeight(cm), result = {}
	if (y2 - y1 > screen) { y2 = y1 + screen }
	var docBottom = cm.doc.height + paddingVert(display)
	var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin
	if (y1 < screentop) {
	  result.scrollTop = atTop ? 0 : y1
	} else if (y2 > screentop + screen) {
	  var newTop = Math.min(y1, (atBottom ? docBottom : y2) - 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 = x2 - x1 > screenw
	if (tooWide) { x2 = x1 + screenw }
	if (x1 < 10)
	  { result.scrollLeft = 0 }
	else if (x1 < screenleft)
	  { result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)) }
	else if (x2 > screenw + screenleft - 3)
	  { result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw }
	return result
  }
  
  // Store a relative adjustment to the scroll position in the current
  // operation (to be applied when the operation finishes).
  function addToScrollPos(cm, left, top) {
	if (left != null || top != null) { resolveScrollToPos(cm) }
	if (left != null)
	  { cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left }
	if (top != null)
	  { 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(), from = cur, to = cur
	if (!cm.options.lineWrapping) {
	  from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur
	  to = Pos(cur.line, cur.ch + 1)
	}
	cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}
  }
  
  // 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(cm, range.from), to = estimateCoords(cm, range.to)
	  var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
									Math.min(from.top, to.top) - range.margin,
									Math.max(from.right, to.right),
									Math.max(from.bottom, to.bottom) + range.margin)
	  cm.scrollTo(sPos.scrollLeft, sPos.scrollTop)
	}
  }
  
  // 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 = {
	  cm: cm,
	  viewChanged: false,      // Flag that indicates that lines might need to be redrawn
	  startHeight: cm.doc.height, // Used to detect need to update scrollbar
	  forceUpdate: false,      // Used to force a redraw
	  updateInput: null,       // Whether to reset the input textarea
	  typing: false,           // Whether this reset should be careful to leave existing text (for compositing)
	  changeObjs: null,        // Accumulated changes, for firing change events
	  cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
	  cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
	  selectionChanged: false, // Whether the selection needs to be redrawn
	  updateMaxLine: false,    // Set when the widest line needs to be determined anew
	  scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
	  scrollToPos: null,       // Used to scroll to a specific position
	  focus: false,
	  id: ++nextOpId           // Unique ID
	}
	pushOperation(cm.curOp)
  }
  
  // Finish an operation, updating the display and signalling delayed events
  function endOperation(cm) {
	var op = cm.curOp
	finishOperation(op, function (group) {
	  for (var i = 0; i < group.ops.length; i++)
		{ 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 i = 0; i < ops.length; i++) // Read DOM
	  { endOperation_R1(ops[i]) }
	for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
	  { endOperation_W1(ops[i$1]) }
	for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
	  { endOperation_R2(ops[i$2]) }
	for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
	  { endOperation_W2(ops[i$3]) }
	for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
	  { endOperation_finish(ops[i$4]) }
  }
  
  function endOperation_R1(op) {
	var cm = op.cm, display = 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(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate)
  }
  
  function endOperation_W1(op) {
	op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update)
  }
  
  function endOperation_R2(op) {
	var cm = op.cm, display = 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(cm, display.maxLine, display.maxLine.text.length).left + 3
	  cm.display.sizerWidth = op.adjustWidthTo
	  op.barMeasure.scrollWidth =
		Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth)
	  op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm))
	}
  
	if (op.updatedDisplay || op.selectionChanged)
	  { op.preparedSelection = display.input.prepareSelection(op.focus) }
  }
  
  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(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) }
	  cm.display.maxLineChanged = false
	}
  
	var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())
	if (op.preparedSelection)
	  { cm.display.input.showSelection(op.preparedSelection, takeFocus) }
	if (op.updatedDisplay || op.startHeight != cm.doc.height)
	  { updateScrollbars(cm, op.barMeasure) }
	if (op.updatedDisplay)
	  { setDocumentHeight(cm, op.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.cm, display = cm.display, doc = cm.doc
  
	if (op.updatedDisplay) { postUpdateDisplay(cm, op.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 && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
	  doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop))
	  display.scrollbars.setScrollTop(doc.scrollTop)
	  display.scroller.scrollTop = doc.scrollTop
	}
	if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
	  doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft))
	  display.scrollbars.setScrollLeft(doc.scrollLeft)
	  display.scroller.scrollLeft = doc.scrollLeft
	  alignHorizontally(cm)
	}
	// If we need to scroll a specific position into view, do so.
	if (op.scrollToPos) {
	  var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
									 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin)
	  if (op.scrollToPos.isCursor && cm.state.focused) { maybeScrollWindow(cm, coords) }
	}
  
	// Fire events for markers that are hidden/unidden by editing or
	// undoing
	var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers
	if (hidden) { for (var i = 0; i < hidden.length; ++i)
	  { if (!hidden[i].lines.length) { signal(hidden[i], "hide") } } }
	if (unhidden) { for (var i$1 = 0; i$1 < 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", cm, op.changeObjs) }
	if (op.update)
	  { op.update.finish() }
  }
  
  // Run the given function in an operation
  function runInOp(cm, f) {
	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(cm, f) {
	return function() {
	  if (cm.curOp) { return f.apply(cm, arguments) }
	  startOperation(cm)
	  try { return f.apply(cm, arguments) }
	  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(this, arguments) }
	  startOperation(this)
	  try { return f.apply(this, arguments) }
	  finally { endOperation(this) }
	}
  }
  function docMethodOp(f) {
	return function() {
	  var cm = this.cm
	  if (!cm || cm.curOp) { return f.apply(this, arguments) }
	  startOperation(cm)
	  try { return f.apply(this, arguments) }
	  finally { endOperation(cm) }
	}
  }
  
  // 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(cm, from, to, lendiff) {
	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.doc, from) < display.viewTo)
		{ resetView(cm) }
	} else if (to <= display.viewFrom) { // Change before
	  if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + 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(cm, to, to + lendiff, 1)
	  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$1 = viewCuttingPoint(cm, from, from, -1)
	  if (cut$1) {
		display.view = display.view.slice(0, cut$1.index)
		display.viewTo = cut$1.lineN
	  } else {
		resetView(cm)
	  }
	} else { // Gap in the middle
	  var cutTop = viewCuttingPoint(cm, from, from, -1)
	  var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1)
	  if (cutTop && cutBot) {
		display.view = display.view.slice(0, cutTop.index)
		  .concat(buildViewArray(cm, cutTop.lineN, cutBot.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(cm, line, type) {
	cm.curOp.viewChanged = true
	var display = cm.display, ext = 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(cm, line)]
	if (lineView.node == null) { return }
	var arr = lineView.changes || (lineView.changes = [])
	if (indexOf(arr, type) == -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(cm, oldN, newN, dir) {
	var index = findViewIndex(cm, oldN), diff, view = cm.display.view
	if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
	  { return {index: index, lineN: newN} }
	var n = cm.display.viewFrom
	for (var i = 0; i < index; i++)
	  { n += view[i].size }
	if (n != oldN) {
	  if (dir > 0) {
		if (index == view.length - 1) { return null }
		diff = (n + view[index].size) - oldN
		index++
	  } else {
		diff = n - oldN
	  }
	  oldN += diff; newN += diff
	}
	while (visualLineNo(cm.doc, newN) != newN) {
	  if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
	  newN += dir * view[index - (dir < 0 ? 1 : 0)].size
	  index += dir
	}
	return {index: index, lineN: newN}
  }
  
  // Force the view to cover a given range, adding empty view element
  // or clipping off existing ones as needed.
  function adjustView(cm, from, to) {
	var display = cm.display, view = display.view
	if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
	  display.view = buildViewArray(cm, from, to)
	  display.viewFrom = from
	} else {
	  if (display.viewFrom > from)
		{ display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view) }
	  else if (display.viewFrom < from)
		{ display.view = display.view.slice(findViewIndex(cm, from)) }
	  display.viewFrom = from
	  if (display.viewTo < to)
		{ display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)) }
	  else if (display.viewTo > to)
		{ display.view = display.view.slice(0, findViewIndex(cm, to)) }
	}
	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.view, dirty = 0
	for (var i = 0; i < view.length; i++) {
	  var lineView = view[i]
	  if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty }
	}
	return dirty
  }
  
  // HIGHLIGHT WORKER
  
  function startWorker(cm, time) {
	if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
	  { cm.state.highlight.set(time, bind(highlightWorker, cm)) }
  }
  
  function highlightWorker(cm) {
	var doc = cm.doc
	if (doc.frontier < doc.first) { doc.frontier = doc.first }
	if (doc.frontier >= cm.display.viewTo) { return }
	var end = +new Date + cm.options.workTime
	var state = copyState(doc.mode, getStateBefore(cm, doc.frontier))
	var changedLines = []
  
	doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
	  if (doc.frontier >= cm.display.viewFrom) { // Visible
		var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength
		var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true)
		line.styles = highlighted.styles
		var oldCls = line.styleClasses, newCls = 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 i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i] }
		if (ischange) { changedLines.push(doc.frontier) }
		line.stateAfter = tooLong ? state : copyState(doc.mode, state)
	  } else {
		if (line.text.length <= cm.options.maxHighlightLength)
		  { processLine(cm, line.text, state) }
		line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null
	  }
	  ++doc.frontier
	  if (+new Date > end) {
		startWorker(cm, cm.options.workDelay)
		return true
	  }
	})
	if (changedLines.length) { runInOp(cm, function () {
	  for (var i = 0; i < changedLines.length; i++)
		{ regLineChange(cm, changedLines[i], "text") }
	}) }
  }
  
  // DISPLAY DRAWING
  
  function DisplayUpdate(cm, viewport, force) {
	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(display, cm.doc, viewport)
	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(emitter, type) {
	if (hasHandler(emitter, type))
	  { this.events.push(arguments) }
  }
  DisplayUpdate.prototype.finish = function() {
	var this$1 = this;
  
	for (var i = 0; i < this.events.length; i++)
	  { signal.apply(null, this$1.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
	}
  }
  
  // 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(cm, update) {
	var display = cm.display, doc = 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.viewportMargin, doc.first)
	var to = Math.min(end, update.visible.to + cm.options.viewportMargin)
	if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom) }
	if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo) }
	if (sawCollapsedSpans) {
	  from = visualLineNo(cm.doc, from)
	  to = visualLineEndNo(cm.doc, to)
	}
  
	var different = from != display.viewFrom || to != display.viewTo ||
	  display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth
	adjustView(cm, from, to)
  
	display.viewOffset = heightAtLine(getLine(cm.doc, display.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 == 0 && !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 focused = activeElt()
	if (toUpdate > 4) { display.lineDiv.style.display = "none" }
	patchDisplay(cm, display.updateLineNumbers, update.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.
	if (focused && activeElt() != focused && focused.offsetHeight) { focused.focus() }
  
	// 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(cm, 400)
	}
  
	display.updateLineNumbers = null
  
	return true
  }
  
  function postUpdateDisplay(cm, update) {
	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 = {top: Math.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.display, cm.doc, viewport)
		if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
		  { break }
	  }
	  if (!updateDisplayIfNeeded(cm, update)) { break }
	  updateHeightsInViewport(cm)
	  var barMeasure = measureForScrollbars(cm)
	  updateSelection(cm)
	  updateScrollbars(cm, barMeasure)
	  setDocumentHeight(cm, barMeasure)
	}
  
	update.signal(cm, "update", cm)
	if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
	  update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo)
	  cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo
	}
  }
  
  function updateDisplaySimple(cm, viewport) {
	var update = new DisplayUpdate(cm, viewport)
	if (updateDisplayIfNeeded(cm, update)) {
	  updateHeightsInViewport(cm)
	  postUpdateDisplay(cm, update)
	  var barMeasure = measureForScrollbars(cm)
	  updateSelection(cm)
	  updateScrollbars(cm, barMeasure)
	  setDocumentHeight(cm, barMeasure)
	  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(cm, updateNumbersFrom, dims) {
	var display = cm.display, lineNumbers = cm.options.lineNumbers
	var container = display.lineDiv, cur = 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.view, lineN = 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 i = 0; i < view.length; i++) {
	  var lineView = view[i]
	  if (lineView.hidden) {
	  } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
		var node = buildLineElement(cm, lineView, lineN, dims)
		container.insertBefore(node, cur)
	  } 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(cm, lineView, lineN, dims)
		}
		if (updateNumber) {
		  removeChildren(lineView.lineNumber)
		  lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)))
		}
		cur = lineView.node.nextSibling
	  }
	  lineN += lineView.size
	}
	while (cur) { cur = rm(cur) }
  }
  
  function updateGutterSpace(cm) {
	var width = cm.display.gutters.offsetWidth
	cm.display.sizer.style.marginLeft = width + "px"
  }
  
  function setDocumentHeight(cm, measure) {
	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"
  }
  
  // Rebuild the gutter elements, ensure the margin to the left of the
  // code matches their width.
  function updateGutters(cm) {
	var gutters = cm.display.gutters, specs = cm.options.gutters
	removeChildren(gutters)
	var i = 0
	for (; i < specs.length; ++i) {
	  var gutterClass = specs[i]
	  var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass))
	  if (gutterClass == "CodeMirror-linenumbers") {
		cm.display.lineGutter = gElt
		gElt.style.width = (cm.display.lineNumWidth || 1) + "px"
	  }
	}
	gutters.style.display = i ? "" : "none"
	updateGutterSpace(cm)
  }
  
  // Make sure the gutters options contains the element
  // "CodeMirror-linenumbers" when the lineNumbers option is true.
  function setGuttersForLineNumbers(options) {
	var found = indexOf(options.gutters, "CodeMirror-linenumbers")
	if (found == -1 && options.lineNumbers) {
	  options.gutters = options.gutters.concat(["CodeMirror-linenumbers"])
	} else if (found > -1 && !options.lineNumbers) {
	  options.gutters = options.gutters.slice(0)
	  options.gutters.splice(found, 1)
	}
  }
  
  // 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).
  function Selection(ranges, primIndex) {
	this.ranges = ranges
	this.primIndex = primIndex
  }
  
  Selection.prototype = {
	primary: function() { return this.ranges[this.primIndex] },
	equals: function(other) {
	  var this$1 = this;
  
	  if (other == this) { return true }
	  if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
	  for (var i = 0; i < this.ranges.length; i++) {
		var here = this$1.ranges[i], there = other.ranges[i]
		if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) { return false }
	  }
	  return true
	},
	deepCopy: function() {
	  var this$1 = this;
  
	  var out = []
	  for (var i = 0; i < this.ranges.length; i++)
		{ out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)) }
	  return new Selection(out, this.primIndex)
	},
	somethingSelected: function() {
	  var this$1 = this;
  
	  for (var i = 0; i < this.ranges.length; i++)
		{ if (!this$1.ranges[i].empty()) { return true } }
	  return false
	},
	contains: function(pos, end) {
	  var this$1 = this;
  
	  if (!end) { end = pos }
	  for (var i = 0; i < this.ranges.length; i++) {
		var range = this$1.ranges[i]
		if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
		  { return i }
	  }
	  return -1
	}
  }
  
  function Range(anchor, head) {
	this.anchor = anchor; this.head = head
  }
  
  Range.prototype = {
	from: function() { return minPos(this.anchor, this.head) },
	to: function() { return maxPos(this.anchor, this.head) },
	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(ranges, primIndex) {
	var prim = ranges[primIndex]
	ranges.sort(function (a, b) { return cmp(a.from(), b.from()); })
	primIndex = indexOf(ranges, prim)
	for (var i = 1; i < ranges.length; i++) {
	  var cur = ranges[i], prev = ranges[i - 1]
	  if (cmp(prev.to(), cur.from()) >= 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 (i <= primIndex) { --primIndex }
		ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to))
	  }
	}
	return new Selection(ranges, primIndex)
  }
  
  function simpleSelection(anchor, head) {
	return new Selection([new Range(anchor, head || 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 == 1 ? 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(pos, change) {
	if (cmp(pos, change.from) < 0) { return pos }
	if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
  
	var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch
	if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch }
	return Pos(line, ch)
  }
  
  function computeSelAfterChange(doc, change) {
	var out = []
	for (var i = 0; i < doc.sel.ranges.length; i++) {
	  var range = doc.sel.ranges[i]
	  out.push(new Range(adjustForChange(range.anchor, change),
						 adjustForChange(range.head, change)))
	}
	return normalizeSelection(out, doc.sel.primIndex)
  }
  
  function offsetPos(pos, old, nw) {
	if (pos.line == old.line)
	  { return Pos(nw.line, pos.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(doc, changes, hint) {
	var out = []
	var oldPrev = Pos(doc.first, 0), newPrev = oldPrev
	for (var i = 0; i < changes.length; i++) {
	  var change = changes[i]
	  var from = offsetPos(change.from, oldPrev, newPrev)
	  var to = offsetPos(changeEnd(change), oldPrev, newPrev)
	  oldPrev = change.to
	  newPrev = to
	  if (hint == "around") {
		var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0
		out[i] = new Range(inv ? to : from, inv ? from : to)
	  } else {
		out[i] = new Range(from, from)
	  }
	}
	return new Selection(out, doc.sel.primIndex)
  }
  
  // Used to get the editor into a consistent state again when options change.
  
  function loadMode(cm) {
	cm.doc.mode = getMode(cm.options, cm.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.frontier = cm.doc.first
	startWorker(cm, 100)
	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(doc, change) {
	return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
	  (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
  }
  
  // Perform a change on the document data structure.
  function updateDoc(doc, change, markedSpans, estimateHeight) {
	function spansFor(n) {return markedSpans ? markedSpans[n] : null}
	function update(line, text, spans) {
	  updateLine(line, text, spans, estimateHeight)
	  signalLater(line, "change", line, change)
	}
	function linesFor(start, end) {
	  var result = []
	  for (var i = start; i < end; ++i)
		{ result.push(new Line(text[i], spansFor(i), estimateHeight)) }
	  return result
	}
  
	var from = change.from, to = change.to, text = change.text
	var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line)
	var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line
  
	// Adjust the line structure
	if (change.full) {
	  doc.insert(0, linesFor(0, text.length))
	  doc.remove(text.length, doc.size - text.length)
	} else if (isWholeLineUpdate(doc, change)) {
	  // This is a whole-line replace. Treated specially to make
	  // sure line objects move the way they are supposed to.
	  var added = linesFor(0, text.length - 1)
	  update(lastLine, lastLine.text, lastSpans)
	  if (nlines) { doc.remove(from.line, nlines) }
	  if (added.length) { doc.insert(from.line, added) }
	} else if (firstLine == lastLine) {
	  if (text.length == 1) {
		update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans)
	  } else {
		var added$1 = linesFor(1, text.length - 1)
		added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight))
		update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0))
		doc.insert(from.line + 1, added$1)
	  }
	} else if (text.length == 1) {
	  update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0))
	  doc.remove(from.line + 1, nlines)
	} else {
	  update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0))
	  update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans)
	  var added$2 = linesFor(1, text.length - 1)
	  if (nlines > 1) { doc.remove(from.line + 1, nlines - 1) }
	  doc.insert(from.line + 1, added$2)
	}
  
	signalLater(doc, "change", doc, change)
  }
  
  // Call f for all linked documents.
  function linkedDocs(doc, f, sharedHistOnly) {
	function propagate(doc, skip, sharedHist) {
	  if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
		var rel = doc.linked[i]
		if (rel.doc == skip) { continue }
		var shared = sharedHist && rel.sharedHist
		if (sharedHistOnly && !shared) { continue }
	
Download .txt
gitextract_1jlpki56/

├── .eslintrc
├── .gitignore
├── README-CN.md
├── README.md
├── asset/
│   ├── codemirror.css
│   ├── codemirror.js
│   ├── show-hint.js
│   ├── sql-hint.js
│   └── sql-qone.js
├── index.html
├── package.json
├── qone.js
└── test/
    ├── clone.html
    ├── index.html
    ├── index.ie.html
    ├── lib/
    │   ├── qunit.css
    │   └── qunit.js
    ├── test.ie.js
    └── test.js
Download .txt
SYMBOL INDEX (542 symbols across 6 files)

FILE: asset/codemirror.js
  function classTest (line 48) | function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)...
  function removeChildren (line 59) | function removeChildren(e) {
  function removeChildrenAndAdd (line 65) | function removeChildrenAndAdd(parent, e) {
  function elt (line 69) | function elt(tag, content, className, style) {
  function contains (line 95) | function contains(parent, child) {
  function addClass (line 119) | function addClass(node, cls) {
  function joinClasses (line 123) | function joinClasses(a, b) {
  function bind (line 136) | function bind(f) {
  function copyObj (line 141) | function copyObj(obj, target, overwrite) {
  function countColumn (line 151) | function countColumn(string, end, tabSize, startIndex, startValue) {
  function Delayed (line 166) | function Delayed() {this.id = null}
  function indexOf (line 172) | function indexOf(array, elt) {
  function findColumn (line 191) | function findColumn(string, goal, tabSize) {
  function spaceStr (line 206) | function spaceStr(n) {
  function lst (line 212) | function lst(arr) { return arr[arr.length-1] }
  function map (line 214) | function map(array, f) {
  function insertSorted (line 220) | function insertSorted(array, value, score) {
  function nothing (line 226) | function nothing() {}
  function createObj (line 228) | function createObj(base, props) {
  function isWordCharBasic (line 241) | function isWordCharBasic(ch) {
  function isWordChar (line 245) | function isWordChar(ch, helper) {
  function isEmpty (line 251) | function isEmpty(obj) {
  function isExtendingChar (line 262) | function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendi...
  function Display (line 268) | function Display(place, doc, input) {
  function getLine (line 367) | function getLine(doc, n) {
  function getBetween (line 383) | function getBetween(doc, start, end) {
  function getLines (line 395) | function getLines(doc, from, to) {
  function updateLineHeight (line 403) | function updateLineHeight(line, height) {
  function lineNo (line 410) | function lineNo(line) {
  function lineAtHeight (line 424) | function lineAtHeight(chunk, h) {
  function isLine (line 444) | function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
  function lineNumberFor (line 446) | function lineNumberFor(options, i) {
  function Pos (line 451) | function Pos (line, ch) {
  function cmp (line 458) | function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
  function copyPos (line 460) | function copyPos(x) {return Pos(x.line, x.ch)}
  function maxPos (line 461) | function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
  function minPos (line 462) | function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
  function clipLine (line 466) | function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.fi...
  function clipPos (line 467) | function clipPos(doc, pos) {
  function clipToLen (line 473) | function clipToLen(pos, linelen) {
  function clipPosArray (line 479) | function clipPosArray(doc, array) {
  function seeReadOnlySpans (line 488) | function seeReadOnlySpans() {
  function seeCollapsedSpans (line 492) | function seeCollapsedSpans() {
  function MarkedSpan (line 498) | function MarkedSpan(marker, from, to) {
  function getMarkedSpanFor (line 504) | function getMarkedSpanFor(spans, marker) {
  function removeMarkedSpan (line 512) | function removeMarkedSpan(spans, span) {
  function addMarkedSpan (line 519) | function addMarkedSpan(line, span) {
  function markedSpansBefore (line 528) | function markedSpansBefore(old, startCh, isInsert) {
  function markedSpansAfter (line 540) | function markedSpansAfter(old, endCh, isInsert) {
  function stretchSpansOverChange (line 560) | function stretchSpansOverChange(doc, change) {
  function clearEmptySpans (line 622) | function clearEmptySpans(spans) {
  function removeReadOnlyRanges (line 633) | function removeReadOnlyRanges(doc, from, to) {
  function detachMarkedSpans (line 662) | function detachMarkedSpans(line) {
  function attachMarkedSpans (line 669) | function attachMarkedSpans(line, spans) {
  function extraLeft (line 678) | function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
  function extraRight (line 679) | function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
  function compareCollapsedMarkers (line 684) | function compareCollapsedMarkers(a, b) {
  function collapsedSpanAtSide (line 697) | function collapsedSpanAtSide(line, start) {
  function collapsedSpanAtStart (line 707) | function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, t...
  function collapsedSpanAtEnd (line 708) | function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, fal...
  function conflictingCollapsedRange (line 713) | function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
  function visualLine (line 733) | function visualLine(line) {
  function visualLineContinued (line 742) | function visualLineContinued(line) {
  function visualLineNo (line 753) | function visualLineNo(doc, lineN) {
  function visualLineEndNo (line 761) | function visualLineEndNo(doc, lineN) {
  function lineIsHidden (line 773) | function lineIsHidden(doc, line) {
  function lineIsHiddenInner (line 784) | function lineIsHiddenInner(doc, line, span) {
  function heightAtLine (line 801) | function heightAtLine(lineObj) {
  function lineLength (line 823) | function lineLength(line) {
  function findMaxLine (line 842) | function findMaxLine(cm) {
  function iterateBidiSections (line 858) | function iterateBidiSections(order, from, to, f) {
  function bidiLeft (line 871) | function bidiLeft(part) { return part.level % 2 ? part.to : part.from }
  function bidiRight (line 872) | function bidiRight(part) { return part.level % 2 ? part.from : part.to }
  function lineLeft (line 874) | function lineLeft(line) { var order = getOrder(line); return order ? bid...
  function lineRight (line 875) | function lineRight(line) {
  function compareBidiLevel (line 881) | function compareBidiLevel(order, a, b) {
  function getBidiPartAt (line 889) | function getBidiPartAt(order, pos) {
  function moveInLine (line 910) | function moveInLine(line, pos, dir, byUnit) {
  function moveVisually (line 922) | function moveVisually(line, start, dir, byUnit) {
  function moveLogically (line 945) | function moveLogically(line, start, dir, byUnit) {
  function charType (line 979) | function charType(code) {
  function BidiSpan (line 994) | function BidiSpan(level, from, to) {
  function getOrder (line 1126) | function getOrder(line) {
  function getHandlers (line 1150) | function getHandlers(emitter, type, copy) {
  function off (line 1156) | function off(emitter, type, f) {
  function signal (line 1168) | function signal(emitter, type /*, values...*/) {
  function signalDOMEvent (line 1178) | function signalDOMEvent(cm, e, override) {
  function signalCursorActivity (line 1185) | function signalCursorActivity(cm) {
  function hasHandler (line 1193) | function hasHandler(emitter, type) {
  function eventMixin (line 1199) | function eventMixin(ctor) {
  function e_preventDefault (line 1207) | function e_preventDefault(e) {
  function e_stopPropagation (line 1211) | function e_stopPropagation(e) {
  function e_defaultPrevented (line 1215) | function e_defaultPrevented(e) {
  function e_stop (line 1218) | function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)}
  function e_target (line 1220) | function e_target(e) {return e.target || e.srcElement}
  function e_button (line 1221) | function e_button(e) {
  function zeroWidthElement (line 1242) | function zeroWidthElement(measure) {
  function hasBadBidiRects (line 1257) | function hasBadBidiRects(measure) {
  function hasBadZoomedRects (line 1306) | function hasBadZoomedRects(measure) {
  function defineMode (line 1319) | function defineMode(name, mode) {
  function defineMIME (line 1325) | function defineMIME(mime, spec) {
  function resolveMode (line 1331) | function resolveMode(spec) {
  function getMode (line 1350) | function getMode(options, spec) {
  function extendMode (line 1374) | function extendMode(mode, properties) {
  function copyState (line 1379) | function copyState(mode, state) {
  function innerMode (line 1393) | function innerMode(mode, state) {
  function startState (line 1404) | function startState(mode, a1, a2) {
  function highlightLine (line 1492) | function highlightLine(cm, line, state, forceToEnd) {
  function getLineStyles (line 1531) | function getLineStyles(cm, line, updateFrontier) {
  function getStateBefore (line 1544) | function getStateBefore(cm, n, precise) {
  function processLine (line 1563) | function processLine(cm, text, state, startAt) {
  function callBlankLine (line 1574) | function callBlankLine(mode, state) {
  function readToken (line 1581) | function readToken(mode, stream, state, inner) {
  function takeToken (line 1591) | function takeToken(cm, pos, precise, asArray) {
  function extractLineClasses (line 1612) | function extractLineClasses(type, output) {
  function runMode (line 1627) | function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
  function findStartLine (line 1671) | function findStartLine(cm, n, precise) {
  function Line (line 1691) | function Line(text, markedSpans, estimateHeight) {
  function updateLine (line 1702) | function updateLine(line, text, markedSpans, estimateHeight) {
  function cleanUpLine (line 1714) | function cleanUpLine(line) {
  function interpretTokenStyle (line 1724) | function interpretTokenStyle(style, options) {
  function buildLineContent (line 1736) | function buildLineContent(cm, lineView) {
  function defaultSpecialCharPlaceholder (line 1794) | function defaultSpecialCharPlaceholder(ch) {
  function buildToken (line 1803) | function buildToken(builder, text, style, startStyle, endStyle, title, c...
  function splitSpaces (line 1865) | function splitSpaces(text, trailingBefore) {
  function buildTokenBadBidi (line 1880) | function buildTokenBadBidi(inner, order) {
  function buildCollapsedSpan (line 1900) | function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
  function insertLineContent (line 1918) | function insertLineContent(line, builder, styles) {
  function LineView (line 1990) | function LineView(doc, line, lineN) {
  function buildViewArray (line 2002) | function buildViewArray(cm, from, to) {
  function pushOperation (line 2014) | function pushOperation(op) {
  function fireCallbacksForOps (line 2025) | function fireCallbacksForOps(group) {
  function finishOperation (line 2041) | function finishOperation(op, endCb) {
  function signalLater (line 2061) | function signalLater(emitter, type /*, values...*/) {
  function fireOrphanDelayed (line 2081) | function fireOrphanDelayed() {
  function updateLineForChanges (line 2090) | function updateLineForChanges(cm, lineView, lineN, dims) {
  function ensureLineWrapped (line 2103) | function ensureLineWrapped(lineView) {
  function updateLineBackground (line 2114) | function updateLineBackground(lineView) {
  function getLineContent (line 2128) | function getLineContent(cm, lineView) {
  function updateLineText (line 2141) | function updateLineText(cm, lineView) {
  function updateLineClasses (line 2156) | function updateLineClasses(lineView) {
  function updateLineGutter (line 2166) | function updateLineGutter(cm, lineView, lineN, dims) {
  function updateLineWidgets (line 2203) | function updateLineWidgets(cm, lineView, dims) {
  function buildLineElement (line 2214) | function buildLineElement(cm, lineView, lineN, dims) {
  function insertLineWidgets (line 2228) | function insertLineWidgets(cm, lineView, dims) {
  function insertLineWidgetsFor (line 2234) | function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
  function positionLineWidget (line 2250) | function positionLineWidget(widget, node, lineView, dims) {
  function widgetHeight (line 2268) | function widgetHeight(widget) {
  function eventInWidget (line 2284) | function eventInWidget(display, e) {
  function paddingTop (line 2294) | function paddingTop(display) {return display.lineSpace.offsetTop}
  function paddingVert (line 2295) | function paddingVert(display) {return display.mover.offsetHeight - displ...
  function paddingH (line 2296) | function paddingH(display) {
  function scrollGap (line 2305) | function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
  function displayWidth (line 2306) | function displayWidth(cm) {
  function displayHeight (line 2309) | function displayHeight(cm) {
  function ensureLineHeights (line 2317) | function ensureLineHeights(cm, lineView, rect) {
  function mapFromLineView (line 2338) | function mapFromLineView(lineView, line, lineN) {
  function updateExternalMeasurement (line 2351) | function updateExternalMeasurement(cm, line) {
  function measureChar (line 2364) | function measureChar(cm, line, ch, bias) {
  function findViewForLine (line 2369) | function findViewForLine(cm, lineN) {
  function prepareMeasureForLine (line 2382) | function prepareMeasureForLine(cm, line) {
  function measureCharPrepared (line 2404) | function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
  function nodeAndOffsetInLineMap (line 2426) | function nodeAndOffsetInLineMap(map, ch, bias) {
  function getUsefulRect (line 2464) | function getUsefulRect(rects, bias) {
  function measureCharInner (line 2474) | function measureCharInner(cm, prepared, ch, bias) {
  function maybeUpdateRectForZooming (line 2527) | function maybeUpdateRectForZooming(measure, rect) {
  function clearLineMeasurementCacheFor (line 2537) | function clearLineMeasurementCacheFor(lineView) {
  function clearLineMeasurementCache (line 2546) | function clearLineMeasurementCache(cm) {
  function clearCaches (line 2553) | function clearCaches(cm) {
  function pageScrollX (line 2560) | function pageScrollX() { return window.pageXOffset || (document.document...
  function pageScrollY (line 2561) | function pageScrollY() { return window.pageYOffset || (document.document...
  function intoCoordSystem (line 2567) | function intoCoordSystem(cm, lineObj, rect, context) {
  function fromCoordSystem (line 2589) | function fromCoordSystem(cm, coords, context) {
  function charCoords (line 2606) | function charCoords(cm, pos, context, lineObj, bias) {
  function cursorCoords (line 2614) | function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHei...
  function estimateCoords (line 2646) | function estimateCoords(cm, pos) {
  function PosWithInfo (line 2661) | function PosWithInfo(line, ch, outside, xRel) {
  function coordsChar (line 2670) | function coordsChar(cm, x, y) {
  function coordsCharInner (line 2691) | function coordsCharInner(cm, lineObj, lineNo, x, y) {
  function textHeight (line 2746) | function textHeight(display) {
  function charWidth (line 2766) | function charWidth(display) {
  function getDimensions (line 2778) | function getDimensions(cm) {
  function compensateForHScroll (line 2795) | function compensateForHScroll(display) {
  function estimateHeight (line 2802) | function estimateHeight(cm) {
  function estimateLineHeights (line 2820) | function estimateLineHeights(cm) {
  function posFromMouse (line 2833) | function posFromMouse(cm, e, liberal, forRect) {
  function findViewIndex (line 2851) | function findViewIndex(cm, n) {
  function updateSelection (line 2862) | function updateSelection(cm) {
  function prepareSelection (line 2866) | function prepareSelection(cm, primary) {
  function drawSelectionCursor (line 2885) | function drawSelectionCursor(cm, head, output) {
  function drawSelectionRange (line 2904) | function drawSelectionRange(cm, range, output) {
  function restartBlink (line 2977) | function restartBlink(cm) {
  function ensureFocus (line 2990) | function ensureFocus(cm) {
  function delayBlurEvent (line 2994) | function delayBlurEvent(cm) {
  function onFocus (line 3002) | function onFocus(cm, e) {
  function onBlur (line 3021) | function onBlur(cm, e) {
  function alignHorizontally (line 3035) | function alignHorizontally(cm) {
  function maybeUpdateLineNumberWidth (line 3058) | function maybeUpdateLineNumberWidth(cm) {
  function updateHeightsInViewport (line 3078) | function updateHeightsInViewport(cm) {
  function updateWidgetHeight (line 3105) | function updateWidgetHeight(line) {
  function visibleLines (line 3113) | function visibleLines(display, doc, viewport) {
  function setScrollTop (line 3136) | function setScrollTop(cm, val) {
  function setScrollLeft (line 3147) | function setScrollLeft(cm, val, isScroller) {
  function wheelEventDelta (line 3178) | function wheelEventDelta(e) {
  function wheelEventPixels (line 3185) | function wheelEventPixels(e) {
  function onScrollWheel (line 3192) | function onScrollWheel(cm, e) {
  function measureForScrollbars (line 3271) | function measureForScrollbars(cm) {
  function NativeScrollbars (line 3287) | function NativeScrollbars(place, scroll, cm) {
  function maybeDisable (line 3359) | function maybeDisable() {
  function NullScrollbars (line 3380) | function NullScrollbars() {}
  function updateScrollbars (line 3389) | function updateScrollbars(cm, measure) {
  function updateScrollbarsInner (line 3403) | function updateScrollbarsInner(cm, measure) {
  function initScrollbars (line 3425) | function initScrollbars(cm) {
  function maybeScrollWindow (line 3451) | function maybeScrollWindow(cm, coords) {
  function scrollPosIntoView (line 3468) | function scrollPosIntoView(cm, pos, end, margin) {
  function scrollIntoView (line 3494) | function scrollIntoView(cm, x1, y1, x2, y2) {
  function calculateScrollPos (line 3504) | function calculateScrollPos(cm, x1, y1, x2, y2) {
  function addToScrollPos (line 3534) | function addToScrollPos(cm, left, top) {
  function ensureCursorVisible (line 3544) | function ensureCursorVisible(cm) {
  function resolveScrollToPos (line 3558) | function resolveScrollToPos(cm) {
  function startOperation (line 3579) | function startOperation(cm) {
  function endOperation (line 3601) | function endOperation(cm) {
  function endOperations (line 3612) | function endOperations(group) {
  function endOperation_R1 (line 3626) | function endOperation_R1(op) {
  function endOperation_W1 (line 3639) | function endOperation_W1(op) {
  function endOperation_R2 (line 3643) | function endOperation_R2(op) {
  function endOperation_W2 (line 3664) | function endOperation_W2(op) {
  function endOperation_finish (line 3689) | function endOperation_finish(op) {
  function runInOp (line 3736) | function runInOp(cm, f) {
  function operation (line 3743) | function operation(cm, f) {
  function methodOp (line 3753) | function methodOp(f) {
  function docMethodOp (line 3761) | function docMethodOp(f) {
  function regChange (line 3777) | function regChange(cm, from, to, lendiff) {
  function regLineChange (line 3842) | function regLineChange(cm, line, type) {
  function resetView (line 3856) | function resetView(cm) {
  function viewCuttingPoint (line 3862) | function viewCuttingPoint(cm, oldN, newN, dir) {
  function adjustView (line 3889) | function adjustView(cm, from, to) {
  function countDirtyView (line 3910) | function countDirtyView(cm) {
  function startWorker (line 3921) | function startWorker(cm, time) {
  function highlightWorker (line 3926) | function highlightWorker(cm) {
  function DisplayUpdate (line 3966) | function DisplayUpdate(cm, viewport, force) {
  function maybeClipScrollbars (line 3992) | function maybeClipScrollbars(cm) {
  function updateDisplayIfNeeded (line 4006) | function updateDisplayIfNeeded(cm, update) {
  function postUpdateDisplay (line 4078) | function postUpdateDisplay(cm, update) {
  function updateDisplaySimple (line 4107) | function updateDisplaySimple(cm, viewport) {
  function patchDisplay (line 4124) | function patchDisplay(cm, updateNumbersFrom, dims) {
  function updateGutterSpace (line 4166) | function updateGutterSpace(cm) {
  function setDocumentHeight (line 4171) | function setDocumentHeight(cm, measure) {
  function updateGutters (line 4179) | function updateGutters(cm) {
  function setGuttersForLineNumbers (line 4197) | function setGuttersForLineNumbers(options) {
  function Selection (line 4212) | function Selection(ranges, primIndex) {
  function Range (line 4258) | function Range(anchor, head) {
  function normalizeSelection (line 4273) | function normalizeSelection(ranges, primIndex) {
  function simpleSelection (line 4289) | function simpleSelection(anchor, head) {
  function changeEnd (line 4295) | function changeEnd(change) {
  function adjustForChange (line 4303) | function adjustForChange(pos, change) {
  function computeSelAfterChange (line 4312) | function computeSelAfterChange(doc, change) {
  function offsetPos (line 4322) | function offsetPos(pos, old, nw) {
  function computeReplacedSel (line 4331) | function computeReplacedSel(doc, changes, hint) {
  function loadMode (line 4352) | function loadMode(cm) {
  function resetModeState (line 4357) | function resetModeState(cm) {
  function isWholeLineUpdate (line 4373) | function isWholeLineUpdate(doc, change) {
  function updateDoc (line 4379) | function updateDoc(doc, change, markedSpans, estimateHeight) {
  function linkedDocs (line 4431) | function linkedDocs(doc, f, sharedHistOnly) {
  function attachDoc (line 4446) | function attachDoc(cm, doc) {
  function History (line 4457) | function History(startGen) {
  function historyChangeFromChange (line 4474) | function historyChangeFromChange(doc, change) {
  function clearSelectionEvents (line 4483) | function clearSelectionEvents(array) {
  function lastChangeEvent (line 4493) | function lastChangeEvent(hist, force) {
  function addChangeToHistory (line 4508) | function addChangeToHistory(doc, change, selAfter, opId) {
  function selectionEventCanBeMerged (line 4551) | function selectionEventCanBeMerged(doc, origin, prev, sel) {
  function addSelectionToHistory (line 4564) | function addSelectionToHistory(doc, sel, opId, options) {
  function pushSelectionToHistory (line 4586) | function pushSelectionToHistory(sel, dest) {
  function attachLocalSpans (line 4593) | function attachLocalSpans(doc, change, from, to) {
  function removeClearedSpans (line 4604) | function removeClearedSpans(spans) {
  function getOldSpans (line 4615) | function getOldSpans(doc, change) {
  function mergeOldSpans (line 4628) | function mergeOldSpans(doc, change) {
  function copyHistoryArray (line 4652) | function copyHistoryArray(events, newGroup, instantiateSel) {
  function extendRange (line 4684) | function extendRange(doc, range, head, other) {
  function extendSelection (line 4703) | function extendSelection(doc, head, other, options) {
  function extendSelections (line 4709) | function extendSelections(doc, heads, options) {
  function replaceOneSelection (line 4718) | function replaceOneSelection(doc, i, range, options) {
  function setSimpleSelection (line 4725) | function setSimpleSelection(doc, anchor, head, options) {
  function filterSelectionChange (line 4731) | function filterSelectionChange(doc, sel, options) {
  function setSelectionReplaceHistory (line 4750) | function setSelectionReplaceHistory(doc, sel, options) {
  function setSelection (line 4761) | function setSelection(doc, sel, options) {
  function setSelectionNoUndo (line 4766) | function setSelectionNoUndo(doc, sel, options) {
  function setSelectionInner (line 4778) | function setSelectionInner(doc, sel) {
  function reCheckSelection (line 4792) | function reCheckSelection(doc) {
  function skipAtomicInSelection (line 4798) | function skipAtomicInSelection(doc, sel, bias, mayClear) {
  function skipAtomicInner (line 4813) | function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
  function skipAtomic (line 4846) | function skipAtomic(doc, pos, oldPos, bias, mayClear) {
  function movePos (line 4859) | function movePos(doc, pos, dir, line) {
  function selectAll (line 4871) | function selectAll(cm) {
  function filterChange (line 4878) | function filterChange(doc, change, update) {
  function makeChange (line 4902) | function makeChange(doc, change, ignoreReadOnly) {
  function makeChangeInner (line 4924) | function makeChangeInner(doc, change) {
  function makeChangeFromHistory (line 4942) | function makeChangeFromHistory(doc, type, allowSelectionOnly) {
  function shiftDoc (line 5015) | function shiftDoc(doc, distance) {
  function makeChangeSingleDoc (line 5031) | function makeChangeSingleDoc(doc, change, selAfter, spans) {
  function makeChangeSingleDocInEditor (line 5064) | function makeChangeSingleDocInEditor(cm, change, spans) {
  function replaceRange (line 5123) | function replaceRange(doc, code, from, to, origin) {
  function rebaseHistSelSingle (line 5132) | function rebaseHistSelSingle(pos, from, to, diff) {
  function rebaseHistArray (line 5148) | function rebaseHistArray(array, from, to, diff) {
  function rebaseHist (line 5176) | function rebaseHist(hist, change) {
  function changeLine (line 5185) | function changeLine(doc, handle, changeType, op) {
  function LeafChunk (line 5207) | function LeafChunk(lines) {
  function BranchChunk (line 5256) | function BranchChunk(children) {
  function LineWidget (line 5369) | function LineWidget(doc, node, options) {
  function adjustScrollWhenAboveVisible (line 5379) | function adjustScrollWhenAboveVisible(cm, line, diff) {
  function addLineWidget (line 5410) | function addLineWidget(doc, handle, node, options) {
  function TextMarker (line 5447) | function TextMarker(doc, type) {
  function markText (line 5565) | function markText(doc, from, to, options, type) {
  function SharedTextMarker (line 5639) | function SharedTextMarker(markers, primary) {
  function markTextShared (line 5662) | function markTextShared(doc, from, to, options, type) {
  function findSharedMarkers (line 5677) | function findSharedMarkers(doc) {
  function copySharedMarkers (line 5681) | function copySharedMarkers(doc, markers) {
  function detachSharedMarkers (line 5693) | function detachSharedMarkers(markers) {
  function onDrop (line 6086) | function onDrop(e) {
  function onDragStart (line 6146) | function onDragStart(cm, e) {
  function onDragOver (line 6169) | function onDragOver(cm, e) {
  function clearDragCursor (line 6181) | function clearDragCursor(cm) {
  function forEachCodeMirror (line 6192) | function forEachCodeMirror(f) {
  function ensureGlobalHandlers (line 6202) | function ensureGlobalHandlers() {
  function registerGlobalHandlers (line 6207) | function registerGlobalHandlers() {
  function onResize (line 6220) | function onResize(cm) {
  function normalizeKeyName (line 6293) | function normalizeKeyName(name) {
  function normalizeKeyMap (line 6317) | function normalizeKeyMap(keymap) {
  function lookupKey (line 6344) | function lookupKey(key, map, handle, context) {
  function isModifierKey (line 6363) | function isModifierKey(value) {
  function keyName (line 6369) | function keyName(event, noShift) {
  function getKeyMap (line 6380) | function getKeyMap(val) {
  function deleteNearSelection (line 6386) | function deleteNearSelection(cm, compute) {
  function lineStart (line 6552) | function lineStart(cm, lineN) {
  function lineEnd (line 6560) | function lineEnd(cm, lineN) {
  function lineStartSmart (line 6570) | function lineStartSmart(cm, pos) {
  function doHandleBinding (line 6583) | function doHandleBinding(cm, bound, dropShift) {
  function lookupKeyForEditor (line 6603) | function lookupKeyForEditor(cm, name, handle) {
  function dispatchKey (line 6613) | function dispatchKey(cm, name, e, handle) {
  function handleKeyBinding (line 6645) | function handleKeyBinding(cm, e) {
  function handleCharBinding (line 6664) | function handleCharBinding(cm, e, ch) {
  function onKeyDown (line 6669) | function onKeyDown(e) {
  function showCrossHair (line 6690) | function showCrossHair(cm) {
  function onKeyUp (line 6705) | function onKeyUp(e) {
  function onKeyPress (line 6710) | function onKeyPress(e) {
  function onMouseDown (line 6728) | function onMouseDown(e) {
  function leftButtonDown (line 6771) | function leftButtonDown(cm, e, start) {
  function leftButtonStartDrag (line 6798) | function leftButtonStartDrag(cm, e, start, modifier) {
  function leftButtonSelect (line 6827) | function leftButtonSelect(cm, e, start, type, addNew) {
  function gutterEvent (line 6975) | function gutterEvent(cm, e, type, prevent) {
  function clickInGutter (line 6999) | function clickInGutter(cm, e) {
  function onContextMenu (line 7008) | function onContextMenu(cm, e) {
  function contextMenuInGutter (line 7014) | function contextMenuInGutter(cm, e) {
  function themeChanged (line 7019) | function themeChanged(cm) {
  function defineOptions (line 7030) | function defineOptions(CodeMirror) {
  function guttersChanged (line 7163) | function guttersChanged(cm) {
  function dragDropChanged (line 7169) | function dragDropChanged(cm, value, old) {
  function wrappingChanged (line 7182) | function wrappingChanged(cm) {
  function CodeMirror (line 7200) | function CodeMirror(place, options) {
  function registerEventHandlers (line 7275) | function registerEventHandlers(cm) {
  function indentLine (line 7389) | function indentLine(cm, n, how, aggressive) {
  function setLastCopied (line 7453) | function setLastCopied(newLastCopied) {
  function applyTextInput (line 7457) | function applyTextInput(cm, inserted, deleted, sel, origin) {
  function handlePaste (line 7505) | function handlePaste(e, cm) {
  function triggerElectric (line 7515) | function triggerElectric(cm, inserted) {
  function copyableRanges (line 7539) | function copyableRanges(cm) {
  function disableBrowserMagic (line 7550) | function disableBrowserMagic(field, spellcheck) {
  function hiddenTextarea (line 7556) | function hiddenTextarea() {
  function addEditorMethods (line 7579) | function addEditorMethods(CodeMirror) {
  function findPosH (line 8066) | function findPosH(doc, pos, dir, unit, visually) {
  function findPosV (line 8118) | function findPosV(cm, pos, dir, unit) {
  function ContentEditableInput (line 8140) | function ContentEditableInput(cm) {
  function onCopyCut (line 8197) | function onCopyCut(e) {
  function poll (line 8339) | function poll() {
  function posToDOM (line 8460) | function posToDOM(cm, pos) {
  function badPos (line 8476) | function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
  function domTextBetween (line 8478) | function domTextBetween(cm, from, to, fromLine, toLine) {
  function domToPos (line 8519) | function domToPos(cm, node, offset) {
  function locateNodeInLineView (line 8538) | function locateNodeInLineView(lineView, node, offset) {
  function TextareaInput (line 8595) | function TextareaInput(cm) {
  function prepareCopyCut (line 8642) | function prepareCopyCut(e) {
  function p (line 8784) | function p() {
  function prepareSelectAllHack (line 8887) | function prepareSelectAllHack() {
  function rehide (line 8900) | function rehide() {
  function fromTextArea (line 8942) | function fromTextArea(textarea, options) {
  function addLegacyProps (line 8999) | function addLegacyProps(CodeMirror) {

FILE: asset/show-hint.js
  function Completion (line 49) | function Completion(cm, options) {
  function parseOptions (line 137) | function parseOptions(cm, pos, options) {
  function getText (line 149) | function getText(completion) {
  function buildKeyMap (line 154) | function buildKeyMap(completion, handle) {
  function getHintElement (line 189) | function getHintElement(hintsElement, el) {
  function Widget (line 196) | function Widget(completion, data) {
  function applicableHelpers (line 351) | function applicableHelpers(cm, helpers) {
  function fetchHints (line 359) | function fetchHints(hint, cm, options, callback) {
  function resolveAutoHints (line 369) | function resolveAutoHints(cm, pos) {

FILE: asset/sql-hint.js
  function isArray (line 24) | function isArray(val) { return Object.prototype.toString.call(val) == "[...
  function getKeywords (line 26) | function getKeywords(editor) {
  function getIdentifierQuote (line 32) | function getIdentifierQuote(editor) {
  function getText (line 38) | function getText(item) {
  function wrapTable (line 42) | function wrapTable(name, value) {
  function parseTables (line 48) | function parseTables(input) {
  function getTable (line 62) | function getTable(name) {
  function shallowClone (line 66) | function shallowClone(object) {
  function match (line 73) | function match(string, word) {
  function addMatches (line 79) | function addMatches(result, search, wordlist, formatter) {
  function cleanName (line 95) | function cleanName(name) {
  function insertIdentifierQuotes (line 108) | function insertIdentifierQuotes(name) {
  function nameCompletion (line 122) | function nameCompletion(cur, token, result, editor) {
  function eachWord (line 187) | function eachWord(lineText, f) {
  function findTableByAlias (line 193) | function findTableByAlias(alias, editor) {

FILE: asset/sql-qone.js
  function tokenBase (line 29) | function tokenBase(stream, state) {
  function tokenLiteral (line 128) | function tokenLiteral(quote) {
  function tokenComment (line 141) | function tokenComment(depth) {
  function pushContext (line 152) | function pushContext(stream, state, type) {
  function popContext (line 161) | function popContext(state) {
  function hookIdentifier (line 213) | function hookIdentifier(stream) {
  function hookIdentifierDoublequote (line 225) | function hookIdentifierDoublequote(stream) {
  function hookVar (line 238) | function hookVar(stream) {
  function hookClient (line 265) | function hookClient(stream) {
  function set (line 280) | function set(str) {

FILE: qone.js
  function HOP (line 25) | function HOP(obj, prop) {
  function isArray (line 29) | function isArray(item) {
  function isObject (line 33) | function isObject(obj) {
  function obj2keys (line 37) | function obj2keys(obj) {
  function array2hash (line 43) | function array2hash(a) {
  function isDigit (line 51) | function isDigit(ch) {
  function isAlphanumericChar (line 56) | function isAlphanumericChar(ch) {
  function characters (line 60) | function characters(str) {
  function parseJsNumber (line 68) | function parseJsNumber(num) {
  function isLetter (line 86) | function isLetter(ch) {
  function isUndefinedOrNull (line 116) | function isUndefinedOrNull(value) {
  function objEquiv (line 120) | function objEquiv(a, b, opts) {
  function toObject (line 163) | function toObject(val) {
  function shouldUseNative (line 171) | function shouldUseNative() {

FILE: test/lib/qunit.js
  function defineProperties (line 59) | function defineProperties(target, props) {
  function diff (line 138) | function diff(a, b) {
  function inArray (line 163) | function inArray(elem, array) {
  function objectValues (line 174) | function objectValues(obj) {
  function extend (line 187) | function extend(a, b, undefOnly) {
  function objectType (line 201) | function objectType(obj) {
  function is (line 236) | function is(type, obj) {
  function generateHash (line 242) | function generateHash(module, testName) {
  function useStrictEquality (line 274) | function useStrictEquality(a, b) {
  function compareConstructors (line 291) | function compareConstructors(a, b) {
  function getRegExpFlags (line 319) | function getRegExpFlags(regexp) {
  function isContainer (line 323) | function isContainer(val) {
  function breadthFirstCompareChild (line 327) | function breadthFirstCompareChild(a, b) {
  function typeEquiv (line 545) | function typeEquiv(a, b) {
  function innerEquiv (line 559) | function innerEquiv(a, b) {
  function quote (line 672) | function quote(str) {
  function literal (line 675) | function literal(o) {
  function join (line 678) | function join(pre, arr, post) {
  function array (line 690) | function array(arr, stack) {
  function isArray (line 706) | function isArray(obj) {
  function emit (line 968) | function emit(eventName, data) {
  function on (line 991) | function on(eventName, callback) {
  function registerLoggingCallbacks (line 1012) | function registerLoggingCallbacks(obj) {
  function runLoggingCallbacks (line 1042) | function runLoggingCallbacks(key, args) {
  function extractStacktrace (line 1055) | function extractStacktrace(e, offset) {
  function sourceFromStacktrace (line 1081) | function sourceFromStacktrace(offset) {
  function advance (line 1109) | function advance() {
  function advanceTaskQueue (line 1120) | function advanceTaskQueue() {
  function advanceTestQueue (line 1142) | function advanceTestQueue() {
  function addToTaskQueue (line 1162) | function addToTaskQueue(tasksArray) {
  function taskQueueLength (line 1170) | function taskQueueLength() {
  function addToTestQueue (line 1180) | function addToTestQueue(testTasksFunc, prioritize, seed) {
  function unitSamplerGenerator (line 1199) | function unitSamplerGenerator(seed) {
  function done (line 1222) | function done() {
  function TestReport (line 1279) | function TestReport(name, suite, options) {
  function Test (line 1384) | function Test(settings) {
  function getNotStartedModules (line 1456) | function getNotStartedModules(startModule) {
  function runTest (line 1529) | function runTest(test) {
  function processHooks (line 1588) | function processHooks(test, module) {
  function logSuiteEnd (line 1695) | function logSuiteEnd(module) {
  function runTest (line 1722) | function runTest() {
  function moduleChainNameMatch (line 1863) | function moduleChainNameMatch(testModule) {
  function moduleChainIdMatch (line 1874) | function moduleChainIdMatch(testModule) {
  function pushFailure (line 1930) | function pushFailure() {
  function saveGlobal (line 1941) | function saveGlobal() {
  function checkPollution (line 1958) | function checkPollution() {
  function test (line 1977) | function test(testName, callback) {
  function todo (line 1990) | function todo(testName, callback) {
  function skip (line 2005) | function skip(testName) {
  function only (line 2019) | function only(testName, callback) {
  function internalStop (line 2036) | function internalStop(test) {
  function internalRecover (line 2072) | function internalRecover(test) {
  function internalStart (line 2078) | function internalStart(test) {
  function collectTests (line 2122) | function collectTests(module) {
  function numberOfTests (line 2136) | function numberOfTests(module) {
  function numberOfUnskippedTests (line 2140) | function numberOfUnskippedTests(module) {
  function notifyTestsRan (line 2146) | function notifyTestsRan(module, skipped) {
  function consoleProxy (line 2165) | function consoleProxy(method) {
  function Assert (line 2178) | function Assert(testContext) {
  function errorString (line 2615) | function errorString(error) {
  function exportQUnit (line 2637) | function exportQUnit(QUnit) {
  function SuiteReport (line 2676) | function SuiteReport(name, parentSuite) {
  function onError (line 2794) | function onError(error) {
  function onUnhandledRejection (line 2814) | function onUnhandledRejection(reason) {
  function createModule (line 2851) | function createModule(name, testEnvironment, modifiers) {
  function processModule (line 2889) | function processModule(name, options, executeNow) {
  function module$1 (line 2929) | function module$1(name, options, executeNow) {
  function scheduleBegin (line 3079) | function scheduleBegin() {
  function begin (line 3093) | function begin() {
  function setHookFunction (line 3129) | function setHookFunction(module, hookName) {
  function storeFixture (line 3147) | function storeFixture() {
  function resetFixture (line 3163) | function resetFixture() {
  function getUrlParams (line 3251) | function getUrlParams() {
  function decodeQueryParam (line 3275) | function decodeQueryParam(param) {
  function escapeText (line 3288) | function escapeText(s) {
  function addEvent (line 3326) | function addEvent(elem, type, fn) {
  function removeEvent (line 3330) | function removeEvent(elem, type, fn) {
  function addEvents (line 3334) | function addEvents(elems, type, fn) {
  function hasClass (line 3341) | function hasClass(elem, name) {
  function addClass (line 3345) | function addClass(elem, name) {
  function toggleClass (line 3351) | function toggleClass(elem, name, force) {
  function removeClass (line 3359) | function removeClass(elem, name) {
  function id (line 3371) | function id(name) {
  function abortTests (line 3375) | function abortTests() {
  function interceptNavigation (line 3385) | function interceptNavigation(ev) {
  function getUrlConfigHtml (line 3395) | function getUrlConfigHtml() {
  function toolbarChanged (line 3449) | function toolbarChanged() {
  function setUrl (line 3480) | function setUrl(params) {
  function applyUrlParams (line 3509) | function applyUrlParams() {
  function toolbarUrlConfigContainer (line 3531) | function toolbarUrlConfigContainer() {
  function abortTestsButton (line 3543) | function abortTestsButton() {
  function toolbarLooseFilter (line 3551) | function toolbarLooseFilter() {
  function moduleListHtml (line 3578) | function moduleListHtml() {
  function toolbarModuleFilter (line 3593) | function toolbarModuleFilter() {
  function appendToolbar (line 3723) | function appendToolbar() {
  function appendHeader (line 3734) | function appendHeader() {
  function appendBanner (line 3742) | function appendBanner() {
  function appendTestResults (line 3750) | function appendTestResults() {
  function appendFilteredTest (line 3774) | function appendFilteredTest() {
  function appendUserAgent (line 3782) | function appendUserAgent() {
  function appendInterface (line 3791) | function appendInterface() {
  function appendTestsList (line 3805) | function appendTestsList(modules) {
  function appendTest (line 3819) | function appendTest(name, testId, moduleName) {
  function getNameHtml (line 3927) | function getNameHtml(name, module) {
  function stripHtml (line 3959) | function stripHtml(string) {
  function DiffMatchPatch (line 4222) | function DiffMatchPatch() {}
  function diffHalfMatchI (line 4590) | function diffHalfMatchI(longtext, shorttext, i) {
  function diffLinesToCharsMunge (line 5071) | function diffLinesToCharsMunge(text) {
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (759K chars).
[
  {
    "path": ".eslintrc",
    "chars": 363,
    "preview": "{\n    \"extends\": \"standard\",\n    \"rules\": {\n        \"indent\": [\n            \"error\",\n            4\n        ],\n        \"s"
  },
  {
    "path": ".gitignore",
    "chars": 13,
    "preview": "/node_modules"
  },
  {
    "path": "README-CN.md",
    "chars": 9227,
    "preview": "[English](./README.md) | 简体中文\n\n<a href=\"##qone\"><img src=\"./asset/qone.png\" alt=\"qone\"></a>\n============================"
  },
  {
    "path": "README.md",
    "chars": 10974,
    "preview": "\nEnglish | [简体中文](./README-CN.md) \n\n\n<a href=\"##qone\"><img src=\"./asset/qone.png\" alt=\"qone\"></a>\n======================"
  },
  {
    "path": "asset/codemirror.css",
    "chars": 8542,
    "preview": "/* BASICS */\n\n.CodeMirror {\n  /* Set height, width, borders, and global font properties here */\n  font-family: monospace"
  },
  {
    "path": "asset/codemirror.js",
    "chars": 337692,
    "preview": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/L"
  },
  {
    "path": "asset/show-hint.js",
    "chars": 15925,
    "preview": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/L"
  },
  {
    "path": "asset/sql-hint.js",
    "chars": 9551,
    "preview": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/L"
  },
  {
    "path": "asset/sql-qone.js",
    "chars": 11862,
    "preview": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/L"
  },
  {
    "path": "index.html",
    "chars": 27244,
    "preview": "<!doctype html>\n<html>\n<head>\n    <meta id=\"viewport\" name=\"viewport\" content=\"width=device-width,initial-scale=1.0, max"
  },
  {
    "path": "package.json",
    "chars": 892,
    "preview": "{\n  \"name\": \"qone\",\n  \"version\": \"2.0.0\",\n  \"main\": \"qone.js\",\n  \"description\": \"Next-generation web query language, ext"
  },
  {
    "path": "qone.js",
    "chars": 50858,
    "preview": "/* qone v2.0.0 - Next-generation web query language, extend .NET LINQ for javascript.\n * By dntzhang https://github.com/"
  },
  {
    "path": "test/clone.html",
    "chars": 1604,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n\n</head>\n\n<body>\n  <div id=\"aa\">aa</div>\n  <script>\n\n    var S = function (num) {\n      t"
  },
  {
    "path": "test/index.html",
    "chars": 465,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\">\n  <link rel=\"icon\" type=\"images/png\"  href=\"../asset/qone.ico\">\n"
  },
  {
    "path": "test/index.ie.html",
    "chars": 1994,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\">\n  <link rel=\"icon\" type=\"images/png\" href=\"../asset/qone.ico\">\n "
  },
  {
    "path": "test/lib/qunit.css",
    "chars": 7879,
    "preview": "/*!\n * QUnit 2.6.1-pre\n * https://qunitjs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released unde"
  },
  {
    "path": "test/lib/qunit.js",
    "chars": 151831,
    "preview": "/*!\n * QUnit 2.6.1-pre\n * https://qunitjs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released unde"
  },
  {
    "path": "test/test.ie.js",
    "chars": 29202,
    "preview": "\"use strict\";\n\nQUnit.test(\"Basic test\", function (assert) {\n    var arr = [1, 2, 3, 4, 5];\n\n    var result = qone({ arr:"
  },
  {
    "path": "test/test.js",
    "chars": 30906,
    "preview": "\nQUnit.test(\"Basic test\", function (assert) {\n    var arr = [1, 2, 3, 4, 5]\n\n    var result = qone({ arr }).query(`\n    "
  }
]

About this extraction

This page contains the full source code of the AlloyTeam/omix GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (690.5 KB), approximately 200.3k tokens, and a symbol index with 542 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!