From ed1e9ec1509335c7e5356145fc1249d683671836 Mon Sep 17 00:00:00 2001
From: Arnaud Fontaine <arnaud.fontaine@nexedi.com>
Date: Tue, 13 Aug 2013 14:42:47 +0900
Subject: [PATCH] ZODB Components: Add Ace Editor settings menu (Alt+p) to set
 up keybinding styles for example.

---
 .../ace/ext-settings_menu.js.xml              |  668 +++++++
 .../ace/keybinding-emacs.js.xml               | 1102 +++++++++++
 .../erp5_ace_editor/ace/keybinding-vim.js.xml | 1756 +++++++++++++++++
 .../erp5_ace_editor/ace_editor_support.xml    |   11 +
 bt5/erp5_ace_editor/bt/change_log             |    3 +
 bt5/erp5_ace_editor/bt/revision               |    2 +-
 6 files changed, 3541 insertions(+), 1 deletion(-)
 create mode 100644 bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/ext-settings_menu.js.xml
 create mode 100644 bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/keybinding-emacs.js.xml
 create mode 100644 bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/keybinding-vim.js.xml

diff --git a/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/ext-settings_menu.js.xml b/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/ext-settings_menu.js.xml
new file mode 100644
index 0000000000..8582513dd4
--- /dev/null
+++ b/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/ext-settings_menu.js.xml
@@ -0,0 +1,668 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="File" module="OFS.Image"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_EtagSupport__etag</string> </key>
+            <value> <string>ts76362800.02</string> </value>
+        </item>
+        <item>
+            <key> <string>__name__</string> </key>
+            <value> <string>ext-settings_menu.js</string> </value>
+        </item>
+        <item>
+            <key> <string>content_type</string> </key>
+            <value> <string>application/javascript</string> </value>
+        </item>
+        <item>
+            <key> <string>data</string> </key>
+            <value> <string encoding="cdata"><![CDATA[
+
+/* ***** BEGIN LICENSE BLOCK *****\n
+ * Distributed under the BSD license:\n
+ *\n
+ * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl\n
+ * All rights reserved.\n
+ *\n
+ * Contributed to Ajax.org under the BSD license.\n
+ *\n
+ * Redistribution and use in source and binary forms, with or without\n
+ * modification, are permitted provided that the following conditions are met:\n
+ *     * Redistributions of source code must retain the above copyright\n
+ *       notice, this list of conditions and the following disclaimer.\n
+ *     * Redistributions in binary form must reproduce the above copyright\n
+ *       notice, this list of conditions and the following disclaimer in the\n
+ *       documentation and/or other materials provided with the distribution.\n
+ *     * Neither the name of Ajax.org B.V. nor the\n
+ *       names of its contributors may be used to endorse or promote products\n
+ *       derived from this software without specific prior written permission.\n
+ *\n
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\n
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY\n
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n
+ *\n
+ * ***** END LICENSE BLOCK ***** */\n
+\n
+define(\'ace/ext/settings_menu\', [\'require\', \'exports\', \'module\' , \'ace/ext/menu_tools/generate_settings_menu\', \'ace/ext/menu_tools/overlay_page\', \'ace/editor\'], function(require, exports, module) {\n
+\n
+var generateSettingsMenu = require(\'./menu_tools/generate_settings_menu\').generateSettingsMenu;\n
+var overlayPage = require(\'./menu_tools/overlay_page\').overlayPage;\n
+function showSettingsMenu(editor) {\n
+    var sm = document.getElementById(\'ace_settingsmenu\');\n
+    if (!sm)    \n
+        overlayPage(editor, generateSettingsMenu(editor), \'0\', \'0\', \'0\');\n
+}\n
+module.exports.init = function(editor) {\n
+    var Editor = require("ace/editor").Editor;\n
+    Editor.prototype.showSettingsMenu = function() {\n
+        showSettingsMenu(this);\n
+    };\n
+};\n
+});\n
+\n
+define(\'ace/ext/menu_tools/generate_settings_menu\', [\'require\', \'exports\', \'module\' , \'ace/ext/menu_tools/element_generator\', \'ace/ext/menu_tools/add_editor_menu_options\', \'ace/ext/menu_tools/get_set_functions\'], function(require, exports, module) {\n
+\n
+var egen = require(\'./element_generator\');\n
+var addEditorMenuOptions = require(\'./add_editor_menu_options\').addEditorMenuOptions;\n
+var getSetFunctions = require(\'./get_set_functions\').getSetFunctions;\n
+module.exports.generateSettingsMenu = function generateSettingsMenu (editor) {\n
+    var elements = [];\n
+    function cleanupElementsList() {\n
+        elements.sort(function(a, b) {\n
+            var x = a.getAttribute(\'contains\');\n
+            var y = b.getAttribute(\'contains\');\n
+            return x.localeCompare(y);\n
+        });\n
+    }\n
+    function wrapElements() {\n
+        var topmenu = document.createElement(\'div\');\n
+        topmenu.setAttribute(\'id\', \'ace_settingsmenu\');\n
+        elements.forEach(function(element) {\n
+            topmenu.appendChild(element);\n
+        });\n
+        return topmenu;\n
+    }\n
+    function createNewEntry(obj, clss, item, val) {\n
+        var el;\n
+        var div = document.createElement(\'div\');\n
+        div.setAttribute(\'contains\', item);\n
+        div.setAttribute(\'class\', \'ace_optionsMenuEntry\');\n
+        div.setAttribute(\'style\', \'clear: both;\');\n
+\n
+        div.appendChild(egen.createLabel(\n
+            item.replace(/^set/, \'\').replace(/([A-Z])/g, \' $1\').trim(),\n
+            item\n
+        ));\n
+\n
+        if (Array.isArray(val)) {\n
+            el = egen.createSelection(item, val, clss);\n
+            el.addEventListener(\'change\', function(e) {\n
+                try{\n
+                    editor.menuOptions[e.target.id].forEach(function(x) {\n
+                        if(x.textContent !== e.target.textContent) {\n
+                            delete x.selected;\n
+                        }\n
+                    });\n
+                    obj[e.target.id](e.target.value);\n
+                } catch (err) {\n
+                    throw new Error(err);\n
+                }\n
+            });\n
+        } else if(typeof val === \'boolean\') {\n
+            el = egen.createCheckbox(item, val, clss);\n
+            el.addEventListener(\'change\', function(e) {\n
+                try{\n
+                    obj[e.target.id](!!e.target.checked);\n
+                } catch (err) {\n
+                    throw new Error(err);\n
+                }\n
+            });\n
+        } else {\n
+            el = egen.createInput(item, val, clss);\n
+            el.addEventListener(\'change\', function(e) {\n
+                try{\n
+                    if(e.target.value === \'true\') {\n
+                        obj[e.target.id](true);\n
+                    } else if(e.target.value === \'false\') {\n
+                        obj[e.target.id](false);\n
+                    } else {\n
+                        obj[e.target.id](e.target.value);\n
+                    }\n
+                } catch (err) {\n
+                    throw new Error(err);\n
+                }\n
+            });\n
+        }\n
+        el.style.cssText = \'float:right;\';\n
+        div.appendChild(el);\n
+        return div;\n
+    }\n
+    function makeDropdown(item, esr, clss, fn) {\n
+        var val = editor.menuOptions[item];\n
+        var currentVal = esr[fn]();\n
+        if (typeof currentVal == \'object\')\n
+            currentVal = currentVal.$id;\n
+        val.forEach(function(valuex) {\n
+            if (valuex.value === currentVal)\n
+                valuex.selected = \'selected\';\n
+        });\n
+        return createNewEntry(esr, clss, item, val);\n
+    }\n
+    function handleSet(setObj) {\n
+        var item = setObj.functionName;\n
+        var esr = setObj.parentObj;\n
+        var clss = setObj.parentName;\n
+        var val;\n
+        var fn = item.replace(/^set/, \'get\');\n
+        if(editor.menuOptions[item] !== undefined) {\n
+            elements.push(makeDropdown(item, esr, clss, fn));\n
+        } else if(typeof esr[fn] === \'function\') {\n
+            try {\n
+                val = esr[fn]();\n
+                if(typeof val === \'object\') {\n
+                    val = val.$id;\n
+                }\n
+                elements.push(\n
+                    createNewEntry(esr, clss, item, val)\n
+                );\n
+            } catch (e) {\n
+            }\n
+        }\n
+    }\n
+    addEditorMenuOptions(editor);\n
+    getSetFunctions(editor).forEach(function(setObj) {\n
+        handleSet(setObj);\n
+    });\n
+    cleanupElementsList();\n
+    return wrapElements();\n
+};\n
+\n
+});\n
+\n
+define(\'ace/ext/menu_tools/element_generator\', [\'require\', \'exports\', \'module\' ], function(require, exports, module) {\n
+module.exports.createOption = function createOption (obj) {\n
+    var attribute;\n
+    var el = document.createElement(\'option\');\n
+    for(attribute in obj) {\n
+        if(obj.hasOwnProperty(attribute)) {\n
+            if(attribute === \'selected\') {\n
+                el.setAttribute(attribute, obj[attribute]);\n
+            } else {\n
+                el[attribute] = obj[attribute];\n
+            }\n
+        }\n
+    }\n
+    return el;\n
+};\n
+module.exports.createCheckbox = function createCheckbox (id, checked, clss) {\n
+    var el = document.createElement(\'input\');\n
+    el.setAttribute(\'type\', \'checkbox\');\n
+    el.setAttribute(\'id\', id);\n
+    el.setAttribute(\'name\', id);\n
+    el.setAttribute(\'value\', checked);\n
+    el.setAttribute(\'class\', clss);\n
+    if(checked) {\n
+        el.setAttribute(\'checked\', \'checked\');\n
+    }\n
+    return el;\n
+};\n
+module.exports.createInput = function createInput (id, value, clss) {\n
+    var el = document.createElement(\'input\');\n
+    el.setAttribute(\'type\', \'text\');\n
+    el.setAttribute(\'id\', id);\n
+    el.setAttribute(\'name\', id);\n
+    el.setAttribute(\'value\', value);\n
+    el.setAttribute(\'class\', clss);\n
+    return el;\n
+};\n
+module.exports.createLabel = function createLabel (text, labelFor) {\n
+    var el = document.createElement(\'label\');\n
+    el.setAttribute(\'for\', labelFor);\n
+    el.textContent = text;\n
+    return el;\n
+};\n
+module.exports.createSelection = function createSelection (id, values, clss) {\n
+    var el = document.createElement(\'select\');\n
+    el.setAttribute(\'id\', id);\n
+    el.setAttribute(\'name\', id);\n
+    el.setAttribute(\'class\', clss);\n
+    values.forEach(function(item) {\n
+        el.appendChild(module.exports.createOption(item));\n
+    });\n
+    return el;\n
+};\n
+\n
+});\n
+\n
+define(\'ace/ext/menu_tools/add_editor_menu_options\', [\'require\', \'exports\', \'module\' , \'ace/ext/modelist\', \'ace/ext/themelist\'], function(require, exports, module) {\n
+module.exports.addEditorMenuOptions = function addEditorMenuOptions (editor) {\n
+    var modelist = require(\'../modelist\');\n
+    var themelist = require(\'../themelist\');\n
+    editor.menuOptions = {\n
+        "setNewLineMode" : [{\n
+            "textContent" : "unix",\n
+            "value" : "unix"\n
+        }, {\n
+            "textContent" : "windows",\n
+            "value" : "windows"\n
+        }, {\n
+            "textContent" : "auto",\n
+            "value" : "auto"\n
+        }],\n
+        "setTheme" : [],\n
+        "setMode" : [],\n
+        "setKeyboardHandler": [{\n
+            "textContent" : "ace",\n
+            "value" : ""\n
+        }, {\n
+            "textContent" : "vim",\n
+            "value" : "ace/keyboard/vim"\n
+        }, {\n
+            "textContent" : "emacs",\n
+            "value" : "ace/keyboard/emacs"\n
+        }]\n
+    };\n
+\n
+    editor.menuOptions.setTheme = themelist.themes.map(function(theme) {\n
+        return {\n
+            \'textContent\' : theme.desc,\n
+            \'value\' : theme.theme\n
+        };\n
+    });\n
+\n
+    editor.menuOptions.setMode = modelist.modes.map(function(mode) {\n
+        return {\n
+            \'textContent\' : mode.name,\n
+            \'value\' : mode.mode\n
+        };\n
+    });\n
+};\n
+\n
+\n
+});define(\'ace/ext/modelist\', [\'require\', \'exports\', \'module\' ], function(require, exports, module) {\n
+\n
+\n
+var modes = [];\n
+function getModeForPath(path) {\n
+    var mode = modesByName.text;\n
+    var fileName = path.split(/[\\/\\\\]/).pop();\n
+    for (var i = 0; i < modes.length; i++) {\n
+        if (modes[i].supportsFile(fileName)) {\n
+            mode = modes[i];\n
+            break;\n
+        }\n
+    }\n
+    return mode;\n
+}\n
+\n
+var Mode = function(name, caption, extensions) {\n
+    this.name = name;\n
+    this.caption = caption;\n
+    this.mode = "ace/mode/" + name;\n
+    this.extensions = extensions;\n
+    if (/\\^/.test(extensions)) {\n
+        var re = extensions.replace(/\\|(\\^)?/g, function(a, b){\n
+            return "$|" + (b ? "^" : "^.*\\\\.");\n
+        }) + "$";\n
+    } else {\n
+        var re = "^.*\\\\.(" + extensions + ")$";\n
+    }\n
+\n
+    this.extRe = new RegExp(re, "gi");\n
+};\n
+\n
+Mode.prototype.supportsFile = function(filename) {\n
+    return filename.match(this.extRe);\n
+};\n
+var supportedModes = {\n
+    ABAP:        ["abap"],\n
+    ADA:         ["ada|adb"],\n
+    ActionScript:["as"],\n
+    AsciiDoc:    ["asciidoc"],\n
+    Assembly_x86:["asm"],\n
+    AutoHotKey:  ["ahk"],\n
+    BatchFile:   ["bat|cmd"],\n
+    C9Search:    ["c9search_results"],\n
+    C_Cpp:       ["c|cc|cpp|cxx|h|hh|hpp"],\n
+    Clojure:     ["clj"],\n
+    Cobol:       ["^CBL|COB"],\n
+    coffee:      ["^Cakefile|coffee|cf|cson"],\n
+    ColdFusion:  ["cfm"],\n
+    CSharp:      ["cs"],\n
+    CSS:         ["css"],\n
+    Curly:       ["curly"],\n
+    D:           ["d|di"],\n
+    Dart:        ["dart"],\n
+    Diff:        ["diff|patch"],\n
+    Dot:         ["dot"],\n
+    Erlang:      ["erl|hrl"],\n
+    EJS:         ["ejs"],\n
+    Forth:       ["frt|fs|ldr"],\n
+    FreeMarker:  ["ftl"],\n
+    Glsl:        ["glsl|frag|vert"],\n
+    golang:      ["go"],\n
+    Groovy:      ["groovy"],\n
+    HAML:        ["haml"],\n
+    Haskell:     ["hs"],\n
+    haXe:        ["hx"],\n
+    HTML:        ["htm|html|xhtml"],\n
+    HTML_Ruby:   ["erb|rhtml|html.erb"],\n
+    Ini:         ["Ini|conf"],\n
+    Jade:        ["jade"],\n
+    Java:        ["java"],\n
+    JavaScript:  ["js"],\n
+    JSON:        ["json"],\n
+    JSONiq:      ["jq"],\n
+    JSP:         ["jsp"],\n
+    JSX:         ["jsx"],\n
+    Julia:       ["jl"],\n
+    LaTeX:       ["latex|tex|ltx|bib"],\n
+    LESS:        ["less"],\n
+    Liquid:      ["liquid"],\n
+    Lisp:        ["lisp"],\n
+    LiveScript:  ["ls"],\n
+    LogiQL:      ["logic|lql"],\n
+    LSL:         ["lsl"],\n
+    Lua:         ["lua"],\n
+    LuaPage:     ["lp"],\n
+    Lucene:      ["lucene"],\n
+    Makefile:    ["^GNUmakefile|^makefile|^Makefile|^OCamlMakefile|make"],\n
+    MATLAB:      ["matlab"],\n
+    Markdown:    ["md|markdown"],\n
+    MySQL:       ["mysql"],\n
+    MUSHCode:    ["mc|mush"],\n
+    ObjectiveC:  ["m|mm"],\n
+    OCaml:       ["ml|mli"],\n
+    Pascal:      ["pas|p"],\n
+    Perl:        ["pl|pm"],\n
+    pgSQL:       ["pgsql"],\n
+    PHP:         ["php|phtml"],\n
+    Powershell:  ["ps1"],\n
+    Prolog:      ["plg|prolog"],\n
+    Properties:  ["properties"],\n
+    Python:      ["py"],\n
+    R:           ["r"],\n
+    RDoc:        ["Rd"],\n
+    RHTML:       ["Rhtml"],\n
+    Ruby:        ["ru|gemspec|rake|rb"],\n
+    Rust:        ["rs"],\n
+    SASS:        ["sass"],\n
+    SCAD:        ["scad"],\n
+    Scala:       ["scala"],\n
+    Scheme:      ["scm|rkt"],\n
+    SCSS:        ["scss"],\n
+    SH:          ["sh|bash"],\n
+    snippets:    ["snippets"],\n
+    SQL:         ["sql"],\n
+    Stylus:      ["styl|stylus"],\n
+    SVG:         ["svg"],\n
+    Tcl:         ["tcl"],\n
+    Tex:         ["tex"],\n
+    Text:        ["txt"],\n
+    Textile:     ["textile"],\n
+    Toml:        ["toml"],\n
+    Twig:        ["twig"],\n
+    Typescript:  ["typescript|ts|str"],\n
+    VBScript:    ["vbs"],\n
+    Velocity:    ["vm"],\n
+    XML:         ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl"],\n
+    XQuery:      ["xq"],\n
+    YAML:        ["yaml"]\n
+};\n
+\n
+var nameOverrides = {\n
+    ObjectiveC: "Objective-C",\n
+    CSharp: "C#",\n
+    golang: "Go",\n
+    C_Cpp: "C/C++",\n
+    coffee: "CoffeeScript",\n
+    HTML_Ruby: "HTML (Ruby)"\n
+};\n
+var modesByName = {};\n
+for (var name in supportedModes) {\n
+    var data = supportedModes[name];\n
+    var displayName = nameOverrides[name] || name;\n
+    var filename = name.toLowerCase();\n
+    var mode = new Mode(filename, displayName, data[0]);\n
+    modesByName[filename] = mode;\n
+    modes.push(mode);\n
+}\n
+\n
+module.exports = {\n
+    getModeForPath: getModeForPath,\n
+    modes: modes,\n
+    modesByName: modesByName\n
+};\n
+\n
+});\n
+\n
+define(\'ace/ext/themelist\', [\'require\', \'exports\', \'module\' , \'ace/ext/themelist_utils/themes\'], function(require, exports, module) {\n
+module.exports.themes = require(\'ace/ext/themelist_utils/themes\').themes;\n
+module.exports.ThemeDescription = function(name) {\n
+    this.name = name;\n
+    this.desc = name.split(\'_\'\n
+        ).map(\n
+            function(namePart) {\n
+                return namePart[0].toUpperCase() + namePart.slice(1);\n
+            }\n
+        ).join(\' \');\n
+    this.theme = "ace/theme/" + name;\n
+};\n
+\n
+module.exports.themesByName = {};\n
+\n
+module.exports.themes = module.exports.themes.map(function(name) {\n
+    module.exports.themesByName[name] = new module.exports.ThemeDescription(name);\n
+    return module.exports.themesByName[name];\n
+});\n
+\n
+});\n
+\n
+define(\'ace/ext/themelist_utils/themes\', [\'require\', \'exports\', \'module\' ], function(require, exports, module) {\n
+\n
+module.exports.themes = [\n
+    "ambiance",\n
+    "chaos",\n
+    "chrome",\n
+    "clouds",\n
+    "clouds_midnight",\n
+    "cobalt",\n
+    "crimson_editor",\n
+    "dawn",\n
+    "dreamweaver",\n
+    "eclipse",\n
+    "github",\n
+    "idle_fingers",\n
+    "kr_theme",\n
+    "merbivore",\n
+    "merbivore_soft",\n
+    "monokai",\n
+    "mono_industrial",\n
+    "pastel_on_dark",\n
+    "solarized_dark",\n
+    "solarized_light",\n
+    "terminal",\n
+    "textmate",\n
+    "tomorrow",\n
+    "tomorrow_night",\n
+    "tomorrow_night_blue",\n
+    "tomorrow_night_bright",\n
+    "tomorrow_night_eighties",\n
+    "twilight",\n
+    "vibrant_ink",\n
+    "xcode"\n
+];\n
+\n
+});\n
+\n
+define(\'ace/ext/menu_tools/get_set_functions\', [\'require\', \'exports\', \'module\' ], function(require, exports, module) {\n
+module.exports.getSetFunctions = function getSetFunctions (editor) {\n
+    var out = [];\n
+    var my = {\n
+        \'editor\' : editor,\n
+        \'session\' : editor.session,\n
+        \'renderer\' : editor.renderer\n
+    };\n
+    var opts = [];\n
+    var skip = [\n
+        \'setOption\',\n
+        \'setUndoManager\',\n
+        \'setDocument\',\n
+        \'setValue\',\n
+        \'setBreakpoints\',\n
+        \'setScrollTop\',\n
+        \'setScrollLeft\',\n
+        \'setSelectionStyle\',\n
+        \'setWrapLimitRange\'\n
+    ];\n
+    [\'renderer\', \'session\', \'editor\'].forEach(function(esra) {\n
+        var esr = my[esra];\n
+        var clss = esra;\n
+        for(var fn in esr) {\n
+            if(skip.indexOf(fn) === -1) {\n
+                if(/^set/.test(fn) && opts.indexOf(fn) === -1) {\n
+                    opts.push(fn);\n
+                    out.push({\n
+                        \'functionName\' : fn,\n
+                        \'parentObj\' : esr,\n
+                        \'parentName\' : clss\n
+                    });\n
+                }\n
+            }\n
+        }\n
+    });\n
+    return out;\n
+};\n
+\n
+});\n
+\n
+define(\'ace/ext/menu_tools/overlay_page\', [\'require\', \'exports\', \'module\' , \'ace/lib/dom\'], function(require, exports, module) {\n
+\n
+var dom = require("../../lib/dom");\n
+var cssText = "#ace_settingsmenu, #kbshortcutmenu {\\\n
+background-color: #F7F7F7;\\\n
+color: black;\\\n
+box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);\\\n
+padding: 1em 0.5em 2em 1em;\\\n
+overflow: auto;\\\n
+position: absolute;\\\n
+margin: 0;\\\n
+bottom: 0;\\\n
+right: 0;\\\n
+top: 0;\\\n
+z-index: 9991;\\\n
+cursor: default;\\\n
+}\\\n
+.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {\\\n
+box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);\\\n
+background-color: rgba(255, 255, 255, 0.6);\\\n
+color: black;\\\n
+}\\\n
+.ace_optionsMenuEntry:hover {\\\n
+background-color: rgba(100, 100, 100, 0.1);\\\n
+-webkit-transition: all 0.5s;\\\n
+transition: all 0.3s\\\n
+}\\\n
+.ace_closeButton {\\\n
+background: rgba(245, 146, 146, 0.5);\\\n
+border: 1px solid #F48A8A;\\\n
+border-radius: 50%;\\\n
+padding: 7px;\\\n
+position: absolute;\\\n
+right: -8px;\\\n
+top: -8px;\\\n
+z-index: 1000;\\\n
+}\\\n
+.ace_closeButton{\\\n
+background: rgba(245, 146, 146, 0.9);\\\n
+}\\\n
+.ace_optionsMenuKey {\\\n
+color: darkslateblue;\\\n
+font-weight: bold;\\\n
+}\\\n
+.ace_optionsMenuCommand {\\\n
+color: darkcyan;\\\n
+font-weight: normal;\\\n
+}";\n
+dom.importCssString(cssText);\n
+module.exports.overlayPage = function overlayPage(editor, contentElement, top, right, bottom, left) {\n
+    top = top ? \'top: \' + top + \';\' : \'\';\n
+    bottom = bottom ? \'bottom: \' + bottom + \';\' : \'\';\n
+    right = right ? \'right: \' + right + \';\' : \'\';\n
+    left = left ? \'left: \' + left + \';\' : \'\';\n
+\n
+    var closer = document.createElement(\'div\');\n
+    var contentContainer = document.createElement(\'div\');\n
+\n
+    function documentEscListener(e) {\n
+        if (e.keyCode === 27) {\n
+            closer.click();\n
+        }\n
+    }\n
+\n
+    closer.style.cssText = \'margin: 0; padding: 0; \' +\n
+        \'position: fixed; top:0; bottom:0; left:0; right:0;\' +\n
+        \'z-index: 9990; \' +\n
+        \'background-color: rgba(0, 0, 0, 0.3);\';\n
+    closer.addEventListener(\'click\', function() {\n
+        document.removeEventListener(\'keydown\', documentEscListener);\n
+        closer.parentNode.removeChild(closer);\n
+        editor.focus();\n
+        closer = null;\n
+    });\n
+    document.addEventListener(\'keydown\', documentEscListener);\n
+\n
+    contentContainer.style.cssText = top + right + bottom + left;\n
+    contentContainer.addEventListener(\'click\', function(e) {\n
+        e.stopPropagation();\n
+    });\n
+\n
+    var wrapper = dom.createElement("div");\n
+    wrapper.style.position = "relative";\n
+    \n
+    var closeButton = dom.createElement("div");\n
+    closeButton.className = "ace_closeButton";\n
+    closeButton.addEventListener(\'click\', function() {\n
+        closer.click();\n
+    });\n
+    \n
+    wrapper.appendChild(closeButton);\n
+    contentContainer.appendChild(wrapper);\n
+    \n
+    contentContainer.appendChild(contentElement);\n
+    closer.appendChild(contentContainer);\n
+    document.body.appendChild(closer);\n
+    editor.blur();\n
+};\n
+\n
+});
+
+]]></string> </value>
+        </item>
+        <item>
+            <key> <string>precondition</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>size</string> </key>
+            <value> <int>19778</int> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/keybinding-emacs.js.xml b/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/keybinding-emacs.js.xml
new file mode 100644
index 0000000000..7d9d275356
--- /dev/null
+++ b/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/keybinding-emacs.js.xml
@@ -0,0 +1,1102 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="File" module="OFS.Image"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_EtagSupport__etag</string> </key>
+            <value> <string>ts76363578.4</string> </value>
+        </item>
+        <item>
+            <key> <string>__name__</string> </key>
+            <value> <string>keybinding-emacs.js</string> </value>
+        </item>
+        <item>
+            <key> <string>content_type</string> </key>
+            <value> <string>application/javascript</string> </value>
+        </item>
+        <item>
+            <key> <string>data</string> </key>
+            <value> <string encoding="cdata"><![CDATA[
+
+/* ***** BEGIN LICENSE BLOCK *****\n
+ * Distributed under the BSD license:\n
+ *\n
+ * Copyright (c) 2010, Ajax.org B.V.\n
+ * All rights reserved.\n
+ *\n
+ * Redistribution and use in source and binary forms, with or without\n
+ * modification, are permitted provided that the following conditions are met:\n
+ *     * Redistributions of source code must retain the above copyright\n
+ *       notice, this list of conditions and the following disclaimer.\n
+ *     * Redistributions in binary form must reproduce the above copyright\n
+ *       notice, this list of conditions and the following disclaimer in the\n
+ *       documentation and/or other materials provided with the distribution.\n
+ *     * Neither the name of Ajax.org B.V. nor the\n
+ *       names of its contributors may be used to endorse or promote products\n
+ *       derived from this software without specific prior written permission.\n
+ *\n
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\n
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY\n
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n
+ *\n
+ * ***** END LICENSE BLOCK ***** */\n
+\n
+define(\'ace/keyboard/emacs\', [\'require\', \'exports\', \'module\' , \'ace/lib/dom\', \'ace/incremental_search\', \'ace/commands/incremental_search_commands\', \'ace/keyboard/hash_handler\', \'ace/lib/keys\'], function(require, exports, module) {\n
+\n
+\n
+var dom = require("../lib/dom");\n
+require("../incremental_search");\n
+var iSearchCommandModule = require("../commands/incremental_search_commands");\n
+\n
+\n
+var screenToTextBlockCoordinates = function(x, y) {\n
+    var canvasPos = this.scroller.getBoundingClientRect();\n
+\n
+    var col = Math.floor(\n
+        (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth\n
+    );\n
+    var row = Math.floor(\n
+        (y + this.scrollTop - canvasPos.top) / this.lineHeight\n
+    );\n
+\n
+    return this.session.screenToDocumentPosition(row, col);\n
+};\n
+\n
+var HashHandler = require("./hash_handler").HashHandler;\n
+exports.handler = new HashHandler();\n
+\n
+exports.handler.isEmacs = true;\n
+exports.handler.$id = "ace/keyboard/emacs";\n
+\n
+var initialized = false;\n
+var $formerLongWords;\n
+var $formerLineStart;\n
+\n
+exports.handler.attach = function(editor) {\n
+    if (!initialized) {\n
+        initialized = true;\n
+        dom.importCssString(\'\\\n
+            .emacs-mode .ace_cursor{\\\n
+                border: 2px rgba(50,250,50,0.8) solid!important;\\\n
+                -moz-box-sizing: border-box!important;\\\n
+                -webkit-box-sizing: border-box!important;\\\n
+                box-sizing: border-box!important;\\\n
+                background-color: rgba(0,250,0,0.9);\\\n
+                opacity: 0.5;\\\n
+            }\\\n
+            .emacs-mode .ace_cursor.ace_hidden{\\\n
+                opacity: 1;\\\n
+                background-color: transparent;\\\n
+            }\\\n
+            .emacs-mode .ace_overwrite-cursors .ace_cursor {\\\n
+                opacity: 1;\\\n
+                background-color: transparent;\\\n
+                border-width: 0 0 2px 2px !important;\\\n
+            }\\\n
+            .emacs-mode .ace_text-layer {\\\n
+                z-index: 4\\\n
+            }\\\n
+            .emacs-mode .ace_cursor-layer {\\\n
+                z-index: 2\\\n
+            }\', \'emacsMode\'\n
+        );\n
+    }\n
+    $formerLongWords = editor.session.$selectLongWords;\n
+    editor.session.$selectLongWords = true;\n
+    $formerLineStart = editor.session.$useEmacsStyleLineStart;\n
+    editor.session.$useEmacsStyleLineStart = true;\n
+\n
+    editor.session.$emacsMark = null; // the active mark\n
+    editor.session.$emacsMarkRing = editor.session.$emacsMarkRing || [];\n
+\n
+    editor.emacsMark = function() {\n
+        return this.session.$emacsMark;\n
+    }\n
+\n
+    editor.setEmacsMark = function(p) {\n
+        this.session.$emacsMark = p;\n
+    }\n
+\n
+    editor.pushEmacsMark = function(p, activate) {\n
+        var prevMark = this.session.$emacsMark;\n
+        if (prevMark)\n
+            this.session.$emacsMarkRing.push(prevMark);\n
+        if (!p || activate) this.setEmacsMark(p)\n
+        else this.session.$emacsMarkRing.push(p);\n
+    }\n
+\n
+    editor.popEmacsMark = function() {\n
+        var mark = this.emacsMark();\n
+        if (mark) { this.setEmacsMark(null); return mark; }\n
+        return this.session.$emacsMarkRing.pop();\n
+    }\n
+\n
+    editor.getLastEmacsMark = function(p) {\n
+        return this.session.$emacsMark || this.session.$emacsMarkRing.slice(-1)[0];\n
+    }\n
+\n
+    editor.on("click", $resetMarkMode);\n
+    editor.on("changeSession", $kbSessionChange);\n
+    editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates;\n
+    editor.setStyle("emacs-mode");\n
+    editor.commands.addCommands(commands);\n
+    exports.handler.platform = editor.commands.platform;\n
+    editor.$emacsModeHandler = this;\n
+    editor.addEventListener(\'copy\', this.onCopy);\n
+    editor.addEventListener(\'paste\', this.onPaste);\n
+};\n
+\n
+exports.handler.detach = function(editor) {\n
+    delete editor.renderer.screenToTextCoordinates;\n
+    editor.session.$selectLongWords = $formerLongWords;\n
+    editor.session.$useEmacsStyleLineStart = $formerLineStart;\n
+    editor.removeEventListener("click", $resetMarkMode);\n
+    editor.removeEventListener("changeSession", $kbSessionChange);\n
+    editor.unsetStyle("emacs-mode");\n
+    editor.commands.removeCommands(commands);\n
+    editor.removeEventListener(\'copy\', this.onCopy);\n
+    editor.removeEventListener(\'paste\', this.onPaste);\n
+};\n
+\n
+var $kbSessionChange = function(e) {\n
+    if (e.oldSession) {\n
+        e.oldSession.$selectLongWords = $formerLongWords;\n
+        e.oldSession.$useEmacsStyleLineStart = $formerLineStart;\n
+    }\n
+\n
+    $formerLongWords = e.session.$selectLongWords;\n
+    e.session.$selectLongWords = true;\n
+    $formerLineStart = e.session.$useEmacsStyleLineStart;\n
+    e.session.$useEmacsStyleLineStart = true;\n
+\n
+    if (!e.session.hasOwnProperty(\'$emacsMark\'))\n
+        e.session.$emacsMark = null;\n
+    if (!e.session.hasOwnProperty(\'$emacsMarkRing\'))\n
+        e.session.$emacsMarkRing = [];\n
+}\n
+\n
+var $resetMarkMode = function(e) {\n
+    e.editor.session.$emacsMark = null;\n
+}\n
+\n
+var keys = require("../lib/keys").KEY_MODS,\n
+    eMods = {C: "ctrl", S: "shift", M: "alt", CMD: "command"},\n
+    combinations = ["C-S-M-CMD",\n
+                    "S-M-CMD", "C-M-CMD", "C-S-CMD", "C-S-M",\n
+                    "M-CMD", "S-CMD", "S-M", "C-CMD", "C-M", "C-S",\n
+                    "CMD", "M", "S", "C"];\n
+combinations.forEach(function(c) {\n
+    var hashId = 0;\n
+    c.split("-").forEach(function(c) {\n
+        hashId = hashId | keys[eMods[c]];\n
+    });\n
+    eMods[hashId] = c.toLowerCase() + "-";\n
+});\n
+\n
+exports.handler.onCopy = function(e, editor) {\n
+    if (editor.$handlesEmacsOnCopy) return;\n
+    editor.$handlesEmacsOnCopy = true;\n
+    exports.handler.commands.killRingSave.exec(editor);\n
+    delete editor.$handlesEmacsOnCopy;\n
+}\n
+\n
+exports.handler.onPaste = function(e, editor) {\n
+    editor.pushEmacsMark(editor.getCursorPosition());\n
+}\n
+\n
+exports.handler.bindKey = function(key, command) {\n
+    if (!key)\n
+        return;\n
+\n
+    var ckb = this.commmandKeyBinding;\n
+    key.split("|").forEach(function(keyPart) {\n
+        keyPart = keyPart.toLowerCase();\n
+        ckb[keyPart] = command;\n
+        var keyParts = keyPart.split(" ").slice(0,-1);\n
+        keyParts.reduce(function(keyMapKeys, keyPart, i) {\n
+            var prefix = keyMapKeys[i-1] ? keyMapKeys[i-1] + \' \' : \'\';\n
+            return keyMapKeys.concat([prefix + keyPart]);\n
+        }, []).forEach(function(keyPart) {\n
+            if (!ckb[keyPart]) ckb[keyPart] = "null";\n
+        });\n
+    }, this);\n
+}\n
+\n
+exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {\n
+    var editor = data.editor;\n
+    if (hashId == -1) {\n
+        editor.pushEmacsMark();\n
+        if (data.count) {\n
+            var str = Array(data.count + 1).join(key);\n
+            data.count = null;\n
+            return {command: "insertstring", args: str};\n
+        }\n
+    }\n
+\n
+    if (key == "\\x00") return undefined;\n
+\n
+    var modifier = eMods[hashId];\n
+    if (modifier == "c-" || data.universalArgument) {\n
+        var prevCount = String(data.count || 0);\n
+        var count = parseInt(key[key.length - 1]);\n
+        if (typeof count === \'number\' && !isNaN(count)) {\n
+            data.count = parseInt(prevCount + count);\n
+            return {command: "null"};\n
+        } else if (data.universalArgument) {\n
+            data.count = 4;\n
+        }\n
+    }\n
+    data.universalArgument = false;\n
+    if (modifier) key = modifier + key;\n
+    if (data.keyChain) key = data.keyChain += " " + key;\n
+    var command = this.commmandKeyBinding[key];\n
+    data.keyChain = command == "null" ? key : "";\n
+    if (!command) return undefined;\n
+    if (command === "null") return {command: "null"};\n
+\n
+    if (command === "universalArgument") {\n
+        data.universalArgument = true;\n
+        return {command: "null"};\n
+    }\n
+    var args;\n
+    if (typeof command !== "string") {\n
+        args = command.args;\n
+        if (command.command) command = command.command;\n
+        if (command === "goorselect") {\n
+            command = editor.emacsMark() ? args[1] : args[0];\n
+            args = null;\n
+        }\n
+    }\n
+\n
+    if (typeof command === "string") {\n
+        if (command === "insertstring" ||\n
+            command === "splitline" ||\n
+            command === "togglecomment") {\n
+            editor.pushEmacsMark();\n
+        }\n
+        command = this.commands[command] || editor.commands.commands[command];\n
+        if (!command) return undefined;\n
+    }\n
+\n
+    if (!command.readonly && !command.isYank)\n
+        data.lastCommand = null;\n
+\n
+    if (data.count) {\n
+        var count = data.count;\n
+        data.count = 0;\n
+        if (!command || !command.handlesCount) {\n
+            return {\n
+                args: args,\n
+                command: {\n
+                    exec: function(editor, args) {\n
+                        for (var i = 0; i < count; i++)\n
+                            command.exec(editor, args);\n
+                    }\n
+                }\n
+            };\n
+        } else {\n
+            if (!args) args = {}\n
+            if (typeof args === \'object\') args.count = count;\n
+        }\n
+    }\n
+\n
+    return {command: command, args: args};\n
+};\n
+\n
+exports.emacsKeys = {\n
+    "Up|C-p"      : {command: "goorselect", args: ["golineup","selectup"]},\n
+    "Down|C-n"    : {command: "goorselect", args: ["golinedown","selectdown"]},\n
+    "Left|C-b"    : {command: "goorselect", args: ["gotoleft","selectleft"]},\n
+    "Right|C-f"   : {command: "goorselect", args: ["gotoright","selectright"]},\n
+    "C-Left|M-b"  : {command: "goorselect", args: ["gotowordleft","selectwordleft"]},\n
+    "C-Right|M-f" : {command: "goorselect", args: ["gotowordright","selectwordright"]},\n
+    "Home|C-a"    : {command: "goorselect", args: ["gotolinestart","selecttolinestart"]},\n
+    "End|C-e"     : {command: "goorselect", args: ["gotolineend","selecttolineend"]},\n
+    "C-Home|S-M-,": {command: "goorselect", args: ["gotostart","selecttostart"]},\n
+    "C-End|S-M-." : {command: "goorselect", args: ["gotoend","selecttoend"]},\n
+    "S-Up|S-C-p"      : "selectup",\n
+    "S-Down|S-C-n"    : "selectdown",\n
+    "S-Left|S-C-b"    : "selectleft",\n
+    "S-Right|S-C-f"   : "selectright",\n
+    "S-C-Left|S-M-b"  : "selectwordleft",\n
+    "S-C-Right|S-M-f" : "selectwordright",\n
+    "S-Home|S-C-a"    : "selecttolinestart",\n
+    "S-End|S-C-e"     : "selecttolineend",\n
+    "S-C-Home"        : "selecttostart",\n
+    "S-C-End"         : "selecttoend",\n
+\n
+    "C-l" : "recenterTopBottom",\n
+    "M-s" : "centerselection",\n
+    "M-g": "gotoline",\n
+    "C-x C-p": "selectall",\n
+    "C-Down": {command: "goorselect", args: ["gotopagedown","selectpagedown"]},\n
+    "C-Up": {command: "goorselect", args: ["gotopageup","selectpageup"]},\n
+    "PageDown|C-v": {command: "goorselect", args: ["gotopagedown","selectpagedown"]},\n
+    "PageUp|M-v": {command: "goorselect", args: ["gotopageup","selectpageup"]},\n
+    "S-C-Down": "selectpagedown",\n
+    "S-C-Up": "selectpageup",\n
+\n
+    "C-s": "iSearch",\n
+    "C-r": "iSearchBackwards",\n
+\n
+    "M-C-s": "findnext",\n
+    "M-C-r": "findprevious",\n
+    "S-M-5": "replace",\n
+    "Backspace": "backspace",\n
+    "Delete|C-d": "del",\n
+    "Return|C-m": {command: "insertstring", args: "\\n"}, // "newline"\n
+    "C-o": "splitline",\n
+\n
+    "M-d|C-Delete": {command: "killWord", args: "right"},\n
+    "C-Backspace|M-Backspace|M-Delete": {command: "killWord", args: "left"},\n
+    "C-k": "killLine",\n
+\n
+    "C-y|S-Delete": "yank",\n
+    "M-y": "yankRotate",\n
+    "C-g": "keyboardQuit",\n
+\n
+    "C-w": "killRegion",\n
+    "M-w": "killRingSave",\n
+    "C-Space": "setMark",\n
+    "C-x C-x": "exchangePointAndMark",\n
+\n
+    "C-t": "transposeletters",\n
+    "M-u": "touppercase",    // Doesn\'t work\n
+    "M-l": "tolowercase",\n
+    "M-/": "autocomplete",   // Doesn\'t work\n
+    "C-u": "universalArgument",\n
+\n
+    "M-;": "togglecomment",\n
+\n
+    "C-/|C-x u|S-C--|C-z": "undo",\n
+    "S-C-/|S-C-x u|C--|S-C-z": "redo", //infinite undo?\n
+    "C-x r":  "selectRectangularRegion",\n
+    "M-x": {command: "focusCommandLine", args: "M-x "}\n
+};\n
+\n
+\n
+exports.handler.bindKeys(exports.emacsKeys);\n
+\n
+exports.handler.addCommands({\n
+    recenterTopBottom: function(editor) {\n
+        var renderer = editor.renderer;\n
+        var pos = renderer.$cursorLayer.getPixelPosition();\n
+        var h = renderer.$size.scrollerHeight - renderer.lineHeight;\n
+        var scrollTop = renderer.scrollTop;\n
+        if (Math.abs(pos.top - scrollTop) < 2) {\n
+            scrollTop = pos.top - h;\n
+        } else if (Math.abs(pos.top - scrollTop - h * 0.5) < 2) {\n
+            scrollTop = pos.top;\n
+        } else {\n
+            scrollTop = pos.top - h * 0.5;\n
+        }\n
+        editor.session.setScrollTop(scrollTop);\n
+    },\n
+    selectRectangularRegion:  function(editor) {\n
+        editor.multiSelect.toggleBlockSelection();\n
+    },\n
+    setMark:  {\n
+        exec: function(editor, args) {\n
+            if (args && args.count) {\n
+                var mark = editor.popEmacsMark();\n
+                mark && editor.selection.moveCursorToPosition(mark);\n
+                return;\n
+            }\n
+\n
+            var mark = editor.emacsMark(),\n
+                transientMarkModeActive = true;\n
+            if (transientMarkModeActive && (mark || !editor.selection.isEmpty())) {\n
+                editor.pushEmacsMark();\n
+                editor.clearSelection();\n
+                return;\n
+            }\n
+\n
+            if (mark) {\n
+                var cp = editor.getCursorPosition();\n
+                if (editor.selection.isEmpty() &&\n
+                    mark.row == cp.row && mark.column == cp.column) {\n
+                    editor.pushEmacsMark();\n
+                    return;\n
+                }\n
+            }\n
+            mark = editor.getCursorPosition();\n
+            editor.setEmacsMark(mark);\n
+            editor.selection.setSelectionAnchor(mark.row, mark.column);\n
+        },\n
+        readonly: true,\n
+        handlesCount: true,\n
+        multiSelectAction: "forEach"\n
+    },\n
+    exchangePointAndMark: {\n
+        exec: function(editor, args) {\n
+            var sel = editor.selection;\n
+            if (args.count) {\n
+                var pos = editor.getCursorPosition();\n
+                sel.clearSelection();\n
+                sel.moveCursorToPosition(editor.popEmacsMark());\n
+                editor.pushEmacsMark(pos);\n
+                return;\n
+            }\n
+            var lastMark = editor.getLastEmacsMark();\n
+            var range = sel.getRange();\n
+            if (range.isEmpty()) {\n
+                sel.selectToPosition(lastMark);\n
+                return;\n
+            }\n
+            sel.setSelectionRange(range, !sel.isBackwards());\n
+        },\n
+        readonly: true,\n
+        handlesCount: true,\n
+        multiSelectAction: "forEach"\n
+    },\n
+    killWord: {\n
+        exec: function(editor, dir) {\n
+            editor.clearSelection();\n
+            if (dir == "left")\n
+                editor.selection.selectWordLeft();\n
+            else\n
+                editor.selection.selectWordRight();\n
+\n
+            var range = editor.getSelectionRange();\n
+            var text = editor.session.getTextRange(range);\n
+            exports.killRing.add(text);\n
+\n
+            editor.session.remove(range);\n
+            editor.clearSelection();\n
+        },\n
+        multiSelectAction: "forEach"\n
+    },\n
+    killLine: function(editor) {\n
+        editor.pushEmacsMark(null);\n
+        var pos = editor.getCursorPosition();\n
+        if (pos.column == 0 &&\n
+            editor.session.doc.getLine(pos.row).length == 0) {\n
+            editor.selection.selectLine();\n
+        } else {\n
+            editor.clearSelection();\n
+            editor.selection.selectLineEnd();\n
+        }\n
+        var range = editor.getSelectionRange();\n
+        var text = editor.session.getTextRange(range);\n
+        exports.killRing.add(text);\n
+\n
+        editor.session.remove(range);\n
+        editor.clearSelection();\n
+    },\n
+    yank: function(editor) {\n
+        editor.onPaste(exports.killRing.get() || \'\');\n
+        editor.keyBinding.$data.lastCommand = "yank";\n
+    },\n
+    yankRotate: function(editor) {\n
+        if (editor.keyBinding.$data.lastCommand != "yank")\n
+            return;\n
+        editor.undo();\n
+        editor.onPaste(exports.killRing.rotate());\n
+        editor.keyBinding.$data.lastCommand = "yank";\n
+    },\n
+    killRegion: {\n
+        exec: function(editor) {\n
+            exports.killRing.add(editor.getCopyText());\n
+            editor.commands.byName.cut.exec(editor);\n
+        },\n
+        readonly: true,\n
+        multiSelectAction: "forEach"\n
+    },\n
+    killRingSave: {\n
+        exec: function(editor) {\n
+            exports.killRing.add(editor.getCopyText());\n
+            setTimeout(function() {\n
+                var sel = editor.selection,\n
+                    range = sel.getRange();\n
+                editor.pushEmacsMark(sel.isBackwards() ? range.end : range.start);\n
+                sel.clearSelection();\n
+            }, 0);\n
+        },\n
+        readonly: true\n
+    },\n
+    keyboardQuit: function(editor) {\n
+        editor.selection.clearSelection();\n
+        editor.setEmacsMark(null);\n
+    },\n
+    focusCommandLine: function(editor, arg) {\n
+        if (editor.showCommandLine)\n
+            editor.showCommandLine(arg);\n
+    }\n
+});\n
+\n
+exports.handler.addCommands(iSearchCommandModule.iSearchStartCommands);\n
+\n
+var commands = exports.handler.commands;\n
+commands.yank.isYank = true;\n
+commands.yankRotate.isYank = true;\n
+\n
+exports.killRing = {\n
+    $data: [],\n
+    add: function(str) {\n
+        str && this.$data.push(str);\n
+        if (this.$data.length > 30)\n
+            this.$data.shift();\n
+    },\n
+    get: function(n) {\n
+        n = n || 1;\n
+        return this.$data.slice(this.$data.length-n, this.$data.length).reverse().join(\'\\n\');\n
+    },\n
+    pop: function() {\n
+        if (this.$data.length > 1)\n
+            this.$data.pop();\n
+        return this.get();\n
+    },\n
+    rotate: function() {\n
+        this.$data.unshift(this.$data.pop());\n
+        return this.get();\n
+    }\n
+};\n
+\n
+});\n
+\n
+define(\'ace/incremental_search\', [\'require\', \'exports\', \'module\' , \'ace/lib/oop\', \'ace/range\', \'ace/search\', \'ace/search_highlight\', \'ace/commands/incremental_search_commands\', \'ace/lib/dom\', \'ace/commands/command_manager\', \'ace/editor\', \'ace/config\'], function(require, exports, module) {\n
+\n
+\n
+var oop = require("./lib/oop");\n
+var Range = require("./range").Range;\n
+var Search = require("./search").Search;\n
+var SearchHighlight = require("./search_highlight").SearchHighlight;\n
+var iSearchCommandModule = require("./commands/incremental_search_commands");\n
+var ISearchKbd = iSearchCommandModule.IncrementalSearchKeyboardHandler;\n
+function IncrementalSearch() {\n
+    this.$options = {wrap: false, skipCurrent: false};\n
+    this.$keyboardHandler = new ISearchKbd(this);\n
+}\n
+\n
+oop.inherits(IncrementalSearch, Search);\n
+\n
+;(function() {\n
+\n
+    this.activate = function(ed, backwards) {\n
+        this.$editor = ed;\n
+        this.$startPos = this.$currentPos = ed.getCursorPosition();\n
+        this.$options.needle = \'\';\n
+        this.$options.backwards = backwards;\n
+        ed.keyBinding.addKeyboardHandler(this.$keyboardHandler);\n
+        this.$mousedownHandler = ed.addEventListener(\'mousedown\', this.onMouseDown.bind(this));\n
+        this.selectionFix(ed);\n
+        this.statusMessage(true);\n
+    }\n
+\n
+    this.deactivate = function(reset) {\n
+        this.cancelSearch(reset);\n
+        this.$editor.keyBinding.removeKeyboardHandler(this.$keyboardHandler);\n
+        if (this.$mousedownHandler) {\n
+            this.$editor.removeEventListener(\'mousedown\', this.$mousedownHandler);\n
+            delete this.$mousedownHandler;\n
+        }\n
+        this.message(\'\');\n
+    }\n
+\n
+    this.selectionFix = function(editor) {\n
+        if (editor.selection.isEmpty() && !editor.session.$emacsMark) {\n
+            editor.clearSelection();\n
+        }\n
+    }\n
+\n
+    this.highlight = function(regexp) {\n
+        var sess = this.$editor.session,\n
+            hl = sess.$isearchHighlight = sess.$isearchHighlight || sess.addDynamicMarker(\n
+                new SearchHighlight(null, "ace_isearch-result", "text"));\n
+        hl.setRegexp(regexp);\n
+        sess._emit("changeBackMarker"); // force highlight layer redraw\n
+    }\n
+\n
+    this.cancelSearch = function(reset) {\n
+        var e = this.$editor;\n
+        this.$prevNeedle = this.$options.needle;\n
+        this.$options.needle = \'\';\n
+        if (reset) {\n
+            e.moveCursorToPosition(this.$startPos);\n
+            this.$currentPos = this.$startPos;\n
+        } else {\n
+            e.pushEmacsMark && e.pushEmacsMark(this.$startPos, false);\n
+        }\n
+        this.highlight(null);\n
+        return Range.fromPoints(this.$currentPos, this.$currentPos);\n
+    }\n
+\n
+    this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) {\n
+        if (!this.$editor) return null;\n
+        var options = this.$options;\n
+        if (needleUpdateFunc) {\n
+            options.needle = needleUpdateFunc.call(this, options.needle || \'\') || \'\';\n
+        }\n
+        if (options.needle.length === 0) {\n
+            this.statusMessage(true);\n
+            return this.cancelSearch(true);\n
+        };\n
+        options.start = this.$currentPos;\n
+        var session = this.$editor.session,\n
+            found = this.find(session);\n
+        if (found) {\n
+            if (options.backwards) found = Range.fromPoints(found.end, found.start);\n
+            this.$editor.moveCursorToPosition(found.end);\n
+            if (moveToNext) this.$currentPos = found.end;\n
+            this.highlight(options.re)\n
+        }\n
+\n
+        this.statusMessage(found);\n
+\n
+        return found;\n
+    }\n
+\n
+    this.addChar = function(c) {\n
+        return this.highlightAndFindWithNeedle(false, function(needle) {\n
+            return needle + c;\n
+        });\n
+    }\n
+\n
+    this.removeChar = function(c) {\n
+        return this.highlightAndFindWithNeedle(false, function(needle) {\n
+            return needle.length > 0 ? needle.substring(0, needle.length-1) : needle;\n
+        });\n
+    }\n
+\n
+    this.next = function(options) {\n
+        options = options || {};\n
+        this.$options.backwards = !!options.backwards;\n
+        this.$currentPos = this.$editor.getCursorPosition();\n
+        return this.highlightAndFindWithNeedle(true, function(needle) {\n
+            return options.useCurrentOrPrevSearch && needle.length === 0 ?\n
+                this.$prevNeedle || \'\' : needle;\n
+        });\n
+    }\n
+\n
+    this.onMouseDown = function(evt) {\n
+        this.deactivate();\n
+        return true;\n
+    }\n
+\n
+    this.statusMessage = function(found) {\n
+        var options = this.$options, msg = \'\';\n
+        msg += options.backwards ? \'reverse-\' : \'\';\n
+        msg += \'isearch: \' + options.needle;\n
+        msg += found ? \'\' : \' (not found)\';\n
+        this.message(msg);\n
+    }\n
+\n
+    this.message = function(msg) {\n
+        if (this.$editor.showCommandLine) {\n
+            this.$editor.showCommandLine(msg);\n
+            this.$editor.focus();\n
+        } else {\n
+            console.log(msg);\n
+        }\n
+    }\n
+\n
+}).call(IncrementalSearch.prototype);\n
+\n
+\n
+exports.IncrementalSearch = IncrementalSearch;\n
+\n
+var dom = require(\'./lib/dom\');\n
+dom.importCssString && dom.importCssString("\\\n
+.ace_marker-layer .ace_isearch-result {\\\n
+  position: absolute;\\\n
+  z-index: 6;\\\n
+  -moz-box-sizing: border-box;\\\n
+  -webkit-box-sizing: border-box;\\\n
+  box-sizing: border-box;\\\n
+}\\\n
+div.ace_isearch-result {\\\n
+  border-radius: 4px;\\\n
+  background-color: rgba(255, 200, 0, 0.5);\\\n
+  box-shadow: 0 0 4px rgb(255, 200, 0);\\\n
+}\\\n
+.ace_dark div.ace_isearch-result {\\\n
+  background-color: rgb(100, 110, 160);\\\n
+  box-shadow: 0 0 4px rgb(80, 90, 140);\\\n
+}", "incremental-search-highlighting");\n
+var commands = require("./commands/command_manager");\n
+(function() {\n
+    this.setupIncrementalSearch = function(editor, val) {\n
+        if (this.usesIncrementalSearch == val) return;\n
+        this.usesIncrementalSearch = val;\n
+        var iSearchCommands = iSearchCommandModule.iSearchStartCommands;\n
+        var method = val ? \'addCommands\' : \'removeCommands\';\n
+        this[method](iSearchCommands);\n
+    };\n
+}).call(commands.CommandManager.prototype);\n
+var Editor = require("./editor").Editor;\n
+require("./config").defineOptions(Editor.prototype, "editor", {\n
+    useIncrementalSearch: {\n
+        set: function(val) {\n
+            this.keyBinding.$handlers.forEach(function(handler) {\n
+                if (handler.setupIncrementalSearch) {\n
+                    handler.setupIncrementalSearch(this, val);\n
+                }\n
+            });\n
+            this._emit(\'incrementalSearchSettingChanged\', {isEnabled: val});\n
+        }\n
+    }\n
+});\n
+\n
+});\n
+\n
+define(\'ace/commands/incremental_search_commands\', [\'require\', \'exports\', \'module\' , \'ace/config\', \'ace/lib/oop\', \'ace/keyboard/hash_handler\', \'ace/commands/occur_commands\'], function(require, exports, module) {\n
+\n
+var config = require("../config");\n
+var oop = require("../lib/oop");\n
+var HashHandler = require("../keyboard/hash_handler").HashHandler;\n
+var occurStartCommand = require("./occur_commands").occurStartCommand;\n
+exports.iSearchStartCommands = [{\n
+    name: "iSearch",\n
+    bindKey: {win: "Ctrl-F", mac: "Command-F"},\n
+    exec: function(editor, options) {\n
+        config.loadModule(["core", "ace/incremental_search"], function(e) {\n
+            var iSearch = e.iSearch = e.iSearch || new e.IncrementalSearch();\n
+            iSearch.activate(editor, options.backwards);\n
+            if (options.jumpToFirstMatch) iSearch.next(options);\n
+        });\n
+    },\n
+    readOnly: true\n
+}, {\n
+    name: "iSearchBackwards",\n
+    exec: function(editor, jumpToNext) { editor.execCommand(\'iSearch\', {backwards: true}); },\n
+    readOnly: true\n
+}, {\n
+    name: "iSearchAndGo",\n
+    bindKey: {win: "Ctrl-K", mac: "Command-G"},\n
+    exec: function(editor, jumpToNext) { editor.execCommand(\'iSearch\', {jumpToFirstMatch: true, useCurrentOrPrevSearch: true}); },\n
+    readOnly: true\n
+}, {\n
+    name: "iSearchBackwardsAndGo",\n
+    bindKey: {win: "Ctrl-Shift-K", mac: "Command-Shift-G"},\n
+    exec: function(editor) { editor.execCommand(\'iSearch\', {jumpToFirstMatch: true, backwards: true, useCurrentOrPrevSearch: true}); },\n
+    readOnly: true\n
+}];\n
+exports.iSearchCommands = [{\n
+    name: "restartSearch",\n
+    bindKey: {win: "Ctrl-F", mac: "Command-F"},\n
+    exec: function(iSearch) {\n
+        iSearch.cancelSearch(true);\n
+    },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}, {\n
+    name: "searchForward",\n
+    bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"},\n
+    exec: function(iSearch, options) {\n
+        options.useCurrentOrPrevSearch = true;\n
+        iSearch.next(options);\n
+    },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}, {\n
+    name: "searchBackward",\n
+    bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"},\n
+    exec: function(iSearch, options) {\n
+        options.useCurrentOrPrevSearch = true;\n
+        options.backwards = true;\n
+        iSearch.next(options);\n
+    },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}, {\n
+    name: "extendSearchTerm",\n
+    exec: function(iSearch, string) {\n
+        iSearch.addChar(string);\n
+    },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}, {\n
+    name: "extendSearchTermSpace",\n
+    bindKey: "space",\n
+    exec: function(iSearch) { iSearch.addChar(\' \'); },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}, {\n
+    name: "shrinkSearchTerm",\n
+    bindKey: "backspace",\n
+    exec: function(iSearch) {\n
+        iSearch.removeChar();\n
+    },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}, {\n
+    name: \'confirmSearch\',\n
+    bindKey: \'return\',\n
+    exec: function(iSearch) { iSearch.deactivate(); },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}, {\n
+    name: \'cancelSearch\',\n
+    bindKey: \'esc|Ctrl-G\',\n
+    exec: function(iSearch) { iSearch.deactivate(true); },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}, {\n
+    name: \'occurisearch\',\n
+    bindKey: \'Ctrl-O\',\n
+    exec: function(iSearch) {\n
+        var options = oop.mixin({}, iSearch.$options);\n
+        iSearch.deactivate();\n
+        occurStartCommand.exec(iSearch.$editor, options);\n
+    },\n
+    readOnly: true,\n
+    isIncrementalSearchCommand: true\n
+}];\n
+\n
+function IncrementalSearchKeyboardHandler(iSearch) {\n
+    this.$iSearch = iSearch;\n
+}\n
+\n
+oop.inherits(IncrementalSearchKeyboardHandler, HashHandler);\n
+\n
+;(function() {\n
+\n
+    this.attach = function(editor) {\n
+        var iSearch = this.$iSearch;\n
+        HashHandler.call(this, exports.iSearchCommands, editor.commands.platform);\n
+        this.$commandExecHandler = editor.commands.addEventListener(\'exec\', function(e) {\n
+            if (!e.command.isIncrementalSearchCommand) return undefined;\n
+            e.stopPropagation();\n
+            e.preventDefault();\n
+            return e.command.exec(iSearch, e.args || {});\n
+        });\n
+    }\n
+\n
+    this.detach = function(editor) {\n
+        if (!this.$commandExecHandler) return;\n
+        editor.commands.removeEventListener(\'exec\', this.$commandExecHandler);\n
+        delete this.$commandExecHandler;\n
+    }\n
+\n
+    var handleKeyboard$super = this.handleKeyboard;\n
+    this.handleKeyboard = function(data, hashId, key, keyCode) {\n
+        var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);\n
+        if (cmd.command) { return cmd; }\n
+        if (hashId == -1) {\n
+            var extendCmd = this.commands.extendSearchTerm;\n
+            if (extendCmd) { return {command: extendCmd, args: key}; }\n
+        }\n
+        return {command: "null", passEvent: hashId == 0 || hashId == 4};\n
+    }\n
+\n
+}).call(IncrementalSearchKeyboardHandler.prototype);\n
+\n
+\n
+exports.IncrementalSearchKeyboardHandler = IncrementalSearchKeyboardHandler;\n
+\n
+});\n
+\n
+define(\'ace/commands/occur_commands\', [\'require\', \'exports\', \'module\' , \'ace/config\', \'ace/occur\', \'ace/keyboard/hash_handler\', \'ace/lib/oop\'], function(require, exports, module) {\n
+\n
+var config = require("../config"),\n
+    Occur = require("../occur").Occur;\n
+var occurStartCommand = {\n
+    name: "occur",\n
+    exec: function(editor, options) {\n
+        var alreadyInOccur = !!editor.session.$occur;\n
+        var occurSessionActive = new Occur().enter(editor, options);\n
+        if (occurSessionActive && !alreadyInOccur)\n
+            OccurKeyboardHandler.installIn(editor);\n
+    },\n
+    readOnly: true\n
+};\n
+\n
+var occurCommands = [{\n
+    name: "occurexit",\n
+    bindKey: \'esc|Ctrl-G\',\n
+    exec: function(editor) {\n
+        var occur = editor.session.$occur;\n
+        if (!occur) return;\n
+        occur.exit(editor, {});\n
+        if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor);\n
+    },\n
+    readOnly: true\n
+}, {\n
+    name: "occuraccept",\n
+    bindKey: \'enter\',\n
+    exec: function(editor) {\n
+        var occur = editor.session.$occur;\n
+        if (!occur) return;\n
+        occur.exit(editor, {translatePosition: true});\n
+        if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor);\n
+    },\n
+    readOnly: true\n
+}];\n
+\n
+var HashHandler = require("../keyboard/hash_handler").HashHandler;\n
+var oop = require("../lib/oop");\n
+\n
+\n
+function OccurKeyboardHandler() {}\n
+\n
+oop.inherits(OccurKeyboardHandler, HashHandler);\n
+\n
+;(function() {\n
+\n
+    this.isOccurHandler = true;\n
+\n
+    this.attach = function(editor) {\n
+        HashHandler.call(this, occurCommands, editor.commands.platform);\n
+        this.$editor = editor;\n
+    }\n
+\n
+    var handleKeyboard$super = this.handleKeyboard;\n
+    this.handleKeyboard = function(data, hashId, key, keyCode) {\n
+        var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);\n
+        return (cmd && cmd.command) ? cmd : undefined;\n
+    }\n
+\n
+}).call(OccurKeyboardHandler.prototype);\n
+\n
+OccurKeyboardHandler.installIn = function(editor) {\n
+    var handler = new this();\n
+    editor.keyBinding.addKeyboardHandler(handler);\n
+    editor.commands.addCommands(occurCommands);\n
+}\n
+\n
+OccurKeyboardHandler.uninstallFrom = function(editor) {\n
+    editor.commands.removeCommands(occurCommands);\n
+    var handler = editor.getKeyboardHandler();\n
+    if (handler.isOccurHandler)\n
+        editor.keyBinding.removeKeyboardHandler(handler);\n
+}\n
+\n
+exports.occurStartCommand = occurStartCommand;\n
+\n
+});\n
+\n
+define(\'ace/occur\', [\'require\', \'exports\', \'module\' , \'ace/lib/oop\', \'ace/range\', \'ace/search\', \'ace/edit_session\', \'ace/search_highlight\', \'ace/lib/dom\'], function(require, exports, module) {\n
+\n
+\n
+var oop = require("./lib/oop");\n
+var Range = require("./range").Range;\n
+var Search = require("./search").Search;\n
+var EditSession = require("./edit_session").EditSession;\n
+var SearchHighlight = require("./search_highlight").SearchHighlight;\n
+function Occur() {}\n
+\n
+oop.inherits(Occur, Search);\n
+\n
+(function() {\n
+    this.enter = function(editor, options) {\n
+        if (!options.needle) return false;\n
+        var pos = editor.getCursorPosition();\n
+        this.displayOccurContent(editor, options);\n
+        var translatedPos = this.originalToOccurPosition(editor.session, pos);\n
+        editor.moveCursorToPosition(translatedPos);\n
+        return true;\n
+    }\n
+    this.exit = function(editor, options) {\n
+        var pos = options.translatePosition && editor.getCursorPosition();\n
+        var translatedPos = pos && this.occurToOriginalPosition(editor.session, pos);\n
+        this.displayOriginalContent(editor);\n
+        if (translatedPos)\n
+            editor.moveCursorToPosition(translatedPos);\n
+        return true;\n
+    }\n
+\n
+    this.highlight = function(sess, regexp) {\n
+        var hl = sess.$occurHighlight = sess.$occurHighlight || sess.addDynamicMarker(\n
+                new SearchHighlight(null, "ace_occur-highlight", "text"));\n
+        hl.setRegexp(regexp);\n
+        sess._emit("changeBackMarker"); // force highlight layer redraw\n
+    }\n
+\n
+    this.displayOccurContent = function(editor, options) {\n
+        this.$originalSession = editor.session;\n
+        var found = this.matchingLines(editor.session, options);\n
+        var lines = found.map(function(foundLine) { return foundLine.content; });\n
+        var occurSession = new EditSession(lines.join(\'\\n\'));\n
+        occurSession.$occur = this;\n
+        occurSession.$occurMatchingLines = found;\n
+        editor.setSession(occurSession);\n
+        this.highlight(occurSession, options.re);\n
+        occurSession._emit(\'changeBackMarker\');\n
+    }\n
+\n
+    this.displayOriginalContent = function(editor) {\n
+        editor.setSession(this.$originalSession);\n
+    }\n
+    this.originalToOccurPosition = function(session, pos) {\n
+        var lines = session.$occurMatchingLines;\n
+        var nullPos = {row: 0, column: 0};\n
+        if (!lines) return nullPos;\n
+        for (var i = 0; i < lines.length; i++) {\n
+            if (lines[i].row === pos.row)\n
+                return {row: i, column: pos.column};\n
+        }\n
+        return nullPos;\n
+    }\n
+    this.occurToOriginalPosition = function(session, pos) {\n
+        var lines = session.$occurMatchingLines;\n
+        if (!lines || !lines[pos.row])\n
+            return pos;\n
+        return {row: lines[pos.row].row, column: pos.column};\n
+    }\n
+\n
+    this.matchingLines = function(session, options) {\n
+        options = oop.mixin({}, options);\n
+        if (!session || !options.needle) return [];\n
+        var search = new Search();\n
+        search.set(options);\n
+        return search.findAll(session).reduce(function(lines, range) {\n
+            var row = range.start.row;\n
+            var last = lines[lines.length-1];\n
+            return last && last.row === row ?\n
+                lines :\n
+                lines.concat({row: row, content: session.getLine(row)});\n
+        }, []);\n
+    }\n
+\n
+}).call(Occur.prototype);\n
+\n
+var dom = require(\'./lib/dom\');\n
+dom.importCssString(".ace_occur-highlight {\\n\\\n
+    border-radius: 4px;\\n\\\n
+    background-color: rgba(87, 255, 8, 0.25);\\n\\\n
+    position: absolute;\\n\\\n
+    z-index: 4;\\n\\\n
+    -moz-box-sizing: border-box;\\n\\\n
+    -webkit-box-sizing: border-box;\\n\\\n
+    box-sizing: border-box;\\n\\\n
+    box-shadow: 0 0 4px rgb(91, 255, 50);\\n\\\n
+}\\n\\\n
+.ace_dark .ace_occur-highlight {\\n\\\n
+    background-color: rgb(80, 140, 85);\\n\\\n
+    box-shadow: 0 0 4px rgb(60, 120, 70);\\n\\\n
+}\\n", "incremental-occur-highlighting");\n
+\n
+exports.Occur = Occur;\n
+\n
+});\n
+
+
+]]></string> </value>
+        </item>
+        <item>
+            <key> <string>precondition</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>size</string> </key>
+            <value> <int>36738</int> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string>keybinding-emacs.js</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/keybinding-vim.js.xml b/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/keybinding-vim.js.xml
new file mode 100644
index 0000000000..db5dbe46c1
--- /dev/null
+++ b/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace/keybinding-vim.js.xml
@@ -0,0 +1,1756 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="File" module="OFS.Image"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_EtagSupport__etag</string> </key>
+            <value> <string>ts76363589.24</string> </value>
+        </item>
+        <item>
+            <key> <string>__name__</string> </key>
+            <value> <string>keybinding-vim.js</string> </value>
+        </item>
+        <item>
+            <key> <string>content_type</string> </key>
+            <value> <string>application/javascript</string> </value>
+        </item>
+        <item>
+            <key> <string>data</string> </key>
+            <value> <string encoding="cdata"><![CDATA[
+
+/* ***** BEGIN LICENSE BLOCK *****\n
+ * Distributed under the BSD license:\n
+ *\n
+ * Copyright (c) 2010, Ajax.org B.V.\n
+ * All rights reserved.\n
+ * \n
+ * Redistribution and use in source and binary forms, with or without\n
+ * modification, are permitted provided that the following conditions are met:\n
+ *     * Redistributions of source code must retain the above copyright\n
+ *       notice, this list of conditions and the following disclaimer.\n
+ *     * Redistributions in binary form must reproduce the above copyright\n
+ *       notice, this list of conditions and the following disclaimer in the\n
+ *       documentation and/or other materials provided with the distribution.\n
+ *     * Neither the name of Ajax.org B.V. nor the\n
+ *       names of its contributors may be used to endorse or promote products\n
+ *       derived from this software without specific prior written permission.\n
+ * \n
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\n
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY\n
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n
+ *\n
+ * ***** END LICENSE BLOCK ***** */\n
+\n
+define(\'ace/keyboard/vim\', [\'require\', \'exports\', \'module\' , \'ace/keyboard/vim/commands\', \'ace/keyboard/vim/maps/util\', \'ace/lib/useragent\'], function(require, exports, module) {\n
+\n
+\n
+var cmds = require("./vim/commands");\n
+var coreCommands = cmds.coreCommands;\n
+var util = require("./vim/maps/util");\n
+var useragent = require("../lib/useragent");\n
+\n
+var startCommands = {\n
+    "i": {\n
+        command: coreCommands.start\n
+    },\n
+    "I": {\n
+        command: coreCommands.startBeginning\n
+    },\n
+    "a": {\n
+        command: coreCommands.append\n
+    },\n
+    "A": {\n
+        command: coreCommands.appendEnd\n
+    },\n
+    "ctrl-f": {\n
+        command: "gotopagedown"\n
+    },\n
+    "ctrl-b": {\n
+        command: "gotopageup"\n
+    }\n
+};\n
+\n
+exports.handler = {\n
+\t$id: "ace/keyboard/vim",\n
+    handleMacRepeat: function(data, hashId, key) {\n
+        if (hashId == -1) {\n
+            data.inputChar = key;\n
+            data.lastEvent = "input";\n
+        } else if (data.inputChar && data.$lastHash == hashId && data.$lastKey == key) {\n
+            if (data.lastEvent == "input") {\n
+                data.lastEvent = "input1";\n
+            } else if (data.lastEvent == "input1") {\n
+                return true;\n
+            }\n
+        } else {\n
+            data.$lastHash = hashId;\n
+            data.$lastKey = key;\n
+            data.lastEvent = "keypress";\n
+        }\n
+    },\n
+\n
+    handleKeyboard: function(data, hashId, key, keyCode, e) {\n
+        if (hashId != 0 && (key == "" || key == "\\x00"))\n
+            return null;\n
+        \n
+        var editor = data.editor;\n
+        \n
+        if (hashId == 1)\n
+            key = "ctrl-" + key;\n
+        if (key == "ctrl-c") {\n
+            if (!useragent.isMac && editor.getCopyText()) {\n
+                editor.once("copy", function() {\n
+                    if (data.state == "start")\n
+                        coreCommands.stop.exec(editor);\n
+                    else\n
+                        editor.selection.clearSelection();\n
+                });\n
+                return {command: "null", passEvent: true};\n
+            }\n
+            return {command: coreCommands.stop};            \n
+        } else if ((key == "esc" && hashId == 0) || key == "ctrl-[") {\n
+            return {command: coreCommands.stop};\n
+        } else if (data.state == "start") {\n
+            if (useragent.isMac && this.handleMacRepeat(data, hashId, key)) {\n
+                hashId = -1;\n
+                key = data.inputChar;\n
+            }\n
+            \n
+            if (hashId == -1 || hashId == 1 || hashId == 0 && key.length > 1) {\n
+                if (cmds.inputBuffer.idle && startCommands[key])\n
+                    return startCommands[key];\n
+                cmds.inputBuffer.push(editor, key);\n
+                return {command: "null", passEvent: false}; \n
+            } // if no modifier || shift: wait for input.\n
+            else if (key.length == 1 && (hashId == 0 || hashId == 4)) {\n
+                return {command: "null", passEvent: true};\n
+            } else if (key == "esc" && hashId == 0) {\n
+                return {command: coreCommands.stop};\n
+            }\n
+        } else {\n
+            if (key == "ctrl-w") {\n
+                return {command: "removewordleft"};\n
+            }\n
+        }\n
+    },\n
+\n
+    attach: function(editor) {\n
+        editor.on("click", exports.onCursorMove);\n
+        if (util.currentMode !== "insert")\n
+            cmds.coreCommands.stop.exec(editor);\n
+        editor.$vimModeHandler = this;\n
+    },\n
+\n
+    detach: function(editor) {\n
+        editor.removeListener("click", exports.onCursorMove);\n
+        util.noMode(editor);\n
+        util.currentMode = "normal";\n
+    },\n
+\n
+    actions: cmds.actions,\n
+    getStatusText: function() {\n
+        if (util.currentMode == "insert")\n
+            return "INSERT";\n
+        if (util.onVisualMode)\n
+            return (util.onVisualLineMode ? "VISUAL LINE " : "VISUAL ") + cmds.inputBuffer.status;\n
+        return cmds.inputBuffer.status;\n
+    }\n
+};\n
+\n
+\n
+exports.onCursorMove = function(e) {\n
+    cmds.onCursorMove(e.editor, e);\n
+    exports.onCursorMove.scheduled = false;\n
+};\n
+\n
+});\n
+ \n
+define(\'ace/keyboard/vim/commands\', [\'require\', \'exports\', \'module\' , \'ace/lib/lang\', \'ace/keyboard/vim/maps/util\', \'ace/keyboard/vim/maps/motions\', \'ace/keyboard/vim/maps/operators\', \'ace/keyboard/vim/maps/aliases\', \'ace/keyboard/vim/registers\'], function(require, exports, module) {\n
+\n
+"never use strict";\n
+\n
+var lang = require("../../lib/lang");\n
+var util = require("./maps/util");\n
+var motions = require("./maps/motions");\n
+var operators = require("./maps/operators");\n
+var alias = require("./maps/aliases");\n
+var registers = require("./registers");\n
+\n
+var NUMBER = 1;\n
+var OPERATOR = 2;\n
+var MOTION = 3;\n
+var ACTION = 4;\n
+var HMARGIN = 8; // Minimum amount of line separation between margins;\n
+\n
+var repeat = function repeat(fn, count, args) {\n
+    while (0 < count--)\n
+        fn.apply(this, args);\n
+};\n
+\n
+var ensureScrollMargin = function(editor) {\n
+    var renderer = editor.renderer;\n
+    var pos = renderer.$cursorLayer.getPixelPosition();\n
+\n
+    var top = pos.top;\n
+\n
+    var margin = HMARGIN * renderer.layerConfig.lineHeight;\n
+    if (2 * margin > renderer.$size.scrollerHeight)\n
+        margin = renderer.$size.scrollerHeight / 2;\n
+\n
+    if (renderer.scrollTop > top - margin) {\n
+        renderer.session.setScrollTop(top - margin);\n
+    }\n
+\n
+    if (renderer.scrollTop + renderer.$size.scrollerHeight < top + margin + renderer.lineHeight) {\n
+        renderer.session.setScrollTop(top + margin + renderer.lineHeight - renderer.$size.scrollerHeight);\n
+    }\n
+};\n
+\n
+var actions = exports.actions = {\n
+    "z": {\n
+        param: true,\n
+        fn: function(editor, range, count, param) {\n
+            switch (param) {\n
+                case "z":\n
+                    editor.renderer.alignCursor(null, 0.5);\n
+                    break;\n
+                case "t":\n
+                    editor.renderer.alignCursor(null, 0);\n
+                    break;\n
+                case "b":\n
+                    editor.renderer.alignCursor(null, 1);\n
+                    break;\n
+            }\n
+        }\n
+    },\n
+    "r": {\n
+        param: true,\n
+        fn: function(editor, range, count, param) {\n
+            if (param && param.length) {\n
+                if (param.length > 1)\n
+                    param = param == "return" ? "\\n" : param == "tab" ? "\\t" : param;\n
+                repeat(function() { editor.insert(param); }, count || 1);\n
+                editor.navigateLeft();\n
+            }\n
+        }\n
+    },\n
+    "R": {\n
+        fn: function(editor, range, count, param) {\n
+            util.insertMode(editor);\n
+            editor.setOverwrite(true);\n
+        }\n
+    },\n
+    "~": {\n
+        fn: function(editor, range, count) {\n
+            repeat(function() {\n
+                var range = editor.selection.getRange();\n
+                if (range.isEmpty())\n
+                    range.end.column++;\n
+                var text = editor.session.getTextRange(range);\n
+                var toggled = text.toUpperCase();\n
+                if (toggled == text)\n
+                    editor.navigateRight();\n
+                else\n
+                    editor.session.replace(range, toggled);\n
+            }, count || 1);\n
+        }\n
+    },\n
+    "*": {\n
+        fn: function(editor, range, count, param) {\n
+            editor.selection.selectWord();\n
+            editor.findNext();\n
+            ensureScrollMargin(editor);\n
+            var r = editor.selection.getRange();\n
+            editor.selection.setSelectionRange(r, true);\n
+        }\n
+    },\n
+    "#": {\n
+        fn: function(editor, range, count, param) {\n
+            editor.selection.selectWord();\n
+            editor.findPrevious();\n
+            ensureScrollMargin(editor);\n
+            var r = editor.selection.getRange();\n
+            editor.selection.setSelectionRange(r, true);\n
+        }\n
+    },\n
+    "m": {\n
+        param: true,\n
+        fn: function(editor, range, count, param) {\n
+            var s =  editor.session;\n
+            var markers = s.vimMarkers || (s.vimMarkers = {});\n
+            var c = editor.getCursorPosition();\n
+            if (!markers[param]) {\n
+                markers[param] = editor.session.doc.createAnchor(c);\n
+            }\n
+            markers[param].setPosition(c.row, c.column, true);\n
+        }\n
+    },\n
+    "n": {\n
+        fn: function(editor, range, count, param) {\n
+            var options = editor.getLastSearchOptions();\n
+            options.backwards = false;\n
+\n
+            editor.selection.moveCursorRight();\n
+            editor.selection.clearSelection();\n
+            editor.findNext(options);\n
+\n
+            ensureScrollMargin(editor);\n
+            var r = editor.selection.getRange();\n
+            r.end.row = r.start.row;\n
+            r.end.column = r.start.column;\n
+            editor.selection.setSelectionRange(r, true);\n
+        }\n
+    },\n
+    "N": {\n
+        fn: function(editor, range, count, param) {\n
+            var options = editor.getLastSearchOptions();\n
+            options.backwards = true;\n
+\n
+            editor.findPrevious(options);\n
+            ensureScrollMargin(editor);\n
+            var r = editor.selection.getRange();\n
+            r.end.row = r.start.row;\n
+            r.end.column = r.start.column;\n
+            editor.selection.setSelectionRange(r, true);\n
+        }\n
+    },\n
+    "v": {\n
+        fn: function(editor, range, count, param) {\n
+            editor.selection.selectRight();\n
+            util.visualMode(editor, false);\n
+        },\n
+        acceptsMotion: true\n
+    },\n
+    "V": {\n
+        fn: function(editor, range, count, param) {\n
+            var row = editor.getCursorPosition().row;\n
+            editor.selection.clearSelection();\n
+            editor.selection.moveCursorTo(row, 0);\n
+            editor.selection.selectLineEnd();\n
+            editor.selection.visualLineStart = row;\n
+\n
+            util.visualMode(editor, true);\n
+        },\n
+        acceptsMotion: true\n
+    },\n
+    "Y": {\n
+        fn: function(editor, range, count, param) {\n
+            util.copyLine(editor);\n
+        }\n
+    },\n
+    "p": {\n
+        fn: function(editor, range, count, param) {\n
+            var defaultReg = registers._default;\n
+\n
+            editor.setOverwrite(false);\n
+            if (defaultReg.isLine) {\n
+                var pos = editor.getCursorPosition();\n
+                pos.column = editor.session.getLine(pos.row).length;\n
+                var text = lang.stringRepeat("\\n" + defaultReg.text, count || 1);\n
+                editor.session.insert(pos, text);\n
+                editor.moveCursorTo(pos.row + 1, 0);\n
+            }\n
+            else {\n
+                editor.navigateRight();\n
+                editor.insert(lang.stringRepeat(defaultReg.text, count || 1));\n
+                editor.navigateLeft();\n
+            }\n
+            editor.setOverwrite(true);\n
+            editor.selection.clearSelection();\n
+        }\n
+    },\n
+    "P": {\n
+        fn: function(editor, range, count, param) {\n
+            var defaultReg = registers._default;\n
+            editor.setOverwrite(false);\n
+\n
+            if (defaultReg.isLine) {\n
+                var pos = editor.getCursorPosition();\n
+                pos.column = 0;\n
+                var text = lang.stringRepeat(defaultReg.text + "\\n", count || 1);\n
+                editor.session.insert(pos, text);\n
+                editor.moveCursorToPosition(pos);\n
+            }\n
+            else {\n
+                editor.insert(lang.stringRepeat(defaultReg.text, count || 1));\n
+            }\n
+            editor.setOverwrite(true);\n
+            editor.selection.clearSelection();\n
+        }\n
+    },\n
+    "J": {\n
+        fn: function(editor, range, count, param) {\n
+            var session = editor.session;\n
+            range = editor.getSelectionRange();\n
+            var pos = {row: range.start.row, column: range.start.column};\n
+            count = count || range.end.row - range.start.row;\n
+            var maxRow = Math.min(pos.row + (count || 1), session.getLength() - 1);\n
+\n
+            range.start.column = session.getLine(pos.row).length;\n
+            range.end.column = session.getLine(maxRow).length;\n
+            range.end.row = maxRow;\n
+\n
+            var text = "";\n
+            for (var i = pos.row; i < maxRow; i++) {\n
+                var nextLine = session.getLine(i + 1);\n
+                text += " " + /^\\s*(.*)$/.exec(nextLine)[1] || "";\n
+            }\n
+\n
+            session.replace(range, text);\n
+            editor.moveCursorTo(pos.row, pos.column);\n
+        }\n
+    },\n
+    "u": {\n
+        fn: function(editor, range, count, param) {\n
+            count = parseInt(count || 1, 10);\n
+            for (var i = 0; i < count; i++) {\n
+                editor.undo();\n
+            }\n
+            editor.selection.clearSelection();\n
+        }\n
+    },\n
+    "ctrl-r": {\n
+        fn: function(editor, range, count, param) {\n
+            count = parseInt(count || 1, 10);\n
+            for (var i = 0; i < count; i++) {\n
+                editor.redo();\n
+            }\n
+            editor.selection.clearSelection();\n
+        }\n
+    },\n
+    ":": {\n
+        fn: function(editor, range, count, param) {\n
+            var val = ":";\n
+            if (count > 1)\n
+                val = ".,.+" + count + val;\n
+            if (editor.showCommandLine)\n
+                editor.showCommandLine(val);\n
+        }\n
+    },\n
+    "/": {\n
+        fn: function(editor, range, count, param) {\n
+            if (editor.showCommandLine)\n
+                editor.showCommandLine("/");\n
+        }\n
+    },\n
+    "?": {\n
+        fn: function(editor, range, count, param) {\n
+            if (editor.showCommandLine)\n
+                editor.showCommandLine("?");\n
+        }\n
+    },\n
+    ".": {\n
+        fn: function(editor, range, count, param) {\n
+            util.onInsertReplaySequence = inputBuffer.lastInsertCommands;\n
+            var previous = inputBuffer.previous;\n
+            if (previous) // If there is a previous action\n
+                inputBuffer.exec(editor, previous.action, previous.param);\n
+        }\n
+    },\n
+    "ctrl-x": {\n
+        fn: function(editor, range, count, param) {\n
+            editor.modifyNumber(-(count || 1));\n
+        }\n
+    },\n
+    "ctrl-a": {\n
+        fn: function(editor, range, count, param) {\n
+            editor.modifyNumber(count || 1);\n
+        }\n
+    }\n
+};\n
+\n
+var inputBuffer = exports.inputBuffer = {\n
+    accepting: [NUMBER, OPERATOR, MOTION, ACTION],\n
+    currentCmd: null,\n
+    currentCount: "",\n
+    status: "",\n
+    operator: null,\n
+    motion: null,\n
+\n
+    lastInsertCommands: [],\n
+\n
+    push: function(editor, ch, keyId) {\n
+        var status = this.status;\n
+        var isKeyHandled = true;\n
+        this.idle = false;\n
+        var wObj = this.waitingForParam;\n
+        if (/^numpad\\d+$/i.test(ch))\n
+            ch = ch.substr(6);\n
+            \n
+        if (wObj) {\n
+            this.exec(editor, wObj, ch);\n
+        }\n
+        else if (!(ch === "0" && !this.currentCount.length) &&\n
+            (/^\\d+$/.test(ch) && this.isAccepting(NUMBER))) {\n
+            this.currentCount += ch;\n
+            this.currentCmd = NUMBER;\n
+            this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];\n
+        }\n
+        else if (!this.operator && this.isAccepting(OPERATOR) && operators[ch]) {\n
+            this.operator = {\n
+                ch: ch,\n
+                count: this.getCount()\n
+            };\n
+            this.currentCmd = OPERATOR;\n
+            this.accepting = [NUMBER, MOTION, ACTION];\n
+            this.exec(editor, { operator: this.operator });\n
+        }\n
+        else if (motions[ch] && this.isAccepting(MOTION)) {\n
+            this.currentCmd = MOTION;\n
+\n
+            var ctx = {\n
+                operator: this.operator,\n
+                motion: {\n
+                    ch: ch,\n
+                    count: this.getCount()\n
+                }\n
+            };\n
+\n
+            if (motions[ch].param)\n
+                this.waitForParam(ctx);\n
+            else\n
+                this.exec(editor, ctx);\n
+        }\n
+        else if (alias[ch] && this.isAccepting(MOTION)) {\n
+            alias[ch].operator.count = this.getCount();\n
+            this.exec(editor, alias[ch]);\n
+        }\n
+        else if (actions[ch] && this.isAccepting(ACTION)) {\n
+            var actionObj = {\n
+                action: {\n
+                    fn: actions[ch].fn,\n
+                    count: this.getCount()\n
+                }\n
+            };\n
+\n
+            if (actions[ch].param) {\n
+                this.waitForParam(actionObj);\n
+            }\n
+            else {\n
+                this.exec(editor, actionObj);\n
+            }\n
+\n
+            if (actions[ch].acceptsMotion)\n
+                this.idle = false;\n
+        }\n
+        else if (this.operator) {\n
+            this.operator.count = this.getCount();\n
+            this.exec(editor, { operator: this.operator }, ch);\n
+        }\n
+        else {\n
+            isKeyHandled = ch.length == 1;\n
+            this.reset();\n
+        }\n
+        \n
+        if (this.waitingForParam || this.motion || this.operator) {\n
+            this.status += ch;\n
+        } else if (this.currentCount) {\n
+            this.status = this.currentCount;\n
+        } else if (this.status) {\n
+            this.status = "";\n
+        }\n
+        if (this.status != status)\n
+            editor._emit("changeStatus");\n
+        return isKeyHandled;\n
+    },\n
+\n
+    waitForParam: function(cmd) {\n
+        this.waitingForParam = cmd;\n
+    },\n
+\n
+    getCount: function() {\n
+        var count = this.currentCount;\n
+        this.currentCount = "";\n
+        return count && parseInt(count, 10);\n
+    },\n
+\n
+    exec: function(editor, action, param) {\n
+        var m = action.motion;\n
+        var o = action.operator;\n
+        var a = action.action;\n
+\n
+        if (!param)\n
+            param = action.param;\n
+\n
+        if (o) {\n
+            this.previous = {\n
+                action: action,\n
+                param: param\n
+            };\n
+        }\n
+\n
+        if (o && !editor.selection.isEmpty()) {\n
+            if (operators[o.ch].selFn) {\n
+                operators[o.ch].selFn(editor, editor.getSelectionRange(), o.count, param);\n
+                this.reset();\n
+            }\n
+            return;\n
+        }\n
+        else if (!m && !a && o && param) {\n
+            operators[o.ch].fn(editor, null, o.count, param);\n
+            this.reset();\n
+        }\n
+        else if (m) {\n
+            var run = function(fn) {\n
+                if (fn && typeof fn === "function") { // There should always be a motion\n
+                    if (m.count && !motionObj.handlesCount)\n
+                        repeat(fn, m.count, [editor, null, m.count, param]);\n
+                    else\n
+                        fn(editor, null, m.count, param);\n
+                }\n
+            };\n
+\n
+            var motionObj = motions[m.ch];\n
+            var selectable = motionObj.sel;\n
+\n
+            if (!o) {\n
+                if ((util.onVisualMode || util.onVisualLineMode) && selectable)\n
+                    run(motionObj.sel);\n
+                else\n
+                    run(motionObj.nav);\n
+            }\n
+            else if (selectable) {\n
+                repeat(function() {\n
+                    run(motionObj.sel);\n
+                    operators[o.ch].fn(editor, editor.getSelectionRange(), o.count, param);\n
+                }, o.count || 1);\n
+            }\n
+            this.reset();\n
+        }\n
+        else if (a) {\n
+            a.fn(editor, editor.getSelectionRange(), a.count, param);\n
+            this.reset();\n
+        }\n
+        handleCursorMove(editor);\n
+    },\n
+\n
+    isAccepting: function(type) {\n
+        return this.accepting.indexOf(type) !== -1;\n
+    },\n
+\n
+    reset: function() {\n
+        this.operator = null;\n
+        this.motion = null;\n
+        this.currentCount = "";\n
+        this.status = "";\n
+        this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];\n
+        this.idle = true;\n
+        this.waitingForParam = null;\n
+    }\n
+};\n
+\n
+function setPreviousCommand(fn) {\n
+    inputBuffer.previous = { action: { action: { fn: fn } } };\n
+}\n
+\n
+exports.coreCommands = {\n
+    start: {\n
+        exec: function start(editor) {\n
+            util.insertMode(editor);\n
+            setPreviousCommand(start);\n
+        }\n
+    },\n
+    startBeginning: {\n
+        exec: function startBeginning(editor) {\n
+            editor.navigateLineStart();\n
+            util.insertMode(editor);\n
+            setPreviousCommand(startBeginning);\n
+        }\n
+    },\n
+    stop: {\n
+        exec: function stop(editor) {\n
+            inputBuffer.reset();\n
+            util.onVisualMode = false;\n
+            util.onVisualLineMode = false;\n
+            inputBuffer.lastInsertCommands = util.normalMode(editor);\n
+        }\n
+    },\n
+    append: {\n
+        exec: function append(editor) {\n
+            var pos = editor.getCursorPosition();\n
+            var lineLen = editor.session.getLine(pos.row).length;\n
+            if (lineLen)\n
+                editor.navigateRight();\n
+            util.insertMode(editor);\n
+            setPreviousCommand(append);\n
+        }\n
+    },\n
+    appendEnd: {\n
+        exec: function appendEnd(editor) {\n
+            editor.navigateLineEnd();\n
+            util.insertMode(editor);\n
+            setPreviousCommand(appendEnd);\n
+        }\n
+    }\n
+};\n
+\n
+var handleCursorMove = exports.onCursorMove = function(editor, e) {\n
+    if (util.currentMode === \'insert\' || handleCursorMove.running)\n
+        return;\n
+    else if(!editor.selection.isEmpty()) {\n
+        handleCursorMove.running = true;\n
+        if (util.onVisualLineMode) {\n
+            var originRow = editor.selection.visualLineStart;\n
+            var cursorRow = editor.getCursorPosition().row;\n
+            if(originRow <= cursorRow) {\n
+                var endLine = editor.session.getLine(cursorRow);\n
+                editor.selection.clearSelection();\n
+                editor.selection.moveCursorTo(originRow, 0);\n
+                editor.selection.selectTo(cursorRow, endLine.length);\n
+            } else {\n
+                var endLine = editor.session.getLine(originRow);\n
+                editor.selection.clearSelection();\n
+                editor.selection.moveCursorTo(originRow, endLine.length);\n
+                editor.selection.selectTo(cursorRow, 0);\n
+            }\n
+        }\n
+        handleCursorMove.running = false;\n
+        return;\n
+    }\n
+    else {\n
+        if (e && (util.onVisualLineMode || util.onVisualMode)) {\n
+            editor.selection.clearSelection();\n
+            util.normalMode(editor);\n
+        }\n
+\n
+        handleCursorMove.running = true;\n
+        var pos = editor.getCursorPosition();\n
+        var lineLen = editor.session.getLine(pos.row).length;\n
+\n
+        if (lineLen && pos.column === lineLen)\n
+            editor.navigateLeft();\n
+        handleCursorMove.running = false;\n
+    }\n
+};\n
+});\n
+define(\'ace/keyboard/vim/maps/util\', [\'require\', \'exports\', \'module\' , \'ace/keyboard/vim/registers\', \'ace/lib/dom\'], function(require, exports, module) {\n
+var registers = require("../registers");\n
+\n
+var dom = require("../../../lib/dom");\n
+dom.importCssString(\'.insert-mode .ace_cursor{\\\n
+    border-left: 2px solid #333333;\\\n
+}\\\n
+.ace_dark.insert-mode .ace_cursor{\\\n
+    border-left: 2px solid #eeeeee;\\\n
+}\\\n
+.normal-mode .ace_cursor{\\\n
+    border: 0!important;\\\n
+    background-color: red;\\\n
+    opacity: 0.5;\\\n
+}\', \'vimMode\');\n
+\n
+module.exports = {\n
+    onVisualMode: false,\n
+    onVisualLineMode: false,\n
+    currentMode: \'normal\',\n
+    noMode: function(editor) {\n
+        editor.unsetStyle(\'insert-mode\');\n
+        editor.unsetStyle(\'normal-mode\');\n
+        if (editor.commands.recording)\n
+            editor.commands.toggleRecording(editor);\n
+        editor.setOverwrite(false);\n
+    },\n
+    insertMode: function(editor) {\n
+        this.currentMode = \'insert\';\n
+        editor.setStyle(\'insert-mode\');\n
+        editor.unsetStyle(\'normal-mode\');\n
+\n
+        editor.setOverwrite(false);\n
+        editor.keyBinding.$data.buffer = "";\n
+        editor.keyBinding.$data.state = "insertMode";\n
+        this.onVisualMode = false;\n
+        this.onVisualLineMode = false;\n
+        if(this.onInsertReplaySequence) {\n
+            editor.commands.macro = this.onInsertReplaySequence;\n
+            editor.commands.replay(editor);\n
+            this.onInsertReplaySequence = null;\n
+            this.normalMode(editor);\n
+        } else {\n
+            editor._emit("changeStatus");\n
+            if(!editor.commands.recording)\n
+                editor.commands.toggleRecording(editor);\n
+        }\n
+    },\n
+    normalMode: function(editor) {\n
+        this.currentMode = \'normal\';\n
+\n
+        editor.unsetStyle(\'insert-mode\');\n
+        editor.setStyle(\'normal-mode\');\n
+        editor.clearSelection();\n
+\n
+        var pos;\n
+        if (!editor.getOverwrite()) {\n
+            pos = editor.getCursorPosition();\n
+            if (pos.column > 0)\n
+                editor.navigateLeft();\n
+        }\n
+\n
+        editor.setOverwrite(true);\n
+        editor.keyBinding.$data.buffer = "";\n
+        editor.keyBinding.$data.state = "start";\n
+        this.onVisualMode = false;\n
+        this.onVisualLineMode = false;\n
+        editor._emit("changeStatus");\n
+        if (editor.commands.recording) {\n
+            editor.commands.toggleRecording(editor);\n
+            return editor.commands.macro;\n
+        }\n
+        else {\n
+            return [];\n
+        }\n
+    },\n
+    visualMode: function(editor, lineMode) {\n
+        if (\n
+            (this.onVisualLineMode && lineMode)\n
+            || (this.onVisualMode && !lineMode)\n
+        ) {\n
+            this.normalMode(editor);\n
+            return;\n
+        }\n
+\n
+        editor.setStyle(\'insert-mode\');\n
+        editor.unsetStyle(\'normal-mode\');\n
+\n
+        editor._emit("changeStatus");\n
+        if (lineMode) {\n
+            this.onVisualLineMode = true;\n
+        } else {\n
+            this.onVisualMode = true;\n
+            this.onVisualLineMode = false;\n
+        }\n
+    },\n
+    getRightNthChar: function(editor, cursor, ch, n) {\n
+        var line = editor.getSession().getLine(cursor.row);\n
+        var matches = line.substr(cursor.column + 1).split(ch);\n
+\n
+        return n < matches.length ? matches.slice(0, n).join(ch).length : null;\n
+    },\n
+    getLeftNthChar: function(editor, cursor, ch, n) {\n
+        var line = editor.getSession().getLine(cursor.row);\n
+        var matches = line.substr(0, cursor.column).split(ch);\n
+\n
+        return n < matches.length ? matches.slice(-1 * n).join(ch).length : null;\n
+    },\n
+    toRealChar: function(ch) {\n
+        if (ch.length === 1)\n
+            return ch;\n
+\n
+        if (/^shift-./.test(ch))\n
+            return ch[ch.length - 1].toUpperCase();\n
+        else\n
+            return "";\n
+    },\n
+    copyLine: function(editor) {\n
+        var pos = editor.getCursorPosition();\n
+        editor.selection.clearSelection();\n
+        editor.moveCursorTo(pos.row, pos.column);\n
+        editor.selection.selectLine();\n
+        registers._default.isLine = true;\n
+        registers._default.text = editor.getCopyText().replace(/\\n$/, "");\n
+        editor.selection.clearSelection();\n
+        editor.moveCursorTo(pos.row, pos.column);\n
+    }\n
+};\n
+});\n
+\n
+define(\'ace/keyboard/vim/registers\', [\'require\', \'exports\', \'module\' ], function(require, exports, module) {\n
+\n
+"never use strict";\n
+\n
+module.exports = {\n
+    _default: {\n
+        text: "",\n
+        isLine: false\n
+    }\n
+};\n
+\n
+});\n
+\n
+\n
+define(\'ace/keyboard/vim/maps/motions\', [\'require\', \'exports\', \'module\' , \'ace/keyboard/vim/maps/util\', \'ace/search\', \'ace/range\'], function(require, exports, module) {\n
+\n
+\n
+var util = require("./util");\n
+\n
+var keepScrollPosition = function(editor, fn) {\n
+    var scrollTopRow = editor.renderer.getScrollTopRow();\n
+    var initialRow = editor.getCursorPosition().row;\n
+    var diff = initialRow - scrollTopRow;\n
+    fn && fn.call(editor);\n
+    editor.renderer.scrollToRow(editor.getCursorPosition().row - diff);\n
+};\n
+\n
+function Motion(m) {\n
+    if (typeof m == "function") {\n
+        var getPos = m;\n
+        m = this;\n
+    } else {\n
+        var getPos = m.getPos;\n
+    }\n
+    m.nav = function(editor, range, count, param) {\n
+        var a = getPos(editor, range, count, param, false);\n
+        if (!a)\n
+            return;\n
+        editor.clearSelection();\n
+        editor.moveCursorTo(a.row, a.column);\n
+    };\n
+    m.sel = function(editor, range, count, param) {\n
+        var a = getPos(editor, range, count, param, true);\n
+        if (!a)\n
+            return;\n
+        editor.selection.selectTo(a.row, a.column);\n
+    };\n
+    return m;\n
+}\n
+\n
+var nonWordRe = /[\\s.\\/\\\\()\\"\'-:,.;<>~!@#$%^&*|+=\\[\\]{}`~?]/;\n
+var wordSeparatorRe = /[.\\/\\\\()\\"\'-:,.;<>~!@#$%^&*|+=\\[\\]{}`~?]/;\n
+var whiteRe = /\\s/;\n
+var StringStream = function(editor, cursor) {\n
+    var sel = editor.selection;\n
+    this.range = sel.getRange();\n
+    cursor = cursor || sel.selectionLead;\n
+    this.row = cursor.row;\n
+    this.col = cursor.column;\n
+    var line = editor.session.getLine(this.row);\n
+    var maxRow = editor.session.getLength();\n
+    this.ch = line[this.col] || \'\\n\';\n
+    this.skippedLines = 0;\n
+\n
+    this.next = function() {\n
+        this.ch = line[++this.col] || this.handleNewLine(1);\n
+        return this.ch;\n
+    };\n
+    this.prev = function() {\n
+        this.ch = line[--this.col] || this.handleNewLine(-1);\n
+        return this.ch;\n
+    };\n
+    this.peek = function(dir) {\n
+        var ch = line[this.col + dir];\n
+        if (ch)\n
+            return ch;\n
+        if (dir == -1)\n
+            return \'\\n\';\n
+        if (this.col == line.length - 1)\n
+            return \'\\n\';\n
+        return editor.session.getLine(this.row + 1)[0] || \'\\n\';\n
+    };\n
+\n
+    this.handleNewLine = function(dir) {\n
+        if (dir == 1){\n
+            if (this.col == line.length)\n
+                return \'\\n\';\n
+            if (this.row == maxRow - 1)\n
+                return \'\';\n
+            this.col = 0;\n
+            this.row ++;\n
+            line = editor.session.getLine(this.row);\n
+            this.skippedLines++;\n
+            return line[0] || \'\\n\';\n
+        }\n
+        if (dir == -1) {\n
+            if (this.row === 0)\n
+                return \'\';\n
+            this.row --;\n
+            line = editor.session.getLine(this.row);\n
+            this.col = line.length;\n
+            this.skippedLines--;\n
+            return \'\\n\';\n
+        }\n
+    };\n
+    this.debug = function() {\n
+        console.log(line.substring(0, this.col)+\'|\'+this.ch+\'\\\'\'+this.col+\'\\\'\'+line.substr(this.col+1));\n
+    };\n
+};\n
+\n
+var Search = require("../../../search").Search;\n
+var search = new Search();\n
+\n
+function find(editor, needle, dir) {\n
+    search.$options.needle = needle;\n
+    search.$options.backwards = dir == -1;\n
+    return search.find(editor.session);\n
+}\n
+\n
+var Range = require("../../../range").Range;\n
+\n
+var LAST_SEARCH_MOTION = {};\n
+\n
+module.exports = {\n
+    "w": new Motion(function(editor) {\n
+        var str = new StringStream(editor);\n
+\n
+        if (str.ch && wordSeparatorRe.test(str.ch)) {\n
+            while (str.ch && wordSeparatorRe.test(str.ch))\n
+                str.next();\n
+        } else {\n
+            while (str.ch && !nonWordRe.test(str.ch))\n
+                str.next();\n
+        }\n
+        while (str.ch && whiteRe.test(str.ch) && str.skippedLines < 2)\n
+            str.next();\n
+\n
+        str.skippedLines == 2 && str.prev();\n
+        return {column: str.col, row: str.row};\n
+    }),\n
+    "W": new Motion(function(editor) {\n
+        var str = new StringStream(editor);\n
+        while(str.ch && !(whiteRe.test(str.ch) && !whiteRe.test(str.peek(1))) && str.skippedLines < 2)\n
+            str.next();\n
+        if (str.skippedLines == 2)\n
+            str.prev();\n
+        else\n
+            str.next();\n
+\n
+        return {column: str.col, row: str.row};\n
+    }),\n
+    "b": new Motion(function(editor) {\n
+        var str = new StringStream(editor);\n
+\n
+        str.prev();\n
+        while (str.ch && whiteRe.test(str.ch) && str.skippedLines > -2)\n
+            str.prev();\n
+\n
+        if (str.ch && wordSeparatorRe.test(str.ch)) {\n
+            while (str.ch && wordSeparatorRe.test(str.ch))\n
+                str.prev();\n
+        } else {\n
+            while (str.ch && !nonWordRe.test(str.ch))\n
+                str.prev();\n
+        }\n
+        str.ch && str.next();\n
+        return {column: str.col, row: str.row};\n
+    }),\n
+    "B": new Motion(function(editor) {\n
+        var str = new StringStream(editor);\n
+        str.prev();\n
+        while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(-1))) && str.skippedLines > -2)\n
+            str.prev();\n
+\n
+        if (str.skippedLines == -2)\n
+            str.next();\n
+\n
+        return {column: str.col, row: str.row};\n
+    }),\n
+    "e": new Motion(function(editor) {\n
+        var str = new StringStream(editor);\n
+\n
+        str.next();\n
+        while (str.ch && whiteRe.test(str.ch))\n
+            str.next();\n
+\n
+        if (str.ch && wordSeparatorRe.test(str.ch)) {\n
+            while (str.ch && wordSeparatorRe.test(str.ch))\n
+                str.next();\n
+        } else {\n
+            while (str.ch && !nonWordRe.test(str.ch))\n
+                str.next();\n
+        }\n
+        str.ch && str.prev();\n
+        return {column: str.col, row: str.row};\n
+    }),\n
+    "E": new Motion(function(editor) {\n
+        var str = new StringStream(editor);\n
+        str.next();\n
+        while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(1))))\n
+            str.next();\n
+\n
+        return {column: str.col, row: str.row};\n
+    }),\n
+\n
+    "l": {\n
+        nav: function(editor) {\n
+            var pos = editor.getCursorPosition();\n
+            var col = pos.column;\n
+            var lineLen = editor.session.getLine(pos.row).length;\n
+            if (lineLen && col !== lineLen)\n
+                editor.navigateRight();\n
+        },\n
+        sel: function(editor) {\n
+            var pos = editor.getCursorPosition();\n
+            var col = pos.column;\n
+            var lineLen = editor.session.getLine(pos.row).length;\n
+            if (lineLen && col !== lineLen) //In selection mode you can select the newline\n
+                editor.selection.selectRight();\n
+        }\n
+    },\n
+    "h": {\n
+        nav: function(editor) {\n
+            var pos = editor.getCursorPosition();\n
+            if (pos.column > 0)\n
+                editor.navigateLeft();\n
+        },\n
+        sel: function(editor) {\n
+            var pos = editor.getCursorPosition();\n
+            if (pos.column > 0)\n
+                editor.selection.selectLeft();\n
+        }\n
+    },\n
+    "H": {\n
+        nav: function(editor) {\n
+            var row = editor.renderer.getScrollTopRow();\n
+            editor.moveCursorTo(row);\n
+        },\n
+        sel: function(editor) {\n
+            var row = editor.renderer.getScrollTopRow();\n
+            editor.selection.selectTo(row);\n
+        }\n
+    },\n
+    "M": {\n
+        nav: function(editor) {\n
+            var topRow = editor.renderer.getScrollTopRow();\n
+            var bottomRow = editor.renderer.getScrollBottomRow();\n
+            var row = topRow + ((bottomRow - topRow) / 2);\n
+            editor.moveCursorTo(row);\n
+        },\n
+        sel: function(editor) {\n
+            var topRow = editor.renderer.getScrollTopRow();\n
+            var bottomRow = editor.renderer.getScrollBottomRow();\n
+            var row = topRow + ((bottomRow - topRow) / 2);\n
+            editor.selection.selectTo(row);\n
+        }\n
+    },\n
+    "L": {\n
+        nav: function(editor) {\n
+            var row = editor.renderer.getScrollBottomRow();\n
+            editor.moveCursorTo(row);\n
+        },\n
+        sel: function(editor) {\n
+            var row = editor.renderer.getScrollBottomRow();\n
+            editor.selection.selectTo(row);\n
+        }\n
+    },\n
+    "k": {\n
+        nav: function(editor) {\n
+            editor.navigateUp();\n
+        },\n
+        sel: function(editor) {\n
+            editor.selection.selectUp();\n
+        }\n
+    },\n
+    "j": {\n
+        nav: function(editor) {\n
+            editor.navigateDown();\n
+        },\n
+        sel: function(editor) {\n
+            editor.selection.selectDown();\n
+        }\n
+    },\n
+\n
+    "i": {\n
+        param: true,\n
+        sel: function(editor, range, count, param) {\n
+            switch (param) {\n
+                case "w":\n
+                    editor.selection.selectWord();\n
+                    break;\n
+                case "W":\n
+                    editor.selection.selectAWord();\n
+                    break;\n
+                case "(":\n
+                case "{":\n
+                case "[":\n
+                    var cursor = editor.getCursorPosition();\n
+                    var end = editor.session.$findClosingBracket(param, cursor, /paren/);\n
+                    if (!end)\n
+                        return;\n
+                    var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/);\n
+                    if (!start)\n
+                        return;\n
+                    start.column ++;\n
+                    editor.selection.setSelectionRange(Range.fromPoints(start, end));\n
+                    break;\n
+                case "\'":\n
+                case \'"\':\n
+                case "/":\n
+                    var end = find(editor, param, 1);\n
+                    if (!end)\n
+                        return;\n
+                    var start = find(editor, param, -1);\n
+                    if (!start)\n
+                        return;\n
+                    editor.selection.setSelectionRange(Range.fromPoints(start.end, end.start));\n
+                    break;\n
+            }\n
+        }\n
+    },\n
+    "a": {\n
+        param: true,\n
+        sel: function(editor, range, count, param) {\n
+            switch (param) {\n
+                case "w":\n
+                    editor.selection.selectAWord();\n
+                    break;\n
+                case "W":\n
+                    editor.selection.selectAWord();\n
+                    break;\n
+                case "(":\n
+                case "{":\n
+                case "[":\n
+                    var cursor = editor.getCursorPosition();\n
+                    var end = editor.session.$findClosingBracket(param, cursor, /paren/);\n
+                    if (!end)\n
+                        return;\n
+                    var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/);\n
+                    if (!start)\n
+                        return;\n
+                    end.column ++;\n
+                    editor.selection.setSelectionRange(Range.fromPoints(start, end));\n
+                    break;\n
+                case "\'":\n
+                case "\\"":\n
+                case "/":\n
+                    var end = find(editor, param, 1);\n
+                    if (!end)\n
+                        return;\n
+                    var start = find(editor, param, -1);\n
+                    if (!start)\n
+                        return;\n
+                    end.column ++;\n
+                    editor.selection.setSelectionRange(Range.fromPoints(start.start, end.end));\n
+                    break;\n
+            }\n
+        }\n
+    },\n
+\n
+    "f": new Motion({\n
+        param: true,\n
+        handlesCount: true,\n
+        getPos: function(editor, range, count, param, isSel, isRepeat) {\n
+            if (!isRepeat)\n
+                LAST_SEARCH_MOTION = {ch: "f", param: param};\n
+            var cursor = editor.getCursorPosition();\n
+            var column = util.getRightNthChar(editor, cursor, param, count || 1);\n
+\n
+            if (typeof column === "number") {\n
+                cursor.column += column + (isSel ? 2 : 1);\n
+                return cursor;\n
+            }\n
+        }\n
+    }),\n
+    "F": new Motion({\n
+        param: true,\n
+        handlesCount: true,\n
+        getPos: function(editor, range, count, param, isSel, isRepeat) {\n
+            if (!isRepeat)\n
+                LAST_SEARCH_MOTION = {ch: "F", param: param};\n
+            var cursor = editor.getCursorPosition();\n
+            var column = util.getLeftNthChar(editor, cursor, param, count || 1);\n
+\n
+            if (typeof column === "number") {\n
+                cursor.column -= column + 1;\n
+                return cursor;\n
+            }\n
+        }\n
+    }),\n
+    "t": new Motion({\n
+        param: true,\n
+        handlesCount: true,\n
+        getPos: function(editor, range, count, param, isSel, isRepeat) {\n
+            if (!isRepeat)\n
+                LAST_SEARCH_MOTION = {ch: "t", param: param};\n
+            var cursor = editor.getCursorPosition();\n
+            var column = util.getRightNthChar(editor, cursor, param, count || 1);\n
+\n
+            if (isRepeat && column == 0 && !(count > 1))\n
+                var column = util.getRightNthChar(editor, cursor, param, 2);\n
+                \n
+            if (typeof column === "number") {\n
+                cursor.column += column + (isSel ? 1 : 0);\n
+                return cursor;\n
+            }\n
+        }\n
+    }),\n
+    "T": new Motion({\n
+        param: true,\n
+        handlesCount: true,\n
+        getPos: function(editor, range, count, param, isSel, isRepeat) {\n
+            if (!isRepeat)\n
+                LAST_SEARCH_MOTION = {ch: "T", param: param};\n
+            var cursor = editor.getCursorPosition();\n
+            var column = util.getLeftNthChar(editor, cursor, param, count || 1);\n
+\n
+            if (isRepeat && column == 0 && !(count > 1))\n
+                var column = util.getLeftNthChar(editor, cursor, param, 2);\n
+            \n
+            if (typeof column === "number") {\n
+                cursor.column -= column;\n
+                return cursor;\n
+            }\n
+        }\n
+    }),\n
+    ";": new Motion({\n
+        handlesCount: true,\n
+        getPos: function(editor, range, count, param, isSel) {\n
+            var ch = LAST_SEARCH_MOTION.ch;\n
+            if (!ch)\n
+                return;\n
+            return module.exports[ch].getPos(\n
+                editor, range, count, LAST_SEARCH_MOTION.param, isSel, true\n
+            );\n
+        }\n
+    }),\n
+    ",": new Motion({\n
+        handlesCount: true,\n
+        getPos: function(editor, range, count, param, isSel) {\n
+            var ch = LAST_SEARCH_MOTION.ch;\n
+            if (!ch)\n
+                return;\n
+            var up = ch.toUpperCase();\n
+            ch = ch === up ? ch.toLowerCase() : up;\n
+            \n
+            return module.exports[ch].getPos(\n
+                editor, range, count, LAST_SEARCH_MOTION.param, isSel, true\n
+            );\n
+        }\n
+    }),\n
+\n
+    "^": {\n
+        nav: function(editor) {\n
+            editor.navigateLineStart();\n
+        },\n
+        sel: function(editor) {\n
+            editor.selection.selectLineStart();\n
+        }\n
+    },\n
+    "$": {\n
+        nav: function(editor) {\n
+            editor.navigateLineEnd();\n
+        },\n
+        sel: function(editor) {\n
+            editor.selection.selectLineEnd();\n
+        }\n
+    },\n
+    "0": new Motion(function(ed) {\n
+        return {row: ed.selection.lead.row, column: 0};\n
+    }),\n
+    "G": {\n
+        nav: function(editor, range, count, param) {\n
+            if (!count && count !== 0) { // Stupid JS\n
+                count = editor.session.getLength();\n
+            }\n
+            editor.gotoLine(count);\n
+        },\n
+        sel: function(editor, range, count, param) {\n
+            if (!count && count !== 0) { // Stupid JS\n
+                count = editor.session.getLength();\n
+            }\n
+            editor.selection.selectTo(count, 0);\n
+        }\n
+    },\n
+    "g": {\n
+        param: true,\n
+        nav: function(editor, range, count, param) {\n
+            switch(param) {\n
+                case "m":\n
+                    console.log("Middle line");\n
+                    break;\n
+                case "e":\n
+                    console.log("End of prev word");\n
+                    break;\n
+                case "g":\n
+                    editor.gotoLine(count || 0);\n
+                case "u":\n
+                    editor.gotoLine(count || 0);\n
+                case "U":\n
+                    editor.gotoLine(count || 0);\n
+            }\n
+        },\n
+        sel: function(editor, range, count, param) {\n
+            switch(param) {\n
+                case "m":\n
+                    console.log("Middle line");\n
+                    break;\n
+                case "e":\n
+                    console.log("End of prev word");\n
+                    break;\n
+                case "g":\n
+                    editor.selection.selectTo(count || 0, 0);\n
+            }\n
+        }\n
+    },\n
+    "o": {\n
+        nav: function(editor, range, count, param) {\n
+            count = count || 1;\n
+            var content = "";\n
+            while (0 < count--)\n
+                content += "\\n";\n
+\n
+            if (content.length) {\n
+                editor.navigateLineEnd()\n
+                editor.insert(content);\n
+                util.insertMode(editor);\n
+            }\n
+        }\n
+    },\n
+    "O": {\n
+        nav: function(editor, range, count, param) {\n
+            var row = editor.getCursorPosition().row;\n
+            count = count || 1;\n
+            var content = "";\n
+            while (0 < count--)\n
+                content += "\\n";\n
+\n
+            if (content.length) {\n
+                if(row > 0) {\n
+                    editor.navigateUp();\n
+                    editor.navigateLineEnd()\n
+                    editor.insert(content);\n
+                } else {\n
+                    editor.session.insert({row: 0, column: 0}, content);\n
+                    editor.navigateUp();\n
+                }\n
+                util.insertMode(editor);\n
+            }\n
+        }\n
+    },\n
+    "%": new Motion(function(editor){\n
+        var brRe = /[\\[\\]{}()]/g;\n
+        var cursor = editor.getCursorPosition();\n
+        var ch = editor.session.getLine(cursor.row)[cursor.column];\n
+        if (!brRe.test(ch)) {\n
+            var range = find(editor, brRe);\n
+            if (!range)\n
+                return;\n
+            cursor = range.start;\n
+        }\n
+        var match = editor.session.findMatchingBracket({\n
+            row: cursor.row,\n
+            column: cursor.column + 1\n
+        });\n
+\n
+        return match;\n
+    }),\n
+    "{": new Motion(function(ed) {\n
+        var session = ed.session;\n
+        var row = session.selection.lead.row;\n
+        while(row > 0 && !/\\S/.test(session.getLine(row)))\n
+            row--;\n
+        while(/\\S/.test(session.getLine(row)))\n
+            row--;\n
+        return {column: 0, row: row};\n
+    }),\n
+    "}": new Motion(function(ed) {\n
+        var session = ed.session;\n
+        var l = session.getLength();\n
+        var row = session.selection.lead.row;\n
+        while(row < l && !/\\S/.test(session.getLine(row)))\n
+            row++;\n
+        while(/\\S/.test(session.getLine(row)))\n
+            row++;\n
+        return {column: 0, row: row};\n
+    }),\n
+    "ctrl-d": {\n
+        nav: function(editor, range, count, param) {\n
+            editor.selection.clearSelection();\n
+            keepScrollPosition(editor, editor.gotoPageDown);\n
+        },\n
+        sel: function(editor, range, count, param) {\n
+            keepScrollPosition(editor, editor.selectPageDown);\n
+        }\n
+    },\n
+    "ctrl-u": {\n
+        nav: function(editor, range, count, param) {\n
+            editor.selection.clearSelection();\n
+            keepScrollPosition(editor, editor.gotoPageUp);\n
+        },\n
+        sel: function(editor, range, count, param) {\n
+            keepScrollPosition(editor, editor.selectPageUp);\n
+        }\n
+    },\n
+    "`": new Motion({\n
+        param: true,\n
+        handlesCount: true,\n
+        getPos: function(editor, range, count, param, isSel) {\n
+            var s = editor.session;\n
+            var marker = s.vimMarkers && s.vimMarkers[param];\n
+            if (marker) {\n
+                return marker.getPosition();\n
+            }\n
+        }\n
+    }),\n
+    "\'": new Motion({\n
+        param: true,\n
+        handlesCount: true,\n
+        getPos: function(editor, range, count, param, isSel) {\n
+            var s = editor.session;\n
+            var marker = s.vimMarkers && s.vimMarkers[param];\n
+            if (marker) {\n
+                var pos = marker.getPosition();\n
+                var line = editor.session.getLine(pos.row);                \n
+                pos.column = line.search(/\\S/);\n
+                if (pos.column == -1)\n
+                    pos.column = line.length;\n
+                return pos;\n
+            }\n
+        }\n
+    })\n
+};\n
+\n
+module.exports.backspace = module.exports.left = module.exports.h;\n
+module.exports.space = module.exports[\'return\'] = module.exports.right = module.exports.l;\n
+module.exports.up = module.exports.k;\n
+module.exports.down = module.exports.j;\n
+module.exports.pagedown = module.exports["ctrl-d"];\n
+module.exports.pageup = module.exports["ctrl-u"];\n
+\n
+});\n
+ \n
+define(\'ace/keyboard/vim/maps/operators\', [\'require\', \'exports\', \'module\' , \'ace/keyboard/vim/maps/util\', \'ace/keyboard/vim/registers\'], function(require, exports, module) {\n
+\n
+\n
+\n
+var util = require("./util");\n
+var registers = require("../registers");\n
+\n
+module.exports = {\n
+    "d": {\n
+        selFn: function(editor, range, count, param) {\n
+            registers._default.text = editor.getCopyText();\n
+            registers._default.isLine = util.onVisualLineMode;\n
+            if(util.onVisualLineMode)\n
+                editor.removeLines();\n
+            else\n
+                editor.session.remove(range);\n
+            util.normalMode(editor);\n
+        },\n
+        fn: function(editor, range, count, param) {\n
+            count = count || 1;\n
+            switch (param) {\n
+                case "d":\n
+                    registers._default.text = "";\n
+                    registers._default.isLine = true;\n
+                    for (var i = 0; i < count; i++) {\n
+                        editor.selection.selectLine();\n
+                        registers._default.text += editor.getCopyText();\n
+                        var selRange = editor.getSelectionRange();\n
+                        if (!selRange.isMultiLine()) {\n
+                            var row = selRange.start.row - 1;\n
+                            var col = editor.session.getLine(row).length\n
+                            selRange.setStart(row, col);\n
+                            editor.session.remove(selRange);\n
+                            editor.selection.clearSelection();\n
+                            break;\n
+                        }\n
+                        editor.session.remove(selRange);\n
+                        editor.selection.clearSelection();\n
+                    }\n
+                    registers._default.text = registers._default.text.replace(/\\n$/, "");\n
+                    break;\n
+                default:\n
+                    if (range) {\n
+                        editor.selection.setSelectionRange(range);\n
+                        registers._default.text = editor.getCopyText();\n
+                        registers._default.isLine = false;\n
+                        editor.session.remove(range);\n
+                        editor.selection.clearSelection();\n
+                    }\n
+            }\n
+        }\n
+    },\n
+    "c": {\n
+        selFn: function(editor, range, count, param) {\n
+            editor.session.remove(range);\n
+            util.insertMode(editor);\n
+        },\n
+        fn: function(editor, range, count, param) {\n
+            count = count || 1;\n
+            switch (param) {\n
+                case "c":\n
+                    for (var i = 0; i < count; i++) {\n
+                        editor.removeLines();\n
+                        util.insertMode(editor);\n
+                    }\n
+\n
+                    break;\n
+                default:\n
+                    if (range) {\n
+                        editor.session.remove(range);\n
+                        util.insertMode(editor);\n
+                    }\n
+            }\n
+        }\n
+    },\n
+    "y": {\n
+        selFn: function(editor, range, count, param) {\n
+            registers._default.text = editor.getCopyText();\n
+            registers._default.isLine = util.onVisualLineMode;\n
+            editor.selection.clearSelection();\n
+            util.normalMode(editor);\n
+        },\n
+        fn: function(editor, range, count, param) {\n
+            count = count || 1;\n
+            switch (param) {\n
+                case "y":\n
+                    var pos = editor.getCursorPosition();\n
+                    editor.selection.selectLine();\n
+                    for (var i = 0; i < count - 1; i++) {\n
+                        editor.selection.moveCursorDown();\n
+                    }\n
+                    registers._default.text = editor.getCopyText().replace(/\\n$/, "");\n
+                    editor.selection.clearSelection();\n
+                    registers._default.isLine = true;\n
+                    editor.moveCursorToPosition(pos);\n
+                    break;\n
+                default:\n
+                    if (range) {\n
+                        var pos = editor.getCursorPosition();\n
+                        editor.selection.setSelectionRange(range);\n
+                        registers._default.text = editor.getCopyText();\n
+                        registers._default.isLine = false;\n
+                        editor.selection.clearSelection();\n
+                        editor.moveCursorTo(pos.row, pos.column);\n
+                    }\n
+            }\n
+        }\n
+    },\n
+    ">": {\n
+        selFn: function(editor, range, count, param) {\n
+            count = count || 1;\n
+            for (var i = 0; i < count; i++) {\n
+                editor.indent();\n
+            }\n
+            util.normalMode(editor);\n
+        },\n
+        fn: function(editor, range, count, param) {\n
+            count = parseInt(count || 1, 10);\n
+            switch (param) {\n
+                case ">":\n
+                    var pos = editor.getCursorPosition();\n
+                    editor.selection.selectLine();\n
+                    for (var i = 0; i < count - 1; i++) {\n
+                        editor.selection.moveCursorDown();\n
+                    }\n
+                    editor.indent();\n
+                    editor.selection.clearSelection();\n
+                    editor.moveCursorToPosition(pos);\n
+                    editor.navigateLineEnd();\n
+                    editor.navigateLineStart();\n
+                    break;\n
+            }\n
+        }\n
+    },\n
+    "<": {\n
+        selFn: function(editor, range, count, param) {\n
+            count = count || 1;\n
+            for (var i = 0; i < count; i++) {\n
+                editor.blockOutdent();\n
+            }\n
+            util.normalMode(editor);\n
+        },\n
+        fn: function(editor, range, count, param) {\n
+            count = count || 1;\n
+            switch (param) {\n
+                case "<":\n
+                    var pos = editor.getCursorPosition();\n
+                    editor.selection.selectLine();\n
+                    for (var i = 0; i < count - 1; i++) {\n
+                        editor.selection.moveCursorDown();\n
+                    }\n
+                    editor.blockOutdent();\n
+                    editor.selection.clearSelection();\n
+                    editor.moveCursorToPosition(pos);\n
+                    editor.navigateLineEnd();\n
+                    editor.navigateLineStart();\n
+                    break;\n
+            }\n
+        }\n
+    }\n
+};\n
+});\n
+ \n
+"use strict"\n
+\n
+define(\'ace/keyboard/vim/maps/aliases\', [\'require\', \'exports\', \'module\' ], function(require, exports, module) {\n
+module.exports = {\n
+    "x": {\n
+        operator: {\n
+            ch: "d",\n
+            count: 1\n
+        },\n
+        motion: {\n
+            ch: "l",\n
+            count: 1\n
+        }\n
+    },\n
+    "X": {\n
+        operator: {\n
+            ch: "d",\n
+            count: 1\n
+        },\n
+        motion: {\n
+            ch: "h",\n
+            count: 1\n
+        }\n
+    },\n
+    "D": {\n
+        operator: {\n
+            ch: "d",\n
+            count: 1\n
+        },\n
+        motion: {\n
+            ch: "$",\n
+            count: 1\n
+        }\n
+    },\n
+    "C": {\n
+        operator: {\n
+            ch: "c",\n
+            count: 1\n
+        },\n
+        motion: {\n
+            ch: "$",\n
+            count: 1\n
+        }\n
+    },\n
+    "s": {\n
+        operator: {\n
+            ch: "c",\n
+            count: 1\n
+        },\n
+        motion: {\n
+            ch: "l",\n
+            count: 1\n
+        }\n
+    },\n
+    "S": {\n
+        operator: {\n
+            ch: "c",\n
+            count: 1\n
+        },\n
+        param: "c"\n
+    }\n
+};\n
+});\n
+\n
+
+
+]]></string> </value>
+        </item>
+        <item>
+            <key> <string>precondition</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>size</string> </key>
+            <value> <int>55892</int> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string>keybinding-vim.js</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace_editor_support.xml b/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace_editor_support.xml
index 1c66056b58..b3b30d3906 100644
--- a/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace_editor_support.xml
+++ b/bt5/erp5_ace_editor/SkinTemplateItem/portal_skins/erp5_ace_editor/ace_editor_support.xml
@@ -173,6 +173,8 @@
           tal:attributes="src string:${portal_url}/ace/ace.js"></script>\n
   <script type="text/javascript"\n
           tal:attributes="src string:${portal_url}/ace/mode-python.js"></script>\n
+  <script type="text/javascript"\n
+          tal:attributes="src string:${portal_url}/ace/ext-settings_menu.js"></script>\n
   <script type="text/javascript"\n
           tal:define=\'fullscreen_button string:<input type="button" value="Fullscreen" onclick="switchToFullScreen()" class="ace_editor_action_button" />;\n
                       save_button string:<button class="ace_editor_save_button" onclick="saveDocument(event)"><img src="images/save2.png" width="30" height="30" border="0" /></button>;\'\n
@@ -354,6 +356,15 @@
     window.onresize = setContainerDivSize;\n
 \n
     ace_editor = ace.edit(\'${div_id}\');\n
+\n
+    ace.require(\'ace/ext/settings_menu\').init(ace_editor);\n
+    ace_editor.commands.addCommands([{\n
+        name: \'showSettingsMenu\',\n
+        bindKey: {win: \'Alt-p\', mac: \'Alt-p\'},\n
+        exec: function(editor) { editor.showSettingsMenu(); },\n
+        readOnly: true\n
+    }]);\n
+\n
     ace_editor.resize();\n
 \n
     var PythonMode = require(\'ace/mode/python\').Mode;\n
diff --git a/bt5/erp5_ace_editor/bt/change_log b/bt5/erp5_ace_editor/bt/change_log
index af18039ce4..1dd749a7e7 100644
--- a/bt5/erp5_ace_editor/bt/change_log
+++ b/bt5/erp5_ace_editor/bt/change_log
@@ -1,3 +1,6 @@
+2013-08-13 arnaud.fontaine
+* ZODB Components: Add Ace Editor settings menu (Alt+p) to set up keybinding styles for example.
+
 2013-08-13 arnaud.fontaine
 * ZODB Components: Add JS file required to find text within Ace Editor.
 
diff --git a/bt5/erp5_ace_editor/bt/revision b/bt5/erp5_ace_editor/bt/revision
index 9d607966b7..3cacc0b93c 100644
--- a/bt5/erp5_ace_editor/bt/revision
+++ b/bt5/erp5_ace_editor/bt/revision
@@ -1 +1 @@
-11
\ No newline at end of file
+12
\ No newline at end of file
-- 
2.30.9