Index: admin/js/codemirror/addon/edit/closebrackets.js
===================================================================
--- admin/js/codemirror/addon/edit/closebrackets.js	(revision 3532)
+++ admin/js/codemirror/addon/edit/closebrackets.js	(revision 3617)
@@ -24,4 +24,5 @@
     }
     if (val) {
+      ensureBound(getOption(val, "pairs"))
       cm.state.closeBrackets = val;
       cm.addKeyMap(keyMap);
@@ -35,8 +36,12 @@
   }
 
-  var bind = defaults.pairs + "`";
   var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
-  for (var i = 0; i < bind.length; i++)
-    keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
+  function ensureBound(chars) {
+    for (var i = 0; i < chars.length; i++) {
+      var ch = chars.charAt(i), key = "'" + ch + "'"
+      if (!keyMap[key]) keyMap[key] = handler(ch)
+    }
+  }
+  ensureBound(defaults.pairs + "`")
 
   function handler(ch) {
@@ -80,5 +85,6 @@
     }
     cm.operation(function() {
-      cm.replaceSelection("\n\n", null);
+      var linesep = cm.lineSeparator() || "\n";
+      cm.replaceSelection(linesep + linesep, null);
       cm.execCommand("goCharLeft");
       ranges = cm.listSelections();
@@ -128,5 +134,6 @@
         curType = "addFour";
       } else if (identical) {
-        if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both";
+        var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur)
+        if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both";
         else return CodeMirror.Pass;
       } else if (opening && (cm.getLine(cur.line).length == cur.ch ||
@@ -180,23 +187,8 @@
   }
 
-  // Project the token type that will exists after the given char is
-  // typed, and use it to determine whether it would cause the start
-  // of a string token.
-  function enteringString(cm, pos, ch) {
-    var line = cm.getLine(pos.line);
-    var token = cm.getTokenAt(pos);
-    if (/\bstring2?\b/.test(token.type) || stringStartsAfter(cm, pos)) return false;
-    var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
-    stream.pos = stream.start = token.start;
-    for (;;) {
-      var type1 = cm.getMode().token(stream, token.state);
-      if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1);
-      stream.start = stream.pos;
-    }
-  }
-
   function stringStartsAfter(cm, pos) {
     var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1))
-    return /\bstring/.test(token.type) && token.start == pos.ch
+    return /\bstring/.test(token.type) && token.start == pos.ch &&
+      (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos)))
   }
 });
Index: admin/js/codemirror/addon/edit/matchbrackets.js
===================================================================
--- admin/js/codemirror/addon/edit/matchbrackets.js	(revision 3532)
+++ admin/js/codemirror/addon/edit/matchbrackets.js	(revision 3617)
@@ -17,10 +17,19 @@
   var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
 
-  function findMatchingBracket(cm, where, strict, config) {
+  function findMatchingBracket(cm, where, config) {
     var line = cm.getLineHandle(where.line), pos = where.ch - 1;
-    var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
+    var afterCursor = config && config.afterCursor
+    if (afterCursor == null)
+      afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)
+
+    // A cursor is defined as between two characters, but in in vim command mode
+    // (i.e. not insert mode), the cursor is visually represented as a
+    // highlighted box on top of the 2nd character. Otherwise, we allow matches
+    // from before or after the cursor.
+    var match = (!afterCursor && pos >= 0 && matching[line.text.charAt(pos)]) ||
+        matching[line.text.charAt(++pos)];
     if (!match) return null;
     var dir = match.charAt(1) == ">" ? 1 : -1;
-    if (strict && (dir > 0) != (pos == where.ch)) return null;
+    if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;
     var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
 
@@ -70,5 +79,5 @@
     var marks = [], ranges = cm.listSelections();
     for (var i = 0; i < ranges.length; i++) {
-      var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
+      var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);
       if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
         var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
@@ -114,6 +123,15 @@
 
   CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
-  CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
-    return findMatchingBracket(this, pos, strict, config);
+  CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){
+    // Backwards-compatibility kludge
+    if (oldConfig || typeof config == "boolean") {
+      if (!oldConfig) {
+        config = config ? {strict: true} : null
+      } else {
+        oldConfig.strict = config
+        config = oldConfig
+      }
+    }
+    return findMatchingBracket(this, pos, config)
   });
   CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
Index: admin/js/codemirror/lib/codemirror.css
===================================================================
--- admin/js/codemirror/lib/codemirror.css	(revision 3542)
+++ admin/js/codemirror/lib/codemirror.css	(revision 3617)
@@ -6,4 +6,5 @@
   height: 300px;
   color: black;
+  direction: ltr;
 }
 
@@ -59,5 +60,10 @@
   z-index: 1;
 }
-
+.cm-fat-cursor-mark {
+  background-color: rgba(20, 255, 20, 0.5);
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+}
 .cm-animate-fat-cursor {
   width: auto;
@@ -120,5 +126,5 @@
 .cm-s-default .cm-operator {}
 .cm-s-default .cm-variable-2 {color: #05a;}
-.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
 .cm-s-default .cm-comment {color: #a50;}
 .cm-s-default .cm-string {color: #a11;}
@@ -140,6 +146,6 @@
 /* Default styles for common addons */
 
-div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
-div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
 .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
 .CodeMirror-activeline-background {background: #e8f2ff;}
@@ -320,6 +326,6 @@
 
 .cm-searching {
-  background: #ffa;
-  background: rgba(255, 255, 0, .4);
+  background-color: #ffa;
+  background-color: rgba(255, 255, 0, .4);
 }
 
Index: admin/js/codemirror/mode/css/css.js
===================================================================
--- admin/js/codemirror/mode/css/css.js	(revision 3542)
+++ admin/js/codemirror/mode/css/css.js	(revision 3617)
@@ -78,7 +78,7 @@
     } else if (/[:;{}\[\]\(\)]/.test(ch)) {
       return ret(null, ch);
-    } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
-               (ch == "d" && stream.match("omain(")) ||
-               (ch == "r" && stream.match("egexp("))) {
+    } else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) ||
+               ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) ||
+               ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) {
       stream.backUp(1);
       state.tokenize = tokenParenthesized;
@@ -163,14 +163,14 @@
     } else if (type == "}" && state.context.prev) {
       return popContext(state);
-    } else if (supportsAtComponent && /@component/.test(type)) {
+    } else if (supportsAtComponent && /@component/i.test(type)) {
       return pushContext(state, stream, "atComponentBlock");
-    } else if (/^@(-moz-)?document$/.test(type)) {
+    } else if (/^@(-moz-)?document$/i.test(type)) {
       return pushContext(state, stream, "documentTypes");
-    } else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
+    } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
       return pushContext(state, stream, "atBlock");
-    } else if (/^@(font-face|counter-style)/.test(type)) {
+    } else if (/^@(font-face|counter-style)/i.test(type)) {
       state.stateArg = type;
       return "restricted_atBlock_before";
-    } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
+    } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
       return "keyframes";
     } else if (type && type.charAt(0) == "@") {
@@ -384,5 +384,6 @@
       }
       override = style;
-      state.state = states[state.state](type, stream, state);
+      if (type != "comment")
+        state.state = states[state.state](type, stream, state);
       return override;
     },
@@ -402,5 +403,4 @@
           // Dedent relative to current context.
           indent = Math.max(0, cx.indent - indentUnit);
-          cx = cx.prev;
         }
       }
@@ -411,4 +411,5 @@
     blockCommentStart: "/*",
     blockCommentEnd: "*/",
+    blockCommentContinue: " * ",
     lineComment: lineComment,
     fold: "brace"
@@ -473,5 +474,5 @@
     "border-top-width", "border-width", "bottom", "box-decoration-break",
     "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
-    "caption-side", "clear", "clip", "color", "color-profile", "column-count",
+    "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
     "column-fill", "column-gap", "column-rule", "column-rule-color",
     "column-rule-style", "column-rule-width", "column-span", "column-width",
@@ -494,5 +495,5 @@
     "grid-template-rows", "hanging-punctuation", "height", "hyphens",
     "icon", "image-orientation", "image-rendering", "image-resolution",
-    "inline-box-align", "justify-content", "left", "letter-spacing",
+    "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
     "line-break", "line-height", "line-stacking", "line-stacking-ruby",
     "line-stacking-shift", "line-stacking-strategy", "list-style",
@@ -509,5 +510,5 @@
     "page", "page-break-after", "page-break-before", "page-break-inside",
     "page-policy", "pause", "pause-after", "pause-before", "perspective",
-    "perspective-origin", "pitch", "pitch-range", "play-during", "position",
+    "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
     "presentation-level", "punctuation-trim", "quotes", "region-break-after",
     "region-break-before", "region-break-inside", "region-fragment",
@@ -660,5 +661,5 @@
     "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
     "searchfield-cancel-button", "searchfield-decoration",
-    "searchfield-results-button", "searchfield-results-decoration",
+    "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
     "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
     "simp-chinese-formal", "simp-chinese-informal", "single",
@@ -666,5 +667,5 @@
     "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
     "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
-    "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "spell-out", "square",
+    "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
     "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
     "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
@@ -749,6 +750,6 @@
       },
       ":": function(stream) {
-        if (stream.match(/\s*\{/))
-          return [null, "{"];
+        if (stream.match(/\s*\{/, false))
+          return [null, null]
         return false;
       },
@@ -793,5 +794,5 @@
       "@": function(stream) {
         if (stream.eat("{")) return [null, "interpolation"];
-        if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
+        if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
         stream.eatWhile(/[\w\\\-]/);
         if (stream.match(/^\s*:/, false))
Index: admin/js/codemirror/mode/htmlmixed/htmlmixed.js
===================================================================
--- admin/js/codemirror/mode/htmlmixed/htmlmixed.js	(revision 3532)
+++ admin/js/codemirror/mode/htmlmixed/htmlmixed.js	(revision 3617)
@@ -134,9 +134,9 @@
       },
 
-      indent: function (state, textAfter) {
+      indent: function (state, textAfter, line) {
         if (!state.localMode || /^\s*<\//.test(textAfter))
           return htmlMode.indent(state.htmlState, textAfter);
         else if (state.localMode.indent)
-          return state.localMode.indent(state.localState, textAfter);
+          return state.localMode.indent(state.localState, textAfter, line);
         else
           return CodeMirror.Pass;
Index: admin/js/codemirror/mode/javascript/javascript.js
===================================================================
--- admin/js/codemirror/mode/javascript/javascript.js	(revision 3542)
+++ admin/js/codemirror/mode/javascript/javascript.js	(revision 3617)
@@ -12,9 +12,4 @@
 "use strict";
 
-function expressionAllowed(stream, state, backUp) {
-  return /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
-    (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
-}
-
 CodeMirror.defineMode("javascript", function(config, parserConfig) {
   var indentUnit = config.indentUnit;
@@ -29,11 +24,11 @@
   var keywords = function(){
     function kw(type) {return {type: type, style: "keyword"};}
-    var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
+    var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
     var operator = kw("operator"), atom = {type: "atom", style: "atom"};
 
     var jsKeywords = {
       "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
-      "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
-      "var": kw("var"), "const": kw("var"), "let": kw("var"),
+      "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
+      "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
       "function": kw("function"), "catch": kw("catch"),
       "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
@@ -42,10 +37,10 @@
       "this": kw("this"), "class": kw("class"), "super": kw("atom"),
       "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
-      "await": C, "async": kw("async")
+      "await": C
     };
 
     // Extend the 'normal' keywords with the TypeScript language extensions
     if (isTS) {
-      var type = {type: "variable", style: "variable-3"};
+      var type = {type: "variable", style: "type"};
       var tsKeywords = {
         // object-like things
@@ -53,7 +48,4 @@
         "implements": C,
         "namespace": C,
-        "module": kw("module"),
-        "enum": kw("module"),
-        "type": kw("type"),
 
         // scope modifiers
@@ -62,7 +54,5 @@
         "protected": kw("modifier"),
         "abstract": kw("modifier"),
-
-        // operators
-        "as": operator,
+        "readonly": kw("modifier"),
 
         // types
@@ -78,5 +68,5 @@
   }();
 
-  var isOperatorChar = /[+\-*&%=<>!?|~^]/;
+  var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
   var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
 
@@ -137,5 +127,5 @@
         return ret("regexp", "string-2");
       } else {
-        stream.eatWhile(isOperatorChar);
+        stream.eat("=");
         return ret("operator", "operator", stream.current());
       }
@@ -147,12 +137,25 @@
       return ret("error", "error");
     } else if (isOperatorChar.test(ch)) {
-      if (ch != ">" || !state.lexical || state.lexical.type != ">")
-        stream.eatWhile(isOperatorChar);
+      if (ch != ">" || !state.lexical || state.lexical.type != ">") {
+        if (stream.eat("=")) {
+          if (ch == "!" || ch == "=") stream.eat("=")
+        } else if (/[<>*+\-]/.test(ch)) {
+          stream.eat(ch)
+          if (ch == ">") stream.eat(ch)
+        }
+      }
       return ret("operator", "operator", stream.current());
     } else if (wordRE.test(ch)) {
       stream.eatWhile(wordRE);
-      var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
-      return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
-                     ret("variable", "variable", word);
+      var word = stream.current()
+      if (state.lastType != ".") {
+        if (keywords.propertyIsEnumerable(word)) {
+          var kw = keywords[word]
+          return ret(kw.type, kw.style, word)
+        }
+        if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\(\w]/, false))
+          return ret("async", "keyword", word)
+      }
+      return ret("variable", "variable", word)
     }
   }
@@ -353,4 +356,6 @@
     if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
     if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
+    if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);
+    if (type == "debugger") return cont(expect(";"));
     if (type == "{") return cont(pushlex("}"), block, poplex);
     if (type == ";") return cont();
@@ -362,6 +367,19 @@
     if (type == "function") return cont(functiondef);
     if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
-    if (type == "variable") return cont(pushlex("stat"), maybelabel);
-    if (type == "switch") return cont(pushlex("form"), parenExpr, pushlex("}", "switch"), expect("{"),
+    if (type == "variable") {
+      if (isTS && value == "type") {
+        cx.marked = "keyword"
+        return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
+      } else if (isTS && value == "declare") {
+        cx.marked = "keyword"
+        return cont(statement)
+      } else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) {
+        cx.marked = "keyword"
+        return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
+      } else {
+        return cont(pushlex("stat"), maybelabel);
+      }
+    }
+    if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
                                       block, poplex, poplex);
     if (type == "case") return cont(expression, expect(":"));
@@ -372,7 +390,6 @@
     if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
     if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
-    if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex)
-    if (type == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
     if (type == "async") return cont(statement)
+    if (value == "@") return cont(expression, statement)
     return pass(pushlex("stat"), expression, expect(";"), poplex);
   }
@@ -390,5 +407,5 @@
     if (cx.state.fatArrowAt == cx.stream.start) {
       var body = noComma ? arrowBodyNoComma : arrowBody;
-      if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
+      if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
       else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
     }
@@ -398,5 +415,5 @@
     if (type == "function") return cont(functiondef, maybeop);
     if (type == "class") return cont(pushlex("form"), classExpression, poplex);
-    if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
+    if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
     if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
     if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
@@ -411,8 +428,4 @@
     return pass(expression);
   }
-  function maybeexpressionNoComma(type) {
-    if (type.match(/[;\}\)\],]/)) return pass();
-    return pass(expressionNoComma);
-  }
 
   function maybeoperatorComma(type, value) {
@@ -425,5 +438,7 @@
     if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
     if (type == "operator") {
-      if (/\+\+|--/.test(value)) return cont(me);
+      if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
+      if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false))
+        return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
       if (value == "?") return cont(expression, expect(":"), expr);
       return cont(expr);
@@ -434,4 +449,10 @@
     if (type == ".") return cont(property, me);
     if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
+    if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
+    if (type == "regexp") {
+      cx.state.lastType = cx.marked = "operator"
+      cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
+      return cont(expr)
+    }
   }
   function quasi(type, value) {
@@ -458,4 +479,5 @@
     return function(type) {
       if (type == ".") return cont(noComma ? targetNoComma : target);
+      else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
       else return pass(noComma ? expressionNoComma : expression);
     };
@@ -481,4 +503,7 @@
       cx.marked = "property";
       if (value == "get" || value == "set") return cont(getterSetter);
+      var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
+      if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
+        cx.state.fatArrowAt = cx.stream.pos + m[0].length
       return cont(afterprop);
     } else if (type == "number" || type == "string") {
@@ -492,5 +517,8 @@
       return cont(expression, expect("]"), afterprop);
     } else if (type == "spread") {
-      return cont(expression);
+      return cont(expressionNoComma, afterprop);
+    } else if (value == "*") {
+      cx.marked = "keyword";
+      return cont(objprop);
     } else if (type == ":") {
       return pass(afterprop)
@@ -539,8 +567,29 @@
     }
   }
-  function typeexpr(type) {
-    if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);}
+  function mayberettype(type) {
+    if (isTS && type == ":") {
+      if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
+      else return cont(typeexpr)
+    }
+  }
+  function isKW(_, value) {
+    if (value == "is") {
+      cx.marked = "keyword"
+      return cont()
+    }
+  }
+  function typeexpr(type, value) {
+    if (type == "variable" || value == "void") {
+      if (value == "keyof") {
+        cx.marked = "keyword"
+        return cont(typeexpr)
+      } else {
+        cx.marked = "type"
+        return cont(afterType)
+      }
+    }
     if (type == "string" || type == "number" || type == "atom") return cont(afterType);
-    if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex)
+    if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
+    if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
     if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
   }
@@ -556,4 +605,6 @@
     } else if (type == ":") {
       return cont(typeexpr)
+    } else if (type == "[") {
+      return cont(expression, maybetype, expect("]"), typeprop)
     }
   }
@@ -566,4 +617,14 @@
     if (value == "|" || type == ".") return cont(typeexpr)
     if (type == "[") return cont(expect("]"), afterType)
+    if (value == "extends") return cont(typeexpr)
+  }
+  function maybeTypeArgs(_, value) {
+    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
+  }
+  function typeparam() {
+    return pass(typeexpr, maybeTypeDefault)
+  }
+  function maybeTypeDefault(_, value) {
+    if (value == "=") return cont(typeexpr)
   }
   function vardef() {
@@ -620,8 +681,10 @@
     if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
     if (type == "variable") {register(value); return cont(functiondef);}
-    if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
-  }
-  function funarg(type) {
-    if (type == "spread") return cont(funarg);
+    if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);
+    if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)
+  }
+  function funarg(type, value) {
+    if (value == "@") cont(expression, funarg)
+    if (type == "spread" || type == "modifier") return cont(funarg);
     return pass(pattern, maybetype, maybeAssign);
   }
@@ -635,5 +698,5 @@
   }
   function classNameAfter(type, value) {
-    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, classNameAfter)
+    if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
     if (value == "extends" || value == "implements" || (isTS && type == ","))
       return cont(isTS ? typeexpr : expression, classNameAfter);
@@ -641,11 +704,12 @@
   }
   function classBody(type, value) {
+    if (type == "modifier" || type == "async" ||
+        (type == "variable" &&
+         (value == "static" || value == "get" || value == "set") &&
+         cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
+      cx.marked = "keyword";
+      return cont(classBody);
+    }
     if (type == "variable" || cx.style == "keyword") {
-      if ((value == "async" || value == "static" || value == "get" || value == "set" ||
-           (isTS && (value == "public" || value == "private" || value == "protected" || value == "readonly" || value == "abstract"))) &&
-          cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false)) {
-        cx.marked = "keyword";
-        return cont(classBody);
-      }
       cx.marked = "property";
       return cont(isTS ? classfield : functiondef, classBody);
@@ -659,4 +723,5 @@
     if (type == ";") return cont(classBody);
     if (type == "}") return cont();
+    if (value == "@") return cont(expression, classBody)
   }
   function classfield(type, value) {
@@ -704,4 +769,10 @@
       isOperatorChar.test(textAfter.charAt(0)) ||
       /[,.]/.test(textAfter.charAt(0));
+  }
+
+  function expressionAllowed(stream, state, backUp) {
+    return state.tokenize == tokenBase &&
+      /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
+      (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
   }
 
@@ -771,4 +842,5 @@
     blockCommentStart: jsonMode ? null : "/*",
     blockCommentEnd: jsonMode ? null : "*/",
+    blockCommentContinue: jsonMode ? null : " * ",
     lineComment: jsonMode ? null : "//",
     fold: "brace",
@@ -780,4 +852,5 @@
 
     expressionAllowed: expressionAllowed,
+
     skipExpression: function(state) {
       var top = state.cc[state.cc.length - 1]
Index: admin/js/codemirror/mode/php/php.js
===================================================================
--- admin/js/codemirror/mode/php/php.js	(revision 3251)
+++ admin/js/codemirror/mode/php/php.js	(revision 3617)
@@ -152,5 +152,5 @@
 
   CodeMirror.defineMode("php", function(config, parserConfig) {
-    var htmlMode = CodeMirror.getMode(config, "text/html");
+    var htmlMode = CodeMirror.getMode(config, (parserConfig && parserConfig.htmlMode) || "text/html");
     var phpMode = CodeMirror.getMode(config, phpConfig);
 
Index: admin/js/codemirror/mode/xml/xml.js
===================================================================
--- admin/js/codemirror/mode/xml/xml.js	(revision 3251)
+++ admin/js/codemirror/mode/xml/xml.js	(revision 3617)
@@ -53,4 +53,5 @@
   allowUnquoted: false,
   allowMissing: false,
+  allowMissingTagName: false,
   caseFold: false
 }
@@ -227,4 +228,7 @@
       setStyle = "tag";
       return attrState;
+    } else if (config.allowMissingTagName && type == "endTag") {
+      setStyle = "tag bracket";
+      return attrState(type, stream, state);
     } else {
       setStyle = "error";
@@ -245,4 +249,7 @@
         return closeStateErr;
       }
+    } else if (config.allowMissingTagName && type == "endTag") {
+      setStyle = "tag bracket";
+      return closeState(type, stream, state);
     } else {
       setStyle = "error";
Index: admin/js/codemirror/theme/abcdef.css
===================================================================
--- admin/js/codemirror/theme/abcdef.css	(revision 3251)
+++ admin/js/codemirror/theme/abcdef.css	(revision 3617)
@@ -15,5 +15,5 @@
 .cm-s-abcdef span.cm-variable { color: #abcdef; }
 .cm-s-abcdef span.cm-variable-2 { color: #cacbcc; }
-.cm-s-abcdef span.cm-variable-3 { color: #def; }
+.cm-s-abcdef span.cm-variable-3, .cm-s-abcdef span.cm-type { color: #def; }
 .cm-s-abcdef span.cm-property { color: #fedcba; }
 .cm-s-abcdef span.cm-operator { color: #ff0; }
Index: admin/js/codemirror/theme/ambiance.css
===================================================================
--- admin/js/codemirror/theme/ambiance.css	(revision 3251)
+++ admin/js/codemirror/theme/ambiance.css	(revision 3617)
@@ -12,5 +12,5 @@
 .cm-s-ambiance .cm-variable { color: #ffb795; }
 .cm-s-ambiance .cm-variable-2 { color: #eed1b3; }
-.cm-s-ambiance .cm-variable-3 { color: #faded3; }
+.cm-s-ambiance .cm-variable-3, .cm-s-ambiance .cm-type { color: #faded3; }
 .cm-s-ambiance .cm-property { color: #eed1b3; }
 .cm-s-ambiance .cm-operator { color: #fa8d6a; }
Index: admin/js/codemirror/theme/cobalt.css
===================================================================
--- admin/js/codemirror/theme/cobalt.css	(revision 3251)
+++ admin/js/codemirror/theme/cobalt.css	(revision 3617)
@@ -16,5 +16,5 @@
 .cm-s-cobalt span.cm-meta { color: #ff9d00; }
 .cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }
-.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; }
+.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def, .cm-s-cobalt .cm-type { color: white; }
 .cm-s-cobalt span.cm-bracket { color: #d8d8d8; }
 .cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }
Index: admin/js/codemirror/theme/colorforth.css
===================================================================
--- admin/js/codemirror/theme/colorforth.css	(revision 3251)
+++ admin/js/codemirror/theme/colorforth.css	(revision 3617)
@@ -16,5 +16,5 @@
 
 .cm-s-colorforth span.cm-variable-2  { color: #EEE; }
-.cm-s-colorforth span.cm-variable-3  { color: #DDD; }
+.cm-s-colorforth span.cm-variable-3, .cm-s-colorforth span.cm-type { color: #DDD; }
 .cm-s-colorforth span.cm-property    {}
 .cm-s-colorforth span.cm-operator    {}
Index: admin/js/codemirror/theme/dracula.css
===================================================================
--- admin/js/codemirror/theme/dracula.css	(revision 3532)
+++ admin/js/codemirror/theme/dracula.css	(revision 3617)
@@ -35,5 +35,5 @@
 .cm-s-dracula span.cm-property { color: #66d9ef; }
 .cm-s-dracula span.cm-builtin { color: #50fa7b; }
-.cm-s-dracula span.cm-variable-3 { color: #ffb86c; }
+.cm-s-dracula span.cm-variable-3, .cm-s-dracula span.cm-type { color: #ffb86c; }
 
 .cm-s-dracula .CodeMirror-activeline-background { background: rgba(255,255,255,0.1); }
Index: admin/js/codemirror/theme/duotone-dark.css
===================================================================
--- admin/js/codemirror/theme/duotone-dark.css	(revision 3532)
+++ admin/js/codemirror/theme/duotone-dark.css	(revision 3617)
@@ -25,5 +25,5 @@
 .cm-s-duotone-dark span.cm-positive { color: #6a51e6; }
 
-.cm-s-duotone-dark span.cm-variable-2, .cm-s-duotone-dark span.cm-variable-3, .cm-s-duotone-dark span.cm-string-2, .cm-s-duotone-dark span.cm-url { color: #7a63ee; }
+.cm-s-duotone-dark span.cm-variable-2, .cm-s-duotone-dark span.cm-variable-3, .cm-s-duotone-dark span.cm-type, .cm-s-duotone-dark span.cm-string-2, .cm-s-duotone-dark span.cm-url { color: #7a63ee; }
 .cm-s-duotone-dark span.cm-def, .cm-s-duotone-dark span.cm-tag, .cm-s-duotone-dark span.cm-builtin, .cm-s-duotone-dark span.cm-qualifier, .cm-s-duotone-dark span.cm-header, .cm-s-duotone-dark span.cm-em { color: #eeebff; }
 .cm-s-duotone-dark span.cm-bracket, .cm-s-duotone-dark span.cm-comment { color: #6c6783; }
Index: admin/js/codemirror/theme/duotone-light.css
===================================================================
--- admin/js/codemirror/theme/duotone-light.css	(revision 3532)
+++ admin/js/codemirror/theme/duotone-light.css	(revision 3617)
@@ -24,5 +24,5 @@
 .cm-s-duotone-light span.cm-positive { color: #896724; }
 
-.cm-s-duotone-light span.cm-variable-2, .cm-s-duotone-light span.cm-variable-3, .cm-s-duotone-light span.cm-string-2, .cm-s-duotone-light span.cm-url { color: #896724; }
+.cm-s-duotone-light span.cm-variable-2, .cm-s-duotone-light span.cm-variable-3, .cm-s-duotone-light span.cm-type, .cm-s-duotone-light span.cm-string-2, .cm-s-duotone-light span.cm-url { color: #896724; }
 .cm-s-duotone-light span.cm-def, .cm-s-duotone-light span.cm-tag, .cm-s-duotone-light span.cm-builtin, .cm-s-duotone-light span.cm-qualifier, .cm-s-duotone-light span.cm-header, .cm-s-duotone-light span.cm-em { color: #2d2006; }
 .cm-s-duotone-light span.cm-bracket, .cm-s-duotone-light span.cm-comment { color: #b6ad9a; }
Index: admin/js/codemirror/theme/eclipse.css
===================================================================
--- admin/js/codemirror/theme/eclipse.css	(revision 3251)
+++ admin/js/codemirror/theme/eclipse.css	(revision 3617)
@@ -6,5 +6,5 @@
 .cm-s-eclipse span.cm-variable { color: black; }
 .cm-s-eclipse span.cm-variable-2 { color: #0000C0; }
-.cm-s-eclipse span.cm-variable-3 { color: #0000C0; }
+.cm-s-eclipse span.cm-variable-3, .cm-s-eclipse span.cm-type { color: #0000C0; }
 .cm-s-eclipse span.cm-property { color: black; }
 .cm-s-eclipse span.cm-operator { color: black; }
Index: admin/js/codemirror/theme/erlang-dark.css
===================================================================
--- admin/js/codemirror/theme/erlang-dark.css	(revision 3251)
+++ admin/js/codemirror/theme/erlang-dark.css	(revision 3617)
@@ -28,5 +28,5 @@
 .cm-s-erlang-dark span.cm-variable   { color: #50fe50; }
 .cm-s-erlang-dark span.cm-variable-2 { color: #e0e; }
-.cm-s-erlang-dark span.cm-variable-3 { color: #ccc; }
+.cm-s-erlang-dark span.cm-variable-3, .cm-s-erlang-dark span.cm-type { color: #ccc; }
 .cm-s-erlang-dark span.cm-error      { color: #9d1e15; }
 
Index: admin/js/codemirror/theme/icecoder.css
===================================================================
--- admin/js/codemirror/theme/icecoder.css	(revision 3251)
+++ admin/js/codemirror/theme/icecoder.css	(revision 3617)
@@ -12,5 +12,5 @@
 .cm-s-icecoder span.cm-variable { color: #6cb5d9; }                /* blue */
 .cm-s-icecoder span.cm-variable-2 { color: #cc1e5c; }              /* pink */
-.cm-s-icecoder span.cm-variable-3 { color: #f9602c; }              /* orange */
+.cm-s-icecoder span.cm-variable-3, .cm-s-icecoder span.cm-type { color: #f9602c; } /* orange */
 
 .cm-s-icecoder span.cm-property { color: #eee; }                   /* off-white 1 */
Index: admin/js/codemirror/theme/lesser-dark.css
===================================================================
--- admin/js/codemirror/theme/lesser-dark.css	(revision 3251)
+++ admin/js/codemirror/theme/lesser-dark.css	(revision 3617)
@@ -28,5 +28,5 @@
 .cm-s-lesser-dark span.cm-variable { color:#D9BF8C; }
 .cm-s-lesser-dark span.cm-variable-2 { color: #669199; }
-.cm-s-lesser-dark span.cm-variable-3 { color: white; }
+.cm-s-lesser-dark span.cm-variable-3, .cm-s-lesser-dark span.cm-type { color: white; }
 .cm-s-lesser-dark span.cm-property { color: #92A75C; }
 .cm-s-lesser-dark span.cm-operator { color: #92A75C; }
Index: admin/js/codemirror/theme/liquibyte.css
===================================================================
--- admin/js/codemirror/theme/liquibyte.css	(revision 3251)
+++ admin/js/codemirror/theme/liquibyte.css	(revision 3617)
@@ -37,5 +37,5 @@
 
 .cm-s-liquibyte span.cm-variable-2  { color: #007f7f; font-weight: bold; }
-.cm-s-liquibyte span.cm-variable-3  { color: #c080ff; font-weight: bold; }
+.cm-s-liquibyte span.cm-variable-3, .cm-s-liquibyte span.cm-type { color: #c080ff; font-weight: bold; }
 .cm-s-liquibyte span.cm-property    { color: #999; font-weight: bold; }
 .cm-s-liquibyte span.cm-operator    { color: #fff; }
@@ -60,8 +60,8 @@
 /* Scrollbars */
 /* Simple */
-.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div:hover, div.CodeMirror-simplescroll-vertical div:hover {
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div:hover, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div:hover {
 	background-color: rgba(80, 80, 80, .7);
 }
-.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div, div.CodeMirror-simplescroll-vertical div {
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div {
 	background-color: rgba(80, 80, 80, .3);
 	border: 1px solid #404040;
Index: admin/js/codemirror/theme/material.css
===================================================================
--- admin/js/codemirror/theme/material.css	(revision 3532)
+++ admin/js/codemirror/theme/material.css	(revision 3617)
@@ -28,5 +28,5 @@
 .cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); }
 .cm-s-material .cm-variable-2 { color: #80CBC4; }
-.cm-s-material .cm-variable-3 { color: #82B1FF; }
+.cm-s-material .cm-variable-3, .cm-s-material .cm-type { color: #82B1FF; }
 .cm-s-material .cm-builtin { color: #DECB6B; }
 .cm-s-material .cm-atom { color: #F77669; }
@@ -42,5 +42,5 @@
 .cm-s-material .cm-property { color: #80CBAE; }
 .cm-s-material .cm-qualifier { color: #DECB6B; }
-.cm-s-material .cm-variable-3 { color: #DECB6B; }
+.cm-s-material .cm-variable-3, .cm-s-material .cm-type { color: #DECB6B; }
 .cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); }
 .cm-s-material .cm-error {
Index: admin/js/codemirror/theme/mdn-like.css
===================================================================
--- admin/js/codemirror/theme/mdn-like.css	(revision 3251)
+++ admin/js/codemirror/theme/mdn-like.css	(revision 3617)
@@ -22,5 +22,5 @@
 .cm-s-mdn-like .cm-def { color: #8DA6CE; }
 .cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; }
-.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def { color: #07a; }
+.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def, .cm-s-mdn-like span.cm-type { color: #07a; }
 
 .cm-s-mdn-like .cm-variable { color: #07a; }
Index: admin/js/codemirror/theme/midnight.css
===================================================================
--- admin/js/codemirror/theme/midnight.css	(revision 3251)
+++ admin/js/codemirror/theme/midnight.css	(revision 3617)
@@ -12,6 +12,4 @@
     color: #D1EDFF;
 }
-
-.cm-s-midnight.CodeMirror { border-top: 1px solid black; border-bottom: 1px solid black; }
 
 .cm-s-midnight div.CodeMirror-selected { background: #314D67; }
Index: admin/js/codemirror/theme/monokai.css
===================================================================
--- admin/js/codemirror/theme/monokai.css	(revision 3251)
+++ admin/js/codemirror/theme/monokai.css	(revision 3617)
@@ -22,5 +22,5 @@
 .cm-s-monokai span.cm-variable { color: #f8f8f2; }
 .cm-s-monokai span.cm-variable-2 { color: #9effff; }
-.cm-s-monokai span.cm-variable-3 { color: #66d9ef; }
+.cm-s-monokai span.cm-variable-3, .cm-s-monokai span.cm-type { color: #66d9ef; }
 .cm-s-monokai span.cm-def { color: #fd971f; }
 .cm-s-monokai span.cm-bracket { color: #f8f8f2; }
Index: admin/js/codemirror/theme/night.css
===================================================================
--- admin/js/codemirror/theme/night.css	(revision 3251)
+++ admin/js/codemirror/theme/night.css	(revision 3617)
@@ -18,5 +18,5 @@
 .cm-s-night span.cm-meta { color: #7678e2; }
 .cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
-.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
+.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def, .cm-s-night span.cm-type { color: white; }
 .cm-s-night span.cm-bracket { color: #8da6ce; }
 .cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
Index: admin/js/codemirror/theme/panda-syntax.css
===================================================================
--- admin/js/codemirror/theme/panda-syntax.css	(revision 3532)
+++ admin/js/codemirror/theme/panda-syntax.css	(revision 3617)
@@ -53,5 +53,5 @@
 	color: #ff9ac1;
 }
-.cm-s-panda-syntax .cm-variable-3 {
+.cm-s-panda-syntax .cm-variable-3, .cm-s-panda-syntax .cm-type {
 	color: #ff9ac1;
 }
Index: admin/js/codemirror/theme/pastel-on-dark.css
===================================================================
--- admin/js/codemirror/theme/pastel-on-dark.css	(revision 3532)
+++ admin/js/codemirror/theme/pastel-on-dark.css	(revision 3617)
@@ -35,5 +35,5 @@
 .cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }
 .cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }
-.cm-s-pastel-on-dark span.cm-variable-3 { color: #DE8E30; }
+.cm-s-pastel-on-dark span.cm-variable-3, .cm-s-pastel-on-dark span.cm-type { color: #DE8E30; }
 .cm-s-pastel-on-dark span.cm-def { color: #757aD8; }
 .cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }
Index: admin/js/codemirror/theme/rubyblue.css
===================================================================
--- admin/js/codemirror/theme/rubyblue.css	(revision 3251)
+++ admin/js/codemirror/theme/rubyblue.css	(revision 3617)
@@ -16,5 +16,5 @@
 .cm-s-rubyblue span.cm-meta { color: #F0F; }
 .cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }
-.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; }
+.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def, .cm-s-rubyblue span.cm-type { color: white; }
 .cm-s-rubyblue span.cm-bracket { color: #F0F; }
 .cm-s-rubyblue span.cm-link { color: #F4C20B; }
Index: admin/js/codemirror/theme/seti.css
===================================================================
--- admin/js/codemirror/theme/seti.css	(revision 3251)
+++ admin/js/codemirror/theme/seti.css	(revision 3617)
@@ -39,5 +39,5 @@
 .cm-s-seti span.cm-qualifier { color: #9fca56; }
 .cm-s-seti span.cm-property { color: #a074c4; }
-.cm-s-seti span.cm-variable-3 { color: #9fca56; }
+.cm-s-seti span.cm-variable-3, .cm-s-seti span.cm-type { color: #9fca56; }
 .cm-s-seti span.cm-builtin { color: #9fca56; }
 .cm-s-seti .CodeMirror-activeline-background { background: #101213; }
Index: admin/js/codemirror/theme/solarized.css
===================================================================
--- admin/js/codemirror/theme/solarized.css	(revision 3532)
+++ admin/js/codemirror/theme/solarized.css	(revision 3617)
@@ -58,5 +58,5 @@
 .cm-s-solarized .cm-variable { color: #839496; }
 .cm-s-solarized .cm-variable-2 { color: #b58900; }
-.cm-s-solarized .cm-variable-3 { color: #6c71c4; }
+.cm-s-solarized .cm-variable-3, .cm-s-solarized .cm-type { color: #6c71c4; }
 
 .cm-s-solarized .cm-property { color: #2aa198; }
@@ -88,5 +88,4 @@
   text-decoration-style: dotted;
 }
-.cm-s-solarized .cm-strong { color: #eee; }
 .cm-s-solarized .cm-error,
 .cm-s-solarized .cm-invalidchar {
Index: admin/js/codemirror/theme/the-matrix.css
===================================================================
--- admin/js/codemirror/theme/the-matrix.css	(revision 3251)
+++ admin/js/codemirror/theme/the-matrix.css	(revision 3617)
@@ -15,5 +15,5 @@
 .cm-s-the-matrix span.cm-variable { color: #F6C; }
 .cm-s-the-matrix span.cm-variable-2 { color: #C6F; }
-.cm-s-the-matrix span.cm-variable-3 { color: #96F; }
+.cm-s-the-matrix span.cm-variable-3, .cm-s-the-matrix span.cm-type { color: #96F; }
 .cm-s-the-matrix span.cm-property { color: #62FFA0; }
 .cm-s-the-matrix span.cm-operator { color: #999; }
Index: admin/js/codemirror/theme/ttcn.css
===================================================================
--- admin/js/codemirror/theme/ttcn.css	(revision 3251)
+++ admin/js/codemirror/theme/ttcn.css	(revision 3617)
@@ -30,5 +30,5 @@
 .cm-s-ttcn .cm-variable { color: #8B2252; }
 .cm-s-ttcn .cm-variable-2 { color: #05a; }
-.cm-s-ttcn .cm-variable-3 { color: #085; }
+.cm-s-ttcn .cm-variable-3, .cm-s-ttcn .cm-type { color: #085; }
 
 .cm-s-ttcn .cm-invalidchar { color: #f00; }
Index: admin/js/codemirror/theme/twilight.css
===================================================================
--- admin/js/codemirror/theme/twilight.css	(revision 3251)
+++ admin/js/codemirror/theme/twilight.css	(revision 3617)
@@ -15,5 +15,5 @@
 .cm-s-twilight .cm-def { color: #8DA6CE; }
 .cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/
-.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def { color: #607392; } /**/
+.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def, .cm-s-twilight span.cm-type { color: #607392; } /**/
 .cm-s-twilight .cm-operator { color: #cda869; } /**/
 .cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/
Index: admin/js/codemirror/theme/vibrant-ink.css
===================================================================
--- admin/js/codemirror/theme/vibrant-ink.css	(revision 3251)
+++ admin/js/codemirror/theme/vibrant-ink.css	(revision 3617)
@@ -17,5 +17,5 @@
 .cm-s-vibrant-ink .cm-def { color: #8DA6CE; }
 .cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D; }
-.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def { color: #FFC66D; }
+.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def, .cm-s-vibrant span.cm-type { color: #FFC66D; }
 .cm-s-vibrant-ink .cm-operator { color: #888; }
 .cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }
Index: admin/js/codemirror/theme/xq-dark.css
===================================================================
--- admin/js/codemirror/theme/xq-dark.css	(revision 3251)
+++ admin/js/codemirror/theme/xq-dark.css	(revision 3617)
@@ -37,5 +37,5 @@
 .cm-s-xq-dark span.cm-variable { color: #FFF; }
 .cm-s-xq-dark span.cm-variable-2 { color: #EEE; }
-.cm-s-xq-dark span.cm-variable-3 { color: #DDD; }
+.cm-s-xq-dark span.cm-variable-3, .cm-s-xq-dark span.cm-type { color: #DDD; }
 .cm-s-xq-dark span.cm-property {}
 .cm-s-xq-dark span.cm-operator {}
Index: admin/js/codemirror/theme/xq-light.css
===================================================================
--- admin/js/codemirror/theme/xq-light.css	(revision 3251)
+++ admin/js/codemirror/theme/xq-light.css	(revision 3617)
@@ -27,5 +27,5 @@
 .cm-s-xq-light span.cm-variable { color: black; }
 .cm-s-xq-light span.cm-variable-2 { color:black; }
-.cm-s-xq-light span.cm-variable-3 { color: black; }
+.cm-s-xq-light span.cm-variable-3, .cm-s-xq-light span.cm-type { color: black; }
 .cm-s-xq-light span.cm-property {}
 .cm-s-xq-light span.cm-operator {}
Index: admin/js/codemirror/theme/yeti.css
===================================================================
--- admin/js/codemirror/theme/yeti.css	(revision 3251)
+++ admin/js/codemirror/theme/yeti.css	(revision 3617)
@@ -40,5 +40,5 @@
 .cm-s-yeti span.cm-property { color: #a074c4; }
 .cm-s-yeti span.cm-builtin { color: #a074c4; }
-.cm-s-yeti span.cm-variable-3 { color: #96c0d8; }
+.cm-s-yeti span.cm-variable-3, .cm-s-yeti span.cm-type { color: #96c0d8; }
 .cm-s-yeti .CodeMirror-activeline-background { background: #E7E4E0; }
 .cm-s-yeti .CodeMirror-matchingbracket { text-decoration: underline; }
