Merge m-c to autoland, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 25 Sep 2017 16:45:14 -0700
changeset 670386 41c0020723649b183fcb7baab915e4c775f6f688
parent 670385 5084608dc0bb4a5a19258827c943ae3584bd7fb5 (current diff)
parent 670182 e6b3498a39b94616ba36798fe0b71a3090b1b14c (diff)
child 670387 82a3a8ca311e5a814537c75eaf093a38f975f420
push id81613
push userbmo:nchevobbe@mozilla.com
push dateTue, 26 Sep 2017 10:17:11 +0000
reviewersmerge
milestone58.0a1
Merge m-c to autoland, a=merge MozReview-Commit-ID: 479h8T5RxkK
dom/html/HTMLShadowElement.cpp
dom/html/HTMLShadowElement.h
dom/tests/mochitest/webcomponents/test_dest_insertion_points_shadow.html
dom/tests/mochitest/webcomponents/test_event_dispatch.html
dom/tests/mochitest/webcomponents/test_shadowroot_host.html
dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html
dom/tests/mochitest/webcomponents/test_shadowroot_youngershadowroot.html
dom/webidl/HTMLShadowElement.webidl
layout/reftests/webcomponents/adjacent-insertion-points-1-ref.html
layout/reftests/webcomponents/adjacent-insertion-points-1.html
layout/reftests/webcomponents/adjacent-insertion-points-2-ref.html
layout/reftests/webcomponents/adjacent-insertion-points-2.html
layout/reftests/webcomponents/basic-shadow-element-1-ref.html
layout/reftests/webcomponents/basic-shadow-element-1.html
layout/reftests/webcomponents/nested-shadow-element-1-ref.html
layout/reftests/webcomponents/nested-shadow-element-1.html
media/webrtc/signaling/signaling.gyp
testing/web-platform/meta/custom-elements/Document-createElement.html.ini
testing/web-platform/meta/custom-elements/reactions/Attr.html.ini
testing/web-platform/meta/custom-elements/reactions/NamedNodeMap.html.ini
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -27,19 +27,17 @@
 #include "nsIWindowMediator.h"
 #include "nsIPrefService.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Printf.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/dom/Location.h"
 
-#ifdef ENABLE_INTL_API
 #include "unicode/uloc.h"
-#endif
 
 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
 
 // DO NOT use namespace mozilla; it'll break due to a naming conflict between
 // mozilla::TextRange and a TextRange in OSX headers.
 using mozilla::StyleSheet;
 using mozilla::dom::IsChromeURI;
 using mozilla::dom::Location;
@@ -633,46 +631,23 @@ nsChromeRegistry::MustLoadURLRemotely(ns
     *aResult = !!(flags & REMOTE_REQUIRED);
   }
   return NS_OK;
 }
 
 bool
 nsChromeRegistry::GetDirectionForLocale(const nsACString& aLocale)
 {
-#ifdef ENABLE_INTL_API
   int pref = mozilla::Preferences::GetInt("intl.uidirection", -1);
   if (pref >= 0) {
     return (pref > 0);
   }
   nsAutoCString locale(aLocale);
   SanitizeForBCP47(locale);
   return uloc_isRightToLeft(locale.get());
-#else
-  // first check the intl.uidirection.<locale> preference, and if that is not
-  // set, check the same preference but with just the first two characters of
-  // the locale. If that isn't set, default to left-to-right.
-  nsAutoCString prefString = NS_LITERAL_CSTRING("intl.uidirection.") + aLocale;
-  nsCOMPtr<nsIPrefBranch> prefBranch (do_GetService(NS_PREFSERVICE_CONTRACTID));
-  if (!prefBranch) {
-    return false;
-  }
-
-  nsCString dir;
-  prefBranch->GetCharPref(prefString.get(), getter_Copies(dir));
-  if (dir.IsEmpty()) {
-    int32_t hyphen = prefString.FindChar('-');
-    if (hyphen >= 1) {
-      nsAutoCString shortPref(Substring(prefString, 0, hyphen));
-      prefBranch->GetCharPref(shortPref.get(), getter_Copies(dir));
-    }
-  }
-
-  return dir.EqualsLiteral("rtl");
-#endif
 }
 
 NS_IMETHODIMP_(bool)
 nsChromeRegistry::WrappersEnabled(nsIURI *aURI)
 {
   nsCOMPtr<nsIURL> chromeURL (do_QueryInterface(aURI));
   if (!chromeURL)
     return false;
@@ -710,33 +685,23 @@ nsChromeRegistry::GetSingleton()
     return nullptr;
 
   return cr.forget();
 }
 
 void
 nsChromeRegistry::SanitizeForBCP47(nsACString& aLocale)
 {
-#ifdef ENABLE_INTL_API
   // Currently, the only locale code we use that's not BCP47-conformant is
   // "ja-JP-mac" on OS X, but let's try to be more general than just
   // hard-coding that here.
   const int32_t LANG_TAG_CAPACITY = 128;
   char langTag[LANG_TAG_CAPACITY];
   nsAutoCString locale(aLocale);
   UErrorCode err = U_ZERO_ERROR;
   // This is a fail-safe method that will set langTag to "und" if it cannot
   // match any part of the input locale code.
   int32_t len = uloc_toLanguageTag(locale.get(), langTag, LANG_TAG_CAPACITY,
                                    false, &err);
   if (U_SUCCESS(err) && len > 0) {
     aLocale.Assign(langTag, len);
   }
-#else
-  // This is only really needed for Intl API purposes, AFAIK,
-  // so probably won't be used in a non-ENABLE_INTL_API build.
-  // But let's fix up the single anomalous code we actually ship,
-  // just in case:
-  if (aLocale.EqualsLiteral("ja-JP-mac")) {
-    aLocale.AssignLiteral("ja-JP");
-  }
-#endif
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_search-basic-01.js
@@ -29,19 +29,16 @@ function test() {
     performTest();
   });
 }
 
 function performTest() {
   // Make sure that the search box becomes focused when pressing ctrl+f - Bug 1211038
   gEditor.focus();
   synthesizeKeyFromKeyTag(gDebugger.document.getElementById("tokenSearchKey"));
-  let focusedEl = Services.focus.focusedElement;
-  focusedEl = focusedEl.ownerDocument.getBindingParent(focusedEl) || focusedEl;
-  is(focusedEl, gDebugger.document.getElementById("searchbox"), "Searchbox is focused");
 
   setText(gSearchBox, "#html");
 
   EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true }, gDebugger);
   is(gFiltering.searchData.toSource(), '["#", ["", "html"]]',
     "The searchbox data wasn't parsed correctly.");
   ok(isCaretPos(gPanel, 35, 7),
     "The editor didn't jump to the correct line.");
--- a/devtools/client/sourceeditor/codemirror/README
+++ b/devtools/client/sourceeditor/codemirror/README
@@ -1,16 +1,16 @@
 This is the CodeMirror editor packaged for the Mozilla Project. CodeMirror
 is a JavaScript component that provides a code editor in the browser. When
 a mode is available for the language you are coding in, it will color your
 code, and optionally help with indentation.
 
 # Upgrade
 
-Currently used version is 5.29.0. To upgrade: download a new version of
+Currently used version is 5.30.0. To upgrade: download a new version of
 CodeMirror from the project's page [1] and replace all JavaScript and
 CSS files inside the codemirror directory [2].
 
 Then to recreate codemirror.bundle.js:
  > cd devtools/client/sourceeditor
  > npm install
  > webpack
 
--- a/devtools/client/sourceeditor/codemirror/addon/edit/closebrackets.js
+++ b/devtools/client/sourceeditor/codemirror/addon/edit/closebrackets.js
@@ -18,31 +18,36 @@
   var Pos = CodeMirror.Pos;
 
   CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
     if (old && old != CodeMirror.Init) {
       cm.removeKeyMap(keyMap);
       cm.state.closeBrackets = null;
     }
     if (val) {
+      ensureBound(getOption(val, "pairs"))
       cm.state.closeBrackets = val;
       cm.addKeyMap(keyMap);
     }
   });
 
   function getOption(conf, name) {
     if (name == "pairs" && typeof conf == "string") return conf;
     if (typeof conf == "object" && conf[name] != null) return conf[name];
     return defaults[name];
   }
 
-  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) {
     return function(cm) { return handleChar(cm, ch); };
   }
 
   function getConfig(cm) {
     var deflt = cm.state.closeBrackets;
     if (!deflt || deflt.override) return deflt;
--- a/devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js
+++ b/devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js
@@ -297,17 +297,17 @@
         if (completion.options.completeOnSingleClick) widget.pick();
       }
     });
 
     CodeMirror.on(hints, "mousedown", function() {
       setTimeout(function(){cm.focus();}, 20);
     });
 
-    CodeMirror.signal(data, "select", completions[0], hints.firstChild);
+    CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
     return true;
   }
 
   Widget.prototype = {
     close: function() {
       if (this.completion.widget != this) return;
       this.completion.widget = null;
       this.hints.parentNode.removeChild(this.hints);
--- a/devtools/client/sourceeditor/codemirror/addon/search/search.js
+++ b/devtools/client/sourceeditor/codemirror/addon/search/search.js
@@ -127,16 +127,17 @@
       queryDialog = doc.createElement("div");
       queryDialog.appendChild(inp);
       queryDialog.style.display = "flex";
     }
 
     var state = getSearchState(cm);
     if (state.query) return findNext(cm, rev);
     var q = cm.getSelection() || state.lastQuery;
+    if (q instanceof RegExp && q.source == "x^") q = null
     if (persistent && cm.openDialog) {
       var hiding = null
       var searchNext = function(query, event) {
         CodeMirror.e_stop(event);
         if (!query) return;
         if (query != state.queryText) {
           startSearch(cm, state, query);
           state.posFrom = state.posTo = cm.getCursor();
--- a/devtools/client/sourceeditor/codemirror/addon/selection/mark-selection.js
+++ b/devtools/client/sourceeditor/codemirror/addon/selection/mark-selection.js
@@ -81,17 +81,17 @@
     if (cm.listSelections().length > 1) return reset(cm);
 
     var from = cm.getCursor("start"), to = cm.getCursor("end");
 
     var array = cm.state.markedSelection;
     if (!array.length) return coverRange(cm, from, to);
 
     var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
-    if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||
+    if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE ||
         cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)
       return reset(cm);
 
     while (cmp(from, coverStart.from) > 0) {
       array.shift().clear();
       coverStart = array[0].find();
     }
     if (cmp(from, coverStart.from) < 0) {
--- a/devtools/client/sourceeditor/codemirror/addon/tern/tern.js
+++ b/devtools/client/sourceeditor/codemirror/addon/tern/tern.js
@@ -566,17 +566,17 @@
       var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize);
       if (indent <= minIndent) break;
     }
     var from = Pos(minLine, 0);
 
     return {type: "part",
             name: data.name,
             offsetLines: from.line,
-            text: doc.getRange(from, Pos(endLine, 0))};
+            text: doc.getRange(from, Pos(endLine, end.line == endLine ? null : 0))};
   }
 
   // Generic utilities
 
   var cmpPos = CodeMirror.cmpPos;
 
   function elt(tagname, cls /*, ... elts*/) {
     var e = document.createElement(tagname);
--- a/devtools/client/sourceeditor/codemirror/codemirror.bundle.js
+++ b/devtools/client/sourceeditor/codemirror/codemirror.bundle.js
@@ -515,23 +515,28 @@ var CodeMirror =
 
 	// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
 	function skipExtendingChars(str, pos, dir) {
 	  while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir }
 	  return pos
 	}
 
 	// Returns the value from the range [`from`; `to`] that satisfies
-	// `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`.
+	// `pred` and is closest to `from`. Assumes that at least `to`
+	// satisfies `pred`. Supports `from` being greater than `to`.
 	function findFirst(pred, from, to) {
+	  // At any point we are certain `to` satisfies `pred`, don't know
+	  // whether `from` does.
+	  var dir = from > to ? -1 : 1
 	  for (;;) {
-	    if (Math.abs(from - to) <= 1) { return pred(from) ? from : to }
-	    var mid = Math.floor((from + to) / 2)
+	    if (from == to) { return from }
+	    var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF)
+	    if (mid == from) { return pred(mid) ? from : to }
 	    if (pred(mid)) { to = mid }
-	    else { from = mid }
+	    else { from = mid + dir }
 	  }
 	}
 
 	// The display handles the DOM integration, both for input reading
 	// and content drawing. It holds references to DOM nodes and
 	// display-related state.
 
 	function Display(place, doc, input) {
@@ -1134,22 +1139,22 @@ var CodeMirror =
 	      d.maxLine = line
 	    }
 	  })
 	}
 
 	// BIDI HELPERS
 
 	function iterateBidiSections(order, from, to, f) {
-	  if (!order) { return f(from, to, "ltr") }
+	  if (!order) { return f(from, to, "ltr", 0) }
 	  var found = false
 	  for (var i = 0; i < order.length; ++i) {
 	    var part = order[i]
 	    if (part.from < to && part.to > from || from == to && part.to == from) {
-	      f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr")
+	      f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i)
 	      found = true
 	    }
 	  }
 	  if (!found) { f(from, to, "ltr") }
 	}
 
 	var bidiOther = null
 	function getBidiPartAt(order, ch, sticky) {
@@ -1342,122 +1347,16 @@ var CodeMirror =
 	// false for lines that are fully left-to-right, and an array of
 	// BidiSpan objects otherwise.
 	function getOrder(line, direction) {
 	  var order = line.order
 	  if (order == null) { order = line.order = bidiOrdering(line.text, direction) }
 	  return order
 	}
 
-	function moveCharLogically(line, ch, dir) {
-	  var target = skipExtendingChars(line.text, ch + dir, dir)
-	  return target < 0 || target > line.text.length ? null : target
-	}
-
-	function moveLogically(line, start, dir) {
-	  var ch = moveCharLogically(line, start.ch, dir)
-	  return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
-	}
-
-	function endOfLine(visually, cm, lineObj, lineNo, dir) {
-	  if (visually) {
-	    var order = getOrder(lineObj, cm.doc.direction)
-	    if (order) {
-	      var part = dir < 0 ? lst(order) : order[0]
-	      var moveInStorageOrder = (dir < 0) == (part.level == 1)
-	      var sticky = moveInStorageOrder ? "after" : "before"
-	      var ch
-	      // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
-	      // it could be that the last bidi part is not on the last visual line,
-	      // since visual lines contain content order-consecutive chunks.
-	      // Thus, in rtl, we are looking for the first (content-order) character
-	      // in the rtl chunk that is on the last line (that is, the same line
-	      // as the last (content-order) character).
-	      if (part.level > 0) {
-	        var prep = prepareMeasureForLine(cm, lineObj)
-	        ch = dir < 0 ? lineObj.text.length - 1 : 0
-	        var targetTop = measureCharPrepared(cm, prep, ch).top
-	        ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
-	        if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) }
-	      } else { ch = dir < 0 ? part.to : part.from }
-	      return new Pos(lineNo, ch, sticky)
-	    }
-	  }
-	  return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
-	}
-
-	function moveVisually(cm, line, start, dir) {
-	  var bidi = getOrder(line, cm.doc.direction)
-	  if (!bidi) { return moveLogically(line, start, dir) }
-	  if (start.ch >= line.text.length) {
-	    start.ch = line.text.length
-	    start.sticky = "before"
-	  } else if (start.ch <= 0) {
-	    start.ch = 0
-	    start.sticky = "after"
-	  }
-	  var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
-	  if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
-	    // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
-	    // nothing interesting happens.
-	    return moveLogically(line, start, dir)
-	  }
-
-	  var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }
-	  var prep
-	  var getWrappedLineExtent = function (ch) {
-	    if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
-	    prep = prep || prepareMeasureForLine(cm, line)
-	    return wrappedLineExtentChar(cm, line, prep, ch)
-	  }
-	  var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
-
-	  if (cm.doc.direction == "rtl" || part.level == 1) {
-	    var moveInStorageOrder = (part.level == 1) == (dir < 0)
-	    var ch = mv(start, moveInStorageOrder ? 1 : -1)
-	    if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
-	      // Case 2: We move within an rtl part or in an rtl editor on the same visual line
-	      var sticky = moveInStorageOrder ? "before" : "after"
-	      return new Pos(start.line, ch, sticky)
-	    }
-	  }
-
-	  // Case 3: Could not move within this bidi part in this visual line, so leave
-	  // the current bidi part
-
-	  var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
-	    var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
-	      ? new Pos(start.line, mv(ch, 1), "before")
-	      : new Pos(start.line, ch, "after"); }
-
-	    for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
-	      var part = bidi[partPos]
-	      var moveInStorageOrder = (dir > 0) == (part.level != 1)
-	      var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
-	      if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
-	      ch = moveInStorageOrder ? part.from : mv(part.to, -1)
-	      if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
-	    }
-	  }
-
-	  // Case 3a: Look for other bidi parts on the same visual line
-	  var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
-	  if (res) { return res }
-
-	  // Case 3b: Look for other bidi parts on the next visual line
-	  var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
-	  if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
-	    res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
-	    if (res) { return res }
-	  }
-
-	  // Case 4: Nowhere to move
-	  return null
-	}
-
 	// EVENT HANDLING
 
 	// Lightweight event framework. on/off also work on DOM nodes,
 	// registering native DOM handlers.
 
 	var noHandlers = []
 
 	var on = function(emitter, type, f) {
@@ -2956,25 +2855,32 @@ var CodeMirror =
 	  if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
 	  return window.pageXOffset || (document.documentElement || document.body).scrollLeft
 	}
 	function pageScrollY() {
 	  if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
 	  return window.pageYOffset || (document.documentElement || document.body).scrollTop
 	}
 
+	function widgetTopHeight(lineObj) {
+	  var height = 0
+	  if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
+	    { height += widgetHeight(lineObj.widgets[i]) } } }
+	  return height
+	}
+
 	// Converts a {top, bottom, left, right} box from line-local
 	// coordinates into another coordinate system. Context may be one of
 	// "line", "div" (display.lineDiv), "local"./null (editor), "window",
 	// or "page".
 	function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
-	  if (!includeWidgets && lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {
-	    var size = widgetHeight(lineObj.widgets[i])
-	    rect.top += size; rect.bottom += size
-	  } } }
+	  if (!includeWidgets) {
+	    var height = widgetTopHeight(lineObj)
+	    rect.top += height; rect.bottom += height
+	  }
 	  if (context == "line") { return rect }
 	  if (!context) { context = "local" }
 	  var yOff = heightAtLine(lineObj)
 	  if (context == "local") { yOff += paddingTop(cm.display) }
 	  else { yOff -= cm.display.viewOffset }
 	  if (context == "page" || context == "window") {
 	    var lOff = cm.display.lineSpace.getBoundingClientRect()
 	    yOff += lOff.top + (context == "window" ? 0 : pageScrollY())
@@ -3039,17 +2945,17 @@ var CodeMirror =
 	    sticky = "before"
 	  } else if (ch <= 0) {
 	    ch = 0
 	    sticky = "after"
 	  }
 	  if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
 
 	  function getBidi(ch, partPos, invert) {
-	    var part = order[partPos], right = (part.level % 2) != 0
+	    var part = order[partPos], right = part.level == 1
 	    return get(invert ? ch - 1 : ch, right != invert)
 	  }
 	  var partPos = getBidiPartAt(order, ch, sticky)
 	  var other = bidiOther
 	  var val = getBidi(ch, partPos, sticky == "before")
 	  if (other != null) { val.other = getBidi(ch, other, sticky != "before") }
 	  return val
 	}
@@ -3097,87 +3003,156 @@ var CodeMirror =
 	    if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
 	      { lineN = lineNo(lineObj = mergedPos.to.line) }
 	    else
 	      { return found }
 	  }
 	}
 
 	function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
-	  var measure = function (ch) { return intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line"); }
+	  y -= widgetTopHeight(lineObj)
 	  var end = lineObj.text.length
-	  var begin = findFirst(function (ch) { return measure(ch - 1).bottom <= y; }, end, 0)
-	  end = findFirst(function (ch) { return measure(ch).top > y; }, begin, end)
+	  var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0)
+	  end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end)
 	  return {begin: begin, end: end}
 	}
 
 	function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
+	  if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
 	  var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top
 	  return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
 	}
 
+	// Returns true if the given side of a box is after the given
+	// coordinates, in top-to-bottom, left-to-right order.
+	function boxIsAfter(box, x, y, left) {
+	  return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
+	}
+
 	function coordsCharInner(cm, lineObj, lineNo, x, y) {
+	  // Move y into line-local coordinate space
 	  y -= heightAtLine(lineObj)
-	  var begin = 0, end = lineObj.text.length
 	  var preparedMeasure = prepareMeasureForLine(cm, lineObj)
-	  var pos
+	  // When directly calling `measureCharPrepared`, we have to adjust
+	  // for the widgets at this line.
+	  var widgetHeight = widgetTopHeight(lineObj)
+	  var begin = 0, end = lineObj.text.length, ltr = true
+
 	  var order = getOrder(lineObj, cm.doc.direction)
+	  // If the line isn't plain left-to-right text, first figure out
+	  // which bidi section the coordinates fall into.
 	  if (order) {
-	    if (cm.options.lineWrapping) {
-	      ;var assign;
-	      ((assign = wrappedLineExtent(cm, lineObj, preparedMeasure, y), begin = assign.begin, end = assign.end, assign))
-	    }
-	    pos = new Pos(lineNo, Math.floor(begin + (end - begin) / 2))
-	    var beginLeft = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left
-	    var dir = beginLeft < x ? 1 : -1
-	    var prevDiff, diff = beginLeft - x, prevPos
-	    var steps = Math.ceil((end - begin) / 4)
-	    outer: do {
-	      prevDiff = diff
-	      prevPos = pos
-	      var i = 0
-	      for (; i < steps; ++i) {
-	        var prevPos$1 = pos
-	        pos = moveVisually(cm, lineObj, pos, dir)
-	        if (pos == null || pos.ch < begin || end <= (pos.sticky == "before" ? pos.ch - 1 : pos.ch)) {
-	          pos = prevPos$1
-	          break outer
-	        }
-	      }
-	      diff = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left - x
-	      if (steps > 1) {
-	        var diff_change_per_step = Math.abs(diff - prevDiff) / steps
-	        steps = Math.min(steps, Math.ceil(Math.abs(diff) / diff_change_per_step))
-	        dir = diff < 0 ? 1 : -1
-	      }
-	    } while (diff != 0 && (steps > 1 || ((dir < 0) != (diff < 0) && (Math.abs(diff) <= Math.abs(prevDiff)))))
-	    if (Math.abs(diff) > Math.abs(prevDiff)) {
-	      if ((diff < 0) == (prevDiff < 0)) { throw new Error("Broke out of infinite loop in coordsCharInner") }
-	      pos = prevPos
-	    }
+	    var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
+	                 (cm, lineObj, lineNo, preparedMeasure, order, x, y)
+	    ltr = part.level != 1
+	    // The awkward -1 offsets are needed because findFirst (called
+	    // on these below) will treat its first bound as inclusive,
+	    // second as exclusive, but we want to actually address the
+	    // characters in the part's range
+	    begin = ltr ? part.from : part.to - 1
+	    end = ltr ? part.to : part.from - 1
+	  }
+
+	  // A binary search to find the first character whose bounding box
+	  // starts after the coordinates. If we run across any whose box wrap
+	  // the coordinates, store that.
+	  var chAround = null, boxAround = null
+	  var ch = findFirst(function (ch) {
+	    var box = measureCharPrepared(cm, preparedMeasure, ch)
+	    box.top += widgetHeight; box.bottom += widgetHeight
+	    if (!boxIsAfter(box, x, y, false)) { return false }
+	    if (box.top <= y && box.left <= x) {
+	      chAround = ch
+	      boxAround = box
+	    }
+	    return true
+	  }, begin, end)
+
+	  var baseX, sticky, outside = false
+	  // If a box around the coordinates was found, use that
+	  if (boxAround) {
+	    // Distinguish coordinates nearer to the left or right side of the box
+	    var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr
+	    ch = chAround + (atStart ? 0 : 1)
+	    sticky = atStart ? "after" : "before"
+	    baseX = atLeft ? boxAround.left : boxAround.right
 	  } else {
-	    var ch = findFirst(function (ch) {
-	      var box = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line")
-	      if (box.top > y) {
-	        // For the cursor stickiness
-	        end = Math.min(ch, end)
-	        return true
-	      }
-	      else if (box.bottom <= y) { return false }
-	      else if (box.left > x) { return true }
-	      else if (box.right < x) { return false }
-	      else { return (x - box.left < box.right - x) }
-	    }, begin, end)
-	    ch = skipExtendingChars(lineObj.text, ch, 1)
-	    pos = new Pos(lineNo, ch, ch == end ? "before" : "after")
-	  }
-	  var coords = cursorCoords(cm, pos, "line", lineObj, preparedMeasure)
-	  if (y < coords.top || coords.bottom < y) { pos.outside = true }
-	  pos.xRel = x < coords.left ? -1 : (x > coords.right ? 1 : 0)
-	  return pos
+	    // (Adjust for extended bound, if necessary.)
+	    if (!ltr && (ch == end || ch == begin)) { ch++ }
+	    // To determine which side to associate with, get the box to the
+	    // left of the character and compare it's vertical position to the
+	    // coordinates
+	    sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
+	      (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?
+	      "after" : "before"
+	    // Now get accurate coordinates for this place, in order to get a
+	    // base X position
+	    var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure)
+	    baseX = coords.left
+	    outside = y < coords.top || y >= coords.bottom
+	  }
+
+	  ch = skipExtendingChars(lineObj.text, ch, 1)
+	  return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
+	}
+
+	function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
+	  // Bidi parts are sorted left-to-right, and in a non-line-wrapping
+	  // situation, we can take this ordering to correspond to the visual
+	  // ordering. This finds the first part whose end is after the given
+	  // coordinates.
+	  var index = findFirst(function (i) {
+	    var part = order[i], ltr = part.level != 1
+	    return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"),
+	                                   "line", lineObj, preparedMeasure), x, y, true)
+	  }, 0, order.length - 1)
+	  var part = order[index]
+	  // If this isn't the first part, the part's start is also after
+	  // the coordinates, and the coordinates aren't on the same line as
+	  // that start, move one part back.
+	  if (index > 0) {
+	    var ltr = part.level != 1
+	    var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"),
+	                             "line", lineObj, preparedMeasure)
+	    if (boxIsAfter(start, x, y, true) && start.top > y)
+	      { part = order[index - 1] }
+	  }
+	  return part
+	}
+
+	function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
+	  // In a wrapped line, rtl text on wrapping boundaries can do things
+	  // that don't correspond to the ordering in our `order` array at
+	  // all, so a binary search doesn't work, and we want to return a
+	  // part that only spans one line so that the binary search in
+	  // coordsCharInner is safe. As such, we first find the extent of the
+	  // wrapped line, and then do a flat search in which we discard any
+	  // spans that aren't on the line.
+	  var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
+	  var begin = ref.begin;
+	  var end = ref.end;
+	  var part = null, closestDist = null
+	  for (var i = 0; i < order.length; i++) {
+	    var p = order[i]
+	    if (p.from >= end || p.to <= begin) { continue }
+	    var ltr = p.level != 1
+	    var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right
+	    // Weigh against spans ending before this, so that they are only
+	    // picked if nothing ends after
+	    var dist = endX < x ? x - endX + 1e9 : endX - x
+	    if (!part || closestDist > dist) {
+	      part = p
+	      closestDist = dist
+	    }
+	  }
+	  if (!part) { part = order[order.length - 1] }
+	  // Clip the part to the wrapped line.
+	  if (part.from < begin) { part = {from: begin, to: part.to, level: part.level} }
+	  if (part.to > end) { part = {from: part.from, to: end, level: part.level} }
+	  return part
 	}
 
 	var measureText
 	// Compute the default text height.
 	function textHeight(display) {
 	  if (display.cachedTextHeight != null) { return display.cachedTextHeight }
 	  if (measureText == null) {
 	    measureText = elt("pre")
@@ -3293,22 +3268,24 @@ var CodeMirror =
 	  }
 	}
 
 	function updateSelection(cm) {
 	  cm.display.input.showSelection(cm.display.input.prepareSelection())
 	}
 
 	function prepareSelection(cm, primary) {
+	  if ( primary === void 0 ) primary = true;
+
 	  var doc = cm.doc, result = {}
 	  var curFragment = result.cursors = document.createDocumentFragment()
 	  var selFragment = result.selection = document.createDocumentFragment()
 
 	  for (var i = 0; i < doc.sel.ranges.length; i++) {
-	    if (primary === false && i == doc.sel.primIndex) { continue }
+	    if (!primary && i == doc.sel.primIndex) { continue }
 	    var range = doc.sel.ranges[i]
 	    if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
 	    var collapsed = range.empty()
 	    if (collapsed || cm.options.showCursorWhenSelecting)
 	      { drawSelectionCursor(cm, range.head, curFragment) }
 	    if (!collapsed)
 	      { drawSelectionRange(cm, range, selFragment) }
 	  }
@@ -3329,16 +3306,18 @@ var CodeMirror =
 	    var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"))
 	    otherCursor.style.display = ""
 	    otherCursor.style.left = pos.other.left + "px"
 	    otherCursor.style.top = pos.other.top + "px"
 	    otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"
 	  }
 	}
 
+	function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
+
 	// Draws the given range as a highlighted selection
 	function drawSelectionRange(cm, range, output) {
 	  var display = cm.display, doc = cm.doc
 	  var fragment = document.createDocumentFragment()
 	  var padding = paddingH(cm.display), leftSide = padding.left
 	  var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right
 
 	  function add(left, top, width, bottom) {
@@ -3351,40 +3330,58 @@ var CodeMirror =
 	  function drawForLine(line, fromArg, toArg) {
 	    var lineObj = getLine(doc, line)
 	    var lineLen = lineObj.text.length
 	    var start, end
 	    function coords(ch, bias) {
 	      return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
 	    }
 
-	    iterateBidiSections(getOrder(lineObj, doc.direction), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
-	      var leftPos = coords(from, "left"), rightPos, left, right
-	      if (from == to) {
-	        rightPos = leftPos
-	        left = right = leftPos.left
-	      } else {
-	        rightPos = coords(to - 1, "right")
-	        if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp }
-	        left = leftPos.left
-	        right = rightPos.right
-	      }
-	      if (fromArg == null && from == 0) { left = leftSide }
-	      if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
-	        add(left, leftPos.top, null, leftPos.bottom)
-	        left = leftSide
-	        if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top) }
-	      }
-	      if (toArg == null && to == lineLen) { right = rightSide }
-	      if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
-	        { start = leftPos }
-	      if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
-	        { end = rightPos }
-	      if (left < leftSide + 1) { left = leftSide }
-	      add(left, rightPos.top, right - left, rightPos.bottom)
+	    var order = getOrder(lineObj, doc.direction)
+	    iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
+	      var fromPos = coords(from, dir == "ltr" ? "left" : "right")
+	      var toPos = coords(to - 1, dir == "ltr" ? "right" : "left")
+	      if (dir == "ltr") {
+	        var fromLeft = fromArg == null && from == 0 ? leftSide : fromPos.left
+	        var toRight = toArg == null && to == lineLen ? rightSide : toPos.right
+	        if (toPos.top - fromPos.top <= 3) { // Single line
+	          add(fromLeft, toPos.top, toRight - fromLeft, toPos.bottom)
+	        } else { // Multiple lines
+	          add(fromLeft, fromPos.top, null, fromPos.bottom)
+	          if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
+	          add(leftSide, toPos.top, toPos.right, toPos.bottom)
+	        }
+	      } else if (from < to) { // RTL
+	        var fromRight = fromArg == null && from == 0 ? rightSide : fromPos.right
+	        var toLeft = toArg == null && to == lineLen ? leftSide : toPos.left
+	        if (toPos.top - fromPos.top <= 3) { // Single line
+	          add(toLeft, toPos.top, fromRight - toLeft, toPos.bottom)
+	        } else { // Multiple lines
+	          var topLeft = leftSide
+	          if (i) {
+	            var topEnd = wrappedLineExtentChar(cm, lineObj, null, from).end
+	            // The coordinates returned for an RTL wrapped space tend to
+	            // be complete bogus, so try to skip that here.
+	            topLeft = coords(topEnd - (/\s/.test(lineObj.text.charAt(topEnd - 1)) ? 2 : 1), "left").left
+	          }
+	          add(topLeft, fromPos.top, fromRight - topLeft, fromPos.bottom)
+	          if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
+	          var botWidth = null
+	          if (i < order.length  - 1 || true) {
+	            var botStart = wrappedLineExtentChar(cm, lineObj, null, to).begin
+	            botWidth = coords(botStart, "right").right - toLeft
+	          }
+	          add(toLeft, toPos.top, botWidth, toPos.bottom)
+	        }
+	      }
+
+	      if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos }
+	      if (cmpCoords(toPos, start) < 0) { start = toPos }
+	      if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos }
+	      if (cmpCoords(toPos, end) < 0) { end = toPos }
 	    })
 	    return {start: start, end: end}
 	  }
 
 	  var sFrom = range.from(), sTo = range.to()
 	  if (sFrom.line == sTo.line) {
 	    drawForLine(sFrom.line, sFrom.ch, sTo.ch)
 	  } else {
@@ -4004,30 +4001,30 @@ var CodeMirror =
 	    op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3
 	    cm.display.sizerWidth = op.adjustWidthTo
 	    op.barMeasure.scrollWidth =
 	      Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth)
 	    op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm))
 	  }
 
 	  if (op.updatedDisplay || op.selectionChanged)
-	    { op.preparedSelection = display.input.prepareSelection(op.focus) }
+	    { op.preparedSelection = display.input.prepareSelection() }
 	}
 
 	function endOperation_W2(op) {
 	  var cm = op.cm
 
 	  if (op.adjustWidthTo != null) {
 	    cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"
 	    if (op.maxScrollLeft < cm.doc.scrollLeft)
 	      { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) }
 	    cm.display.maxLineChanged = false
 	  }
 
-	  var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())
+	  var takeFocus = op.focus && op.focus == activeElt()
 	  if (op.preparedSelection)
 	    { cm.display.input.showSelection(op.preparedSelection, takeFocus) }
 	  if (op.updatedDisplay || op.startHeight != cm.doc.height)
 	    { updateScrollbars(cm, op.barMeasure) }
 	  if (op.updatedDisplay)
 	    { setDocumentHeight(cm, op.barMeasure) }
 
 	  if (op.selectionChanged) { restartBlink(cm) }
@@ -5606,17 +5603,18 @@ var CodeMirror =
 	    if (changeHandler) { signalLater(cm, "change", cm, obj) }
 	    if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj) }
 	  }
 	  cm.display.selForContextMenu = null
 	}
 
 	function replaceRange(doc, code, from, to, origin) {
 	  if (!to) { to = from }
-	  if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp }
+	  if (cmp(to, from) < 0) { var assign;
+	    (assign = [to, from], from = assign[0], to = assign[1], assign) }
 	  if (typeof code == "string") { code = doc.splitLines(code) }
 	  makeChange(doc, {from: from, to: to, text: code, origin: origin})
 	}
 
 	// Rebasing/resetting history to deal with externally-sourced changes
 
 	function rebaseHistSelSingle(pos, from, to, diff) {
 	  if (to < pos.line) {
@@ -6968,16 +6966,122 @@ var CodeMirror =
 	  // Next, remove those actual ranges.
 	  runInOp(cm, function () {
 	    for (var i = kill.length - 1; i >= 0; i--)
 	      { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") }
 	    ensureCursorVisible(cm)
 	  })
 	}
 
+	function moveCharLogically(line, ch, dir) {
+	  var target = skipExtendingChars(line.text, ch + dir, dir)
+	  return target < 0 || target > line.text.length ? null : target
+	}
+
+	function moveLogically(line, start, dir) {
+	  var ch = moveCharLogically(line, start.ch, dir)
+	  return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
+	}
+
+	function endOfLine(visually, cm, lineObj, lineNo, dir) {
+	  if (visually) {
+	    var order = getOrder(lineObj, cm.doc.direction)
+	    if (order) {
+	      var part = dir < 0 ? lst(order) : order[0]
+	      var moveInStorageOrder = (dir < 0) == (part.level == 1)
+	      var sticky = moveInStorageOrder ? "after" : "before"
+	      var ch
+	      // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
+	      // it could be that the last bidi part is not on the last visual line,
+	      // since visual lines contain content order-consecutive chunks.
+	      // Thus, in rtl, we are looking for the first (content-order) character
+	      // in the rtl chunk that is on the last line (that is, the same line
+	      // as the last (content-order) character).
+	      if (part.level > 0) {
+	        var prep = prepareMeasureForLine(cm, lineObj)
+	        ch = dir < 0 ? lineObj.text.length - 1 : 0
+	        var targetTop = measureCharPrepared(cm, prep, ch).top
+	        ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
+	        if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) }
+	      } else { ch = dir < 0 ? part.to : part.from }
+	      return new Pos(lineNo, ch, sticky)
+	    }
+	  }
+	  return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
+	}
+
+	function moveVisually(cm, line, start, dir) {
+	  var bidi = getOrder(line, cm.doc.direction)
+	  if (!bidi) { return moveLogically(line, start, dir) }
+	  if (start.ch >= line.text.length) {
+	    start.ch = line.text.length
+	    start.sticky = "before"
+	  } else if (start.ch <= 0) {
+	    start.ch = 0
+	    start.sticky = "after"
+	  }
+	  var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
+	  if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
+	    // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
+	    // nothing interesting happens.
+	    return moveLogically(line, start, dir)
+	  }
+
+	  var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }
+	  var prep
+	  var getWrappedLineExtent = function (ch) {
+	    if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
+	    prep = prep || prepareMeasureForLine(cm, line)
+	    return wrappedLineExtentChar(cm, line, prep, ch)
+	  }
+	  var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
+
+	  if (cm.doc.direction == "rtl" || part.level == 1) {
+	    var moveInStorageOrder = (part.level == 1) == (dir < 0)
+	    var ch = mv(start, moveInStorageOrder ? 1 : -1)
+	    if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
+	      // Case 2: We move within an rtl part or in an rtl editor on the same visual line
+	      var sticky = moveInStorageOrder ? "before" : "after"
+	      return new Pos(start.line, ch, sticky)
+	    }
+	  }
+
+	  // Case 3: Could not move within this bidi part in this visual line, so leave
+	  // the current bidi part
+
+	  var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
+	    var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
+	      ? new Pos(start.line, mv(ch, 1), "before")
+	      : new Pos(start.line, ch, "after"); }
+
+	    for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
+	      var part = bidi[partPos]
+	      var moveInStorageOrder = (dir > 0) == (part.level != 1)
+	      var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
+	      if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
+	      ch = moveInStorageOrder ? part.from : mv(part.to, -1)
+	      if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
+	    }
+	  }
+
+	  // Case 3a: Look for other bidi parts on the same visual line
+	  var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
+	  if (res) { return res }
+
+	  // Case 3b: Look for other bidi parts on the next visual line
+	  var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
+	  if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
+	    res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
+	    if (res) { return res }
+	  }
+
+	  // Case 4: Nowhere to move
+	  return null
+	}
+
 	// Commands are parameter-less actions that can be performed on an
 	// editor, mostly used for keybindings.
 	var commands = {
 	  selectAll: selectAll,
 	  singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
 	  killLine: function (cm) { return deleteNearSelection(cm, function (range) {
 	    if (range.empty()) {
 	      var len = getLine(cm.doc, range.head.line).text.length
@@ -7529,17 +7633,17 @@ var CodeMirror =
 	      if (cmp(range.anchor, anchor) > 0) {
 	        head = range.head
 	        anchor = minPos(oldRange.from(), range.anchor)
 	      } else {
 	        head = range.anchor
 	        anchor = maxPos(oldRange.to(), range.head)
 	      }
 	      var ranges$1 = startSel.ranges.slice(0)
-	      ranges$1[ourIndex] = new Range(clipPos(doc, anchor), head)
+	      ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head))
 	      setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse)
 	    }
 	  }
 
 	  var editorSize = display.wrapper.getBoundingClientRect()
 	  // Used to ensure timeout re-tries don't fire when another extend
 	  // happened in the meantime (clearTimeout isn't reliable -- at
 	  // least on Chrome, the timeouts still happen even when cleared,
@@ -7581,23 +7685,62 @@ var CodeMirror =
 	    else { extend(e) }
 	  })
 	  var up = operation(cm, done)
 	  cm.state.selectingText = up
 	  on(document, "mousemove", move)
 	  on(document, "mouseup", up)
 	}
 
+	// Used when mouse-selecting to adjust the anchor to the proper side
+	// of a bidi jump depending on the visual position of the head.
+	function bidiSimplify(cm, range) {
+	  var anchor = range.anchor;
+	  var head = range.head;
+	  var anchorLine = getLine(cm.doc, anchor.line)
+	  if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range }
+	  var order = getOrder(anchorLine)
+	  if (!order) { return range }
+	  var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]
+	  if (part.from != anchor.ch && part.to != anchor.ch) { return range }
+	  var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1)
+	  if (boundary == 0 || boundary == order.length) { return range }
+
+	  // Compute the relative visual position of the head compared to the
+	  // anchor (<0 is to the left, >0 to the right)
+	  var leftSide
+	  if (head.line != anchor.line) {
+	    leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0
+	  } else {
+	    var headIndex = getBidiPartAt(order, head.ch, head.sticky)
+	    var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1)
+	    if (headIndex == boundary - 1 || headIndex == boundary)
+	      { leftSide = dir < 0 }
+	    else
+	      { leftSide = dir > 0 }
+	  }
+
+	  var usePart = order[boundary + (leftSide ? -1 : 0)]
+	  var from = leftSide == (usePart.level == 1)
+	  var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"
+	  return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head)
+	}
+
 
 	// Determines whether an event happened in the gutter, and fires the
 	// handlers for the corresponding event.
 	function gutterEvent(cm, e, type, prevent) {
 	  var mX, mY
-	  try { mX = e.clientX; mY = e.clientY }
-	  catch(e) { return false }
+	  if (e.touches) {
+	    mX = e.touches[0].clientX
+	    mY = e.touches[0].clientY
+	  } else {
+	    try { mX = e.clientX; mY = e.clientY }
+	    catch(e) { return false }
+	  }
 	  if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
 	  if (prevent) { e_preventDefault(e) }
 
 	  var display = cm.display
 	  var lineBox = display.lineDiv.getBoundingClientRect()
 
 	  if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
 	  mY -= lineBox.top - display.viewOffset
@@ -7925,17 +8068,17 @@ var CodeMirror =
 	    return touch.radiusX <= 1 && touch.radiusY <= 1
 	  }
 	  function farAway(touch, other) {
 	    if (other.left == null) { return true }
 	    var dx = other.left - touch.left, dy = other.top - touch.top
 	    return dx * dx + dy * dy > 20 * 20
 	  }
 	  on(d.scroller, "touchstart", function (e) {
-	    if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
+	    if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
 	      d.input.ensurePolled()
 	      clearTimeout(touchFinished)
 	      var now = +new Date
 	      d.activeTouch = {start: now, moved: false,
 	                       prev: now - prevTouch.end <= 300 ? prevTouch : null}
 	      if (e.touches.length == 1) {
 	        d.activeTouch.left = e.touches[0].pageX
 	        d.activeTouch.top = e.touches[0].pageY
@@ -9709,17 +9852,17 @@ var CodeMirror =
 	CodeMirror.defineDocExtension = function (name, func) {
 	  Doc.prototype[name] = func
 	}
 
 	CodeMirror.fromTextArea = fromTextArea
 
 	addLegacyProps(CodeMirror)
 
-	CodeMirror.version = "5.29.0"
+	CodeMirror.version = "5.30.0"
 
 	return CodeMirror;
 
 	})));
 
 /***/ }),
 /* 3 */
 /***/ (function(module, exports, __webpack_require__) {
@@ -10148,16 +10291,17 @@ var CodeMirror =
 	      queryDialog = doc.createElement("div");
 	      queryDialog.appendChild(inp);
 	      queryDialog.style.display = "flex";
 	    }
 
 	    var state = getSearchState(cm);
 	    if (state.query) return findNext(cm, rev);
 	    var q = cm.getSelection() || state.lastQuery;
+	    if (q instanceof RegExp && q.source == "x^") q = null
 	    if (persistent && cm.openDialog) {
 	      var hiding = null
 	      var searchNext = function(query, event) {
 	        CodeMirror.e_stop(event);
 	        if (!query) return;
 	        if (query != state.queryText) {
 	          startSearch(cm, state, query);
 	          state.posFrom = state.posTo = cm.getCursor();
@@ -10457,31 +10601,36 @@ var CodeMirror =
 	  var Pos = CodeMirror.Pos;
 
 	  CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
 	    if (old && old != CodeMirror.Init) {
 	      cm.removeKeyMap(keyMap);
 	      cm.state.closeBrackets = null;
 	    }
 	    if (val) {
+	      ensureBound(getOption(val, "pairs"))
 	      cm.state.closeBrackets = val;
 	      cm.addKeyMap(keyMap);
 	    }
 	  });
 
 	  function getOption(conf, name) {
 	    if (name == "pairs" && typeof conf == "string") return conf;
 	    if (typeof conf == "object" && conf[name] != null) return conf[name];
 	    return defaults[name];
 	  }
 
-	  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) {
 	    return function(cm) { return handleChar(cm, ch); };
 	  }
 
 	  function getConfig(cm) {
 	    var deflt = cm.state.closeBrackets;
 	    if (!deflt || deflt.override) return deflt;
@@ -10889,17 +11038,17 @@ var CodeMirror =
 
 	  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 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,
+	      "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "void": C, "throw": C, "debugger": C,
 	      "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"),
 	      "in": operator, "typeof": operator, "instanceof": operator,
 	      "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
 	      "this": kw("this"), "class": kw("class"), "super": kw("atom"),
 	      "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
 	      "await": C
@@ -11259,17 +11408,17 @@ var CodeMirror =
 	  }
 	  function parenExpr(type) {
 	    if (type != "(") return pass()
 	    return cont(pushlex(")"), expression, expect(")"), poplex)
 	  }
 	  function expressionInner(type, noComma) {
 	    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);
 	    }
 
 	    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
 	    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
 	    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);
@@ -11304,16 +11453,21 @@ var CodeMirror =
 	      return cont(expr);
 	    }
 	    if (type == "quasi") { return pass(quasi, me); }
 	    if (type == ";") return;
 	    if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
 	    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) {
 	    if (type != "quasi") return pass();
 	    if (value.slice(value.length - 2) != "${") return cont(quasi);
 	    return cont(expression, continueQuasi);
 	  }
 	  function continueQuasi(type) {
 	    if (type == "}") {
@@ -11352,16 +11506,19 @@ var CodeMirror =
 	  }
 	  function objprop(type, value) {
 	    if (type == "async") {
 	      cx.marked = "property";
 	      return cont(objprop);
 	    } else if (type == "variable" || cx.style == "keyword") {
 	      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") {
 	      cx.marked = jsonldMode ? "property" : (cx.style + " property");
 	      return cont(afterprop);
 	    } else if (type == "jsonld-keyword") {
 	      return cont(afterprop);
 	    } else if (type == "modifier") {
 	      return cont(objprop)
@@ -11509,17 +11666,18 @@ var CodeMirror =
 	    if (type != ")") cont(expression);
 	  }
 	  function functiondef(type, value) {
 	    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);
 	    if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
 	  }
-	  function funarg(type) {
+	  function funarg(type, value) {
+	    if (value == "@") cont(expression, funarg)
 	    if (type == "spread" || type == "modifier") return cont(funarg);
 	    return pass(pattern, maybetype, maybeAssign);
 	  }
 	  function classExpression(type, value) {
 	    // Class expressions may have an optional name.
 	    if (type == "variable") return className(type, value);
 	    return classNameAfter(type, value);
 	  }
@@ -11535,17 +11693,17 @@ var CodeMirror =
 	  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") {
+	    if (type == "variable" || cx.style == "keyword") {
 	      cx.marked = "property";
 	      return cont(isTS ? classfield : functiondef, classBody);
 	    }
 	    if (type == "[")
 	      return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
 	    if (value == "*") {
 	      cx.marked = "keyword";
 	      return cont(classBody);
@@ -11597,17 +11755,17 @@ var CodeMirror =
 	  function isContinuedStatement(state, textAfter) {
 	    return state.lastType == "operator" || state.lastType == "," ||
 	      isOperatorChar.test(textAfter.charAt(0)) ||
 	      /[,.]/.test(textAfter.charAt(0));
 	  }
 
 	  function expressionAllowed(stream, state, backUp) {
 	    return state.tokenize == tokenBase &&
-	      /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
+	      /^(?:operator|sof|keyword [bc]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
 	      (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
 	  }
 
 	  // Interface
 
 	  return {
 	    startState: function(basecolumn) {
 	      var state = {
--- a/devtools/client/sourceeditor/codemirror/lib/codemirror.js
+++ b/devtools/client/sourceeditor/codemirror/lib/codemirror.js
@@ -273,23 +273,28 @@ function isExtendingChar(ch) { return ch
 
 // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
 function skipExtendingChars(str, pos, dir) {
   while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir }
   return pos
 }
 
 // Returns the value from the range [`from`; `to`] that satisfies
-// `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`.
+// `pred` and is closest to `from`. Assumes that at least `to`
+// satisfies `pred`. Supports `from` being greater than `to`.
 function findFirst(pred, from, to) {
+  // At any point we are certain `to` satisfies `pred`, don't know
+  // whether `from` does.
+  var dir = from > to ? -1 : 1
   for (;;) {
-    if (Math.abs(from - to) <= 1) { return pred(from) ? from : to }
-    var mid = Math.floor((from + to) / 2)
+    if (from == to) { return from }
+    var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF)
+    if (mid == from) { return pred(mid) ? from : to }
     if (pred(mid)) { to = mid }
-    else { from = mid }
+    else { from = mid + dir }
   }
 }
 
 // The display handles the DOM integration, both for input reading
 // and content drawing. It holds references to DOM nodes and
 // display-related state.
 
 function Display(place, doc, input) {
@@ -892,22 +897,22 @@ function findMaxLine(cm) {
       d.maxLine = line
     }
   })
 }
 
 // BIDI HELPERS
 
 function iterateBidiSections(order, from, to, f) {
-  if (!order) { return f(from, to, "ltr") }
+  if (!order) { return f(from, to, "ltr", 0) }
   var found = false
   for (var i = 0; i < order.length; ++i) {
     var part = order[i]
     if (part.from < to && part.to > from || from == to && part.to == from) {
-      f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr")
+      f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i)
       found = true
     }
   }
   if (!found) { f(from, to, "ltr") }
 }
 
 var bidiOther = null
 function getBidiPartAt(order, ch, sticky) {
@@ -1100,122 +1105,16 @@ var bidiOrdering = (function() {
 // false for lines that are fully left-to-right, and an array of
 // BidiSpan objects otherwise.
 function getOrder(line, direction) {
   var order = line.order
   if (order == null) { order = line.order = bidiOrdering(line.text, direction) }
   return order
 }
 
-function moveCharLogically(line, ch, dir) {
-  var target = skipExtendingChars(line.text, ch + dir, dir)
-  return target < 0 || target > line.text.length ? null : target
-}
-
-function moveLogically(line, start, dir) {
-  var ch = moveCharLogically(line, start.ch, dir)
-  return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
-}
-
-function endOfLine(visually, cm, lineObj, lineNo, dir) {
-  if (visually) {
-    var order = getOrder(lineObj, cm.doc.direction)
-    if (order) {
-      var part = dir < 0 ? lst(order) : order[0]
-      var moveInStorageOrder = (dir < 0) == (part.level == 1)
-      var sticky = moveInStorageOrder ? "after" : "before"
-      var ch
-      // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
-      // it could be that the last bidi part is not on the last visual line,
-      // since visual lines contain content order-consecutive chunks.
-      // Thus, in rtl, we are looking for the first (content-order) character
-      // in the rtl chunk that is on the last line (that is, the same line
-      // as the last (content-order) character).
-      if (part.level > 0) {
-        var prep = prepareMeasureForLine(cm, lineObj)
-        ch = dir < 0 ? lineObj.text.length - 1 : 0
-        var targetTop = measureCharPrepared(cm, prep, ch).top
-        ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
-        if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) }
-      } else { ch = dir < 0 ? part.to : part.from }
-      return new Pos(lineNo, ch, sticky)
-    }
-  }
-  return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
-}
-
-function moveVisually(cm, line, start, dir) {
-  var bidi = getOrder(line, cm.doc.direction)
-  if (!bidi) { return moveLogically(line, start, dir) }
-  if (start.ch >= line.text.length) {
-    start.ch = line.text.length
-    start.sticky = "before"
-  } else if (start.ch <= 0) {
-    start.ch = 0
-    start.sticky = "after"
-  }
-  var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
-  if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
-    // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
-    // nothing interesting happens.
-    return moveLogically(line, start, dir)
-  }
-
-  var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }
-  var prep
-  var getWrappedLineExtent = function (ch) {
-    if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
-    prep = prep || prepareMeasureForLine(cm, line)
-    return wrappedLineExtentChar(cm, line, prep, ch)
-  }
-  var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
-
-  if (cm.doc.direction == "rtl" || part.level == 1) {
-    var moveInStorageOrder = (part.level == 1) == (dir < 0)
-    var ch = mv(start, moveInStorageOrder ? 1 : -1)
-    if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
-      // Case 2: We move within an rtl part or in an rtl editor on the same visual line
-      var sticky = moveInStorageOrder ? "before" : "after"
-      return new Pos(start.line, ch, sticky)
-    }
-  }
-
-  // Case 3: Could not move within this bidi part in this visual line, so leave
-  // the current bidi part
-
-  var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
-    var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
-      ? new Pos(start.line, mv(ch, 1), "before")
-      : new Pos(start.line, ch, "after"); }
-
-    for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
-      var part = bidi[partPos]
-      var moveInStorageOrder = (dir > 0) == (part.level != 1)
-      var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
-      if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
-      ch = moveInStorageOrder ? part.from : mv(part.to, -1)
-      if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
-    }
-  }
-
-  // Case 3a: Look for other bidi parts on the same visual line
-  var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
-  if (res) { return res }
-
-  // Case 3b: Look for other bidi parts on the next visual line
-  var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
-  if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
-    res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
-    if (res) { return res }
-  }
-
-  // Case 4: Nowhere to move
-  return null
-}
-
 // EVENT HANDLING
 
 // Lightweight event framework. on/off also work on DOM nodes,
 // registering native DOM handlers.
 
 var noHandlers = []
 
 var on = function(emitter, type, f) {
@@ -2714,25 +2613,32 @@ function pageScrollX() {
   if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
   return window.pageXOffset || (document.documentElement || document.body).scrollLeft
 }
 function pageScrollY() {
   if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
   return window.pageYOffset || (document.documentElement || document.body).scrollTop
 }
 
+function widgetTopHeight(lineObj) {
+  var height = 0
+  if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
+    { height += widgetHeight(lineObj.widgets[i]) } } }
+  return height
+}
+
 // Converts a {top, bottom, left, right} box from line-local
 // coordinates into another coordinate system. Context may be one of
 // "line", "div" (display.lineDiv), "local"./null (editor), "window",
 // or "page".
 function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
-  if (!includeWidgets && lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {
-    var size = widgetHeight(lineObj.widgets[i])
-    rect.top += size; rect.bottom += size
-  } } }
+  if (!includeWidgets) {
+    var height = widgetTopHeight(lineObj)
+    rect.top += height; rect.bottom += height
+  }
   if (context == "line") { return rect }
   if (!context) { context = "local" }
   var yOff = heightAtLine(lineObj)
   if (context == "local") { yOff += paddingTop(cm.display) }
   else { yOff -= cm.display.viewOffset }
   if (context == "page" || context == "window") {
     var lOff = cm.display.lineSpace.getBoundingClientRect()
     yOff += lOff.top + (context == "window" ? 0 : pageScrollY())
@@ -2797,17 +2703,17 @@ function cursorCoords(cm, pos, context, 
     sticky = "before"
   } else if (ch <= 0) {
     ch = 0
     sticky = "after"
   }
   if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
 
   function getBidi(ch, partPos, invert) {
-    var part = order[partPos], right = (part.level % 2) != 0
+    var part = order[partPos], right = part.level == 1
     return get(invert ? ch - 1 : ch, right != invert)
   }
   var partPos = getBidiPartAt(order, ch, sticky)
   var other = bidiOther
   var val = getBidi(ch, partPos, sticky == "before")
   if (other != null) { val.other = getBidi(ch, other, sticky != "before") }
   return val
 }
@@ -2855,87 +2761,156 @@ function coordsChar(cm, x, y) {
     if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
       { lineN = lineNo(lineObj = mergedPos.to.line) }
     else
       { return found }
   }
 }
 
 function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
-  var measure = function (ch) { return intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line"); }
+  y -= widgetTopHeight(lineObj)
   var end = lineObj.text.length
-  var begin = findFirst(function (ch) { return measure(ch - 1).bottom <= y; }, end, 0)
-  end = findFirst(function (ch) { return measure(ch).top > y; }, begin, end)
+  var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0)
+  end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end)
   return {begin: begin, end: end}
 }
 
 function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
+  if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
   var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top
   return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
 }
 
+// Returns true if the given side of a box is after the given
+// coordinates, in top-to-bottom, left-to-right order.
+function boxIsAfter(box, x, y, left) {
+  return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
+}
+
 function coordsCharInner(cm, lineObj, lineNo, x, y) {
+  // Move y into line-local coordinate space
   y -= heightAtLine(lineObj)
-  var begin = 0, end = lineObj.text.length
   var preparedMeasure = prepareMeasureForLine(cm, lineObj)
-  var pos
+  // When directly calling `measureCharPrepared`, we have to adjust
+  // for the widgets at this line.
+  var widgetHeight = widgetTopHeight(lineObj)
+  var begin = 0, end = lineObj.text.length, ltr = true
+
   var order = getOrder(lineObj, cm.doc.direction)
+  // If the line isn't plain left-to-right text, first figure out
+  // which bidi section the coordinates fall into.
   if (order) {
-    if (cm.options.lineWrapping) {
-      ;var assign;
-      ((assign = wrappedLineExtent(cm, lineObj, preparedMeasure, y), begin = assign.begin, end = assign.end, assign))
-    }
-    pos = new Pos(lineNo, Math.floor(begin + (end - begin) / 2))
-    var beginLeft = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left
-    var dir = beginLeft < x ? 1 : -1
-    var prevDiff, diff = beginLeft - x, prevPos
-    var steps = Math.ceil((end - begin) / 4)
-    outer: do {
-      prevDiff = diff
-      prevPos = pos
-      var i = 0
-      for (; i < steps; ++i) {
-        var prevPos$1 = pos
-        pos = moveVisually(cm, lineObj, pos, dir)
-        if (pos == null || pos.ch < begin || end <= (pos.sticky == "before" ? pos.ch - 1 : pos.ch)) {
-          pos = prevPos$1
-          break outer
-        }
-      }
-      diff = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left - x
-      if (steps > 1) {
-        var diff_change_per_step = Math.abs(diff - prevDiff) / steps
-        steps = Math.min(steps, Math.ceil(Math.abs(diff) / diff_change_per_step))
-        dir = diff < 0 ? 1 : -1
-      }
-    } while (diff != 0 && (steps > 1 || ((dir < 0) != (diff < 0) && (Math.abs(diff) <= Math.abs(prevDiff)))))
-    if (Math.abs(diff) > Math.abs(prevDiff)) {
-      if ((diff < 0) == (prevDiff < 0)) { throw new Error("Broke out of infinite loop in coordsCharInner") }
-      pos = prevPos
-    }
+    var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
+                 (cm, lineObj, lineNo, preparedMeasure, order, x, y)
+    ltr = part.level != 1
+    // The awkward -1 offsets are needed because findFirst (called
+    // on these below) will treat its first bound as inclusive,
+    // second as exclusive, but we want to actually address the
+    // characters in the part's range
+    begin = ltr ? part.from : part.to - 1
+    end = ltr ? part.to : part.from - 1
+  }
+
+  // A binary search to find the first character whose bounding box
+  // starts after the coordinates. If we run across any whose box wrap
+  // the coordinates, store that.
+  var chAround = null, boxAround = null
+  var ch = findFirst(function (ch) {
+    var box = measureCharPrepared(cm, preparedMeasure, ch)
+    box.top += widgetHeight; box.bottom += widgetHeight
+    if (!boxIsAfter(box, x, y, false)) { return false }
+    if (box.top <= y && box.left <= x) {
+      chAround = ch
+      boxAround = box
+    }
+    return true
+  }, begin, end)
+
+  var baseX, sticky, outside = false
+  // If a box around the coordinates was found, use that
+  if (boxAround) {
+    // Distinguish coordinates nearer to the left or right side of the box
+    var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr
+    ch = chAround + (atStart ? 0 : 1)
+    sticky = atStart ? "after" : "before"
+    baseX = atLeft ? boxAround.left : boxAround.right
   } else {
-    var ch = findFirst(function (ch) {
-      var box = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line")
-      if (box.top > y) {
-        // For the cursor stickiness
-        end = Math.min(ch, end)
-        return true
-      }
-      else if (box.bottom <= y) { return false }
-      else if (box.left > x) { return true }
-      else if (box.right < x) { return false }
-      else { return (x - box.left < box.right - x) }
-    }, begin, end)
-    ch = skipExtendingChars(lineObj.text, ch, 1)
-    pos = new Pos(lineNo, ch, ch == end ? "before" : "after")
-  }
-  var coords = cursorCoords(cm, pos, "line", lineObj, preparedMeasure)
-  if (y < coords.top || coords.bottom < y) { pos.outside = true }
-  pos.xRel = x < coords.left ? -1 : (x > coords.right ? 1 : 0)
-  return pos
+    // (Adjust for extended bound, if necessary.)
+    if (!ltr && (ch == end || ch == begin)) { ch++ }
+    // To determine which side to associate with, get the box to the
+    // left of the character and compare it's vertical position to the
+    // coordinates
+    sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
+      (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?
+      "after" : "before"
+    // Now get accurate coordinates for this place, in order to get a
+    // base X position
+    var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure)
+    baseX = coords.left
+    outside = y < coords.top || y >= coords.bottom
+  }
+
+  ch = skipExtendingChars(lineObj.text, ch, 1)
+  return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
+}
+
+function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
+  // Bidi parts are sorted left-to-right, and in a non-line-wrapping
+  // situation, we can take this ordering to correspond to the visual
+  // ordering. This finds the first part whose end is after the given
+  // coordinates.
+  var index = findFirst(function (i) {
+    var part = order[i], ltr = part.level != 1
+    return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"),
+                                   "line", lineObj, preparedMeasure), x, y, true)
+  }, 0, order.length - 1)
+  var part = order[index]
+  // If this isn't the first part, the part's start is also after
+  // the coordinates, and the coordinates aren't on the same line as
+  // that start, move one part back.
+  if (index > 0) {
+    var ltr = part.level != 1
+    var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"),
+                             "line", lineObj, preparedMeasure)
+    if (boxIsAfter(start, x, y, true) && start.top > y)
+      { part = order[index - 1] }
+  }
+  return part
+}
+
+function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
+  // In a wrapped line, rtl text on wrapping boundaries can do things
+  // that don't correspond to the ordering in our `order` array at
+  // all, so a binary search doesn't work, and we want to return a
+  // part that only spans one line so that the binary search in
+  // coordsCharInner is safe. As such, we first find the extent of the
+  // wrapped line, and then do a flat search in which we discard any
+  // spans that aren't on the line.
+  var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
+  var begin = ref.begin;
+  var end = ref.end;
+  var part = null, closestDist = null
+  for (var i = 0; i < order.length; i++) {
+    var p = order[i]
+    if (p.from >= end || p.to <= begin) { continue }
+    var ltr = p.level != 1
+    var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right
+    // Weigh against spans ending before this, so that they are only
+    // picked if nothing ends after
+    var dist = endX < x ? x - endX + 1e9 : endX - x
+    if (!part || closestDist > dist) {
+      part = p
+      closestDist = dist
+    }
+  }
+  if (!part) { part = order[order.length - 1] }
+  // Clip the part to the wrapped line.
+  if (part.from < begin) { part = {from: begin, to: part.to, level: part.level} }
+  if (part.to > end) { part = {from: part.from, to: end, level: part.level} }
+  return part
 }
 
 var measureText
 // Compute the default text height.
 function textHeight(display) {
   if (display.cachedTextHeight != null) { return display.cachedTextHeight }
   if (measureText == null) {
     measureText = elt("pre")
@@ -3051,22 +3026,24 @@ function findViewIndex(cm, n) {
   }
 }
 
 function updateSelection(cm) {
   cm.display.input.showSelection(cm.display.input.prepareSelection())
 }
 
 function prepareSelection(cm, primary) {
+  if ( primary === void 0 ) primary = true;
+
   var doc = cm.doc, result = {}
   var curFragment = result.cursors = document.createDocumentFragment()
   var selFragment = result.selection = document.createDocumentFragment()
 
   for (var i = 0; i < doc.sel.ranges.length; i++) {
-    if (primary === false && i == doc.sel.primIndex) { continue }
+    if (!primary && i == doc.sel.primIndex) { continue }
     var range = doc.sel.ranges[i]
     if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
     var collapsed = range.empty()
     if (collapsed || cm.options.showCursorWhenSelecting)
       { drawSelectionCursor(cm, range.head, curFragment) }
     if (!collapsed)
       { drawSelectionRange(cm, range, selFragment) }
   }
@@ -3087,16 +3064,18 @@ function drawSelectionCursor(cm, head, o
     var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"))
     otherCursor.style.display = ""
     otherCursor.style.left = pos.other.left + "px"
     otherCursor.style.top = pos.other.top + "px"
     otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"
   }
 }
 
+function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
+
 // Draws the given range as a highlighted selection
 function drawSelectionRange(cm, range, output) {
   var display = cm.display, doc = cm.doc
   var fragment = document.createDocumentFragment()
   var padding = paddingH(cm.display), leftSide = padding.left
   var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right
 
   function add(left, top, width, bottom) {
@@ -3109,40 +3088,58 @@ function drawSelectionRange(cm, range, o
   function drawForLine(line, fromArg, toArg) {
     var lineObj = getLine(doc, line)
     var lineLen = lineObj.text.length
     var start, end
     function coords(ch, bias) {
       return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
     }
 
-    iterateBidiSections(getOrder(lineObj, doc.direction), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
-      var leftPos = coords(from, "left"), rightPos, left, right
-      if (from == to) {
-        rightPos = leftPos
-        left = right = leftPos.left
-      } else {
-        rightPos = coords(to - 1, "right")
-        if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp }
-        left = leftPos.left
-        right = rightPos.right
+    var order = getOrder(lineObj, doc.direction)
+    iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
+      var fromPos = coords(from, dir == "ltr" ? "left" : "right")
+      var toPos = coords(to - 1, dir == "ltr" ? "right" : "left")
+      if (dir == "ltr") {
+        var fromLeft = fromArg == null && from == 0 ? leftSide : fromPos.left
+        var toRight = toArg == null && to == lineLen ? rightSide : toPos.right
+        if (toPos.top - fromPos.top <= 3) { // Single line
+          add(fromLeft, toPos.top, toRight - fromLeft, toPos.bottom)
+        } else { // Multiple lines
+          add(fromLeft, fromPos.top, null, fromPos.bottom)
+          if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
+          add(leftSide, toPos.top, toPos.right, toPos.bottom)
+        }
+      } else if (from < to) { // RTL
+        var fromRight = fromArg == null && from == 0 ? rightSide : fromPos.right
+        var toLeft = toArg == null && to == lineLen ? leftSide : toPos.left
+        if (toPos.top - fromPos.top <= 3) { // Single line
+          add(toLeft, toPos.top, fromRight - toLeft, toPos.bottom)
+        } else { // Multiple lines
+          var topLeft = leftSide
+          if (i) {
+            var topEnd = wrappedLineExtentChar(cm, lineObj, null, from).end
+            // The coordinates returned for an RTL wrapped space tend to
+            // be complete bogus, so try to skip that here.
+            topLeft = coords(topEnd - (/\s/.test(lineObj.text.charAt(topEnd - 1)) ? 2 : 1), "left").left
+          }
+          add(topLeft, fromPos.top, fromRight - topLeft, fromPos.bottom)
+          if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
+          var botWidth = null
+          if (i < order.length  - 1 || true) {
+            var botStart = wrappedLineExtentChar(cm, lineObj, null, to).begin
+            botWidth = coords(botStart, "right").right - toLeft
+          }
+          add(toLeft, toPos.top, botWidth, toPos.bottom)
+        }
       }
-      if (fromArg == null && from == 0) { left = leftSide }
-      if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
-        add(left, leftPos.top, null, leftPos.bottom)
-        left = leftSide
-        if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top) }
-      }
-      if (toArg == null && to == lineLen) { right = rightSide }
-      if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
-        { start = leftPos }
-      if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
-        { end = rightPos }
-      if (left < leftSide + 1) { left = leftSide }
-      add(left, rightPos.top, right - left, rightPos.bottom)
+
+      if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos }
+      if (cmpCoords(toPos, start) < 0) { start = toPos }
+      if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos }
+      if (cmpCoords(toPos, end) < 0) { end = toPos }
     })
     return {start: start, end: end}
   }
 
   var sFrom = range.from(), sTo = range.to()
   if (sFrom.line == sTo.line) {
     drawForLine(sFrom.line, sFrom.ch, sTo.ch)
   } else {
@@ -3762,30 +3759,30 @@ function endOperation_R2(op) {
     op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3
     cm.display.sizerWidth = op.adjustWidthTo
     op.barMeasure.scrollWidth =
       Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth)
     op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm))
   }
 
   if (op.updatedDisplay || op.selectionChanged)
-    { op.preparedSelection = display.input.prepareSelection(op.focus) }
+    { op.preparedSelection = display.input.prepareSelection() }
 }
 
 function endOperation_W2(op) {
   var cm = op.cm
 
   if (op.adjustWidthTo != null) {
     cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"
     if (op.maxScrollLeft < cm.doc.scrollLeft)
       { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) }
     cm.display.maxLineChanged = false
   }
 
-  var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())
+  var takeFocus = op.focus && op.focus == activeElt()
   if (op.preparedSelection)
     { cm.display.input.showSelection(op.preparedSelection, takeFocus) }
   if (op.updatedDisplay || op.startHeight != cm.doc.height)
     { updateScrollbars(cm, op.barMeasure) }
   if (op.updatedDisplay)
     { setDocumentHeight(cm, op.barMeasure) }
 
   if (op.selectionChanged) { restartBlink(cm) }
@@ -5364,17 +5361,18 @@ function makeChangeSingleDocInEditor(cm,
     if (changeHandler) { signalLater(cm, "change", cm, obj) }
     if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj) }
   }
   cm.display.selForContextMenu = null
 }
 
 function replaceRange(doc, code, from, to, origin) {
   if (!to) { to = from }
-  if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp }
+  if (cmp(to, from) < 0) { var assign;
+    (assign = [to, from], from = assign[0], to = assign[1], assign) }
   if (typeof code == "string") { code = doc.splitLines(code) }
   makeChange(doc, {from: from, to: to, text: code, origin: origin})
 }
 
 // Rebasing/resetting history to deal with externally-sourced changes
 
 function rebaseHistSelSingle(pos, from, to, diff) {
   if (to < pos.line) {
@@ -6726,16 +6724,122 @@ function deleteNearSelection(cm, compute
   // Next, remove those actual ranges.
   runInOp(cm, function () {
     for (var i = kill.length - 1; i >= 0; i--)
       { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") }
     ensureCursorVisible(cm)
   })
 }
 
+function moveCharLogically(line, ch, dir) {
+  var target = skipExtendingChars(line.text, ch + dir, dir)
+  return target < 0 || target > line.text.length ? null : target
+}
+
+function moveLogically(line, start, dir) {
+  var ch = moveCharLogically(line, start.ch, dir)
+  return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
+}
+
+function endOfLine(visually, cm, lineObj, lineNo, dir) {
+  if (visually) {
+    var order = getOrder(lineObj, cm.doc.direction)
+    if (order) {
+      var part = dir < 0 ? lst(order) : order[0]
+      var moveInStorageOrder = (dir < 0) == (part.level == 1)
+      var sticky = moveInStorageOrder ? "after" : "before"
+      var ch
+      // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
+      // it could be that the last bidi part is not on the last visual line,
+      // since visual lines contain content order-consecutive chunks.
+      // Thus, in rtl, we are looking for the first (content-order) character
+      // in the rtl chunk that is on the last line (that is, the same line
+      // as the last (content-order) character).
+      if (part.level > 0) {
+        var prep = prepareMeasureForLine(cm, lineObj)
+        ch = dir < 0 ? lineObj.text.length - 1 : 0
+        var targetTop = measureCharPrepared(cm, prep, ch).top
+        ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch)
+        if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) }
+      } else { ch = dir < 0 ? part.to : part.from }
+      return new Pos(lineNo, ch, sticky)
+    }
+  }
+  return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
+}
+
+function moveVisually(cm, line, start, dir) {
+  var bidi = getOrder(line, cm.doc.direction)
+  if (!bidi) { return moveLogically(line, start, dir) }
+  if (start.ch >= line.text.length) {
+    start.ch = line.text.length
+    start.sticky = "before"
+  } else if (start.ch <= 0) {
+    start.ch = 0
+    start.sticky = "after"
+  }
+  var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]
+  if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
+    // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
+    // nothing interesting happens.
+    return moveLogically(line, start, dir)
+  }
+
+  var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }
+  var prep
+  var getWrappedLineExtent = function (ch) {
+    if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
+    prep = prep || prepareMeasureForLine(cm, line)
+    return wrappedLineExtentChar(cm, line, prep, ch)
+  }
+  var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch)
+
+  if (cm.doc.direction == "rtl" || part.level == 1) {
+    var moveInStorageOrder = (part.level == 1) == (dir < 0)
+    var ch = mv(start, moveInStorageOrder ? 1 : -1)
+    if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
+      // Case 2: We move within an rtl part or in an rtl editor on the same visual line
+      var sticky = moveInStorageOrder ? "before" : "after"
+      return new Pos(start.line, ch, sticky)
+    }
+  }
+
+  // Case 3: Could not move within this bidi part in this visual line, so leave
+  // the current bidi part
+
+  var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
+    var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
+      ? new Pos(start.line, mv(ch, 1), "before")
+      : new Pos(start.line, ch, "after"); }
+
+    for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
+      var part = bidi[partPos]
+      var moveInStorageOrder = (dir > 0) == (part.level != 1)
+      var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1)
+      if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
+      ch = moveInStorageOrder ? part.from : mv(part.to, -1)
+      if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
+    }
+  }
+
+  // Case 3a: Look for other bidi parts on the same visual line
+  var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent)
+  if (res) { return res }
+
+  // Case 3b: Look for other bidi parts on the next visual line
+  var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1)
+  if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
+    res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh))
+    if (res) { return res }
+  }
+
+  // Case 4: Nowhere to move
+  return null
+}
+
 // Commands are parameter-less actions that can be performed on an
 // editor, mostly used for keybindings.
 var commands = {
   selectAll: selectAll,
   singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
   killLine: function (cm) { return deleteNearSelection(cm, function (range) {
     if (range.empty()) {
       var len = getLine(cm.doc, range.head.line).text.length
@@ -7287,17 +7391,17 @@ function leftButtonSelect(cm, event, sta
       if (cmp(range.anchor, anchor) > 0) {
         head = range.head
         anchor = minPos(oldRange.from(), range.anchor)
       } else {
         head = range.anchor
         anchor = maxPos(oldRange.to(), range.head)
       }
       var ranges$1 = startSel.ranges.slice(0)
-      ranges$1[ourIndex] = new Range(clipPos(doc, anchor), head)
+      ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head))
       setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse)
     }
   }
 
   var editorSize = display.wrapper.getBoundingClientRect()
   // Used to ensure timeout re-tries don't fire when another extend
   // happened in the meantime (clearTimeout isn't reliable -- at
   // least on Chrome, the timeouts still happen even when cleared,
@@ -7339,23 +7443,62 @@ function leftButtonSelect(cm, event, sta
     else { extend(e) }
   })
   var up = operation(cm, done)
   cm.state.selectingText = up
   on(document, "mousemove", move)
   on(document, "mouseup", up)
 }
 
+// Used when mouse-selecting to adjust the anchor to the proper side
+// of a bidi jump depending on the visual position of the head.
+function bidiSimplify(cm, range) {
+  var anchor = range.anchor;
+  var head = range.head;
+  var anchorLine = getLine(cm.doc, anchor.line)
+  if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range }
+  var order = getOrder(anchorLine)
+  if (!order) { return range }
+  var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]
+  if (part.from != anchor.ch && part.to != anchor.ch) { return range }
+  var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1)
+  if (boundary == 0 || boundary == order.length) { return range }
+
+  // Compute the relative visual position of the head compared to the
+  // anchor (<0 is to the left, >0 to the right)
+  var leftSide
+  if (head.line != anchor.line) {
+    leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0
+  } else {
+    var headIndex = getBidiPartAt(order, head.ch, head.sticky)
+    var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1)
+    if (headIndex == boundary - 1 || headIndex == boundary)
+      { leftSide = dir < 0 }
+    else
+      { leftSide = dir > 0 }
+  }
+
+  var usePart = order[boundary + (leftSide ? -1 : 0)]
+  var from = leftSide == (usePart.level == 1)
+  var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"
+  return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head)
+}
+
 
 // Determines whether an event happened in the gutter, and fires the
 // handlers for the corresponding event.
 function gutterEvent(cm, e, type, prevent) {
   var mX, mY
-  try { mX = e.clientX; mY = e.clientY }
-  catch(e) { return false }
+  if (e.touches) {
+    mX = e.touches[0].clientX
+    mY = e.touches[0].clientY
+  } else {
+    try { mX = e.clientX; mY = e.clientY }
+    catch(e) { return false }
+  }
   if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
   if (prevent) { e_preventDefault(e) }
 
   var display = cm.display
   var lineBox = display.lineDiv.getBoundingClientRect()
 
   if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
   mY -= lineBox.top - display.viewOffset
@@ -7683,17 +7826,17 @@ function registerEventHandlers(cm) {
     return touch.radiusX <= 1 && touch.radiusY <= 1
   }
   function farAway(touch, other) {
     if (other.left == null) { return true }
     var dx = other.left - touch.left, dy = other.top - touch.top
     return dx * dx + dy * dy > 20 * 20
   }
   on(d.scroller, "touchstart", function (e) {
-    if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
+    if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
       d.input.ensurePolled()
       clearTimeout(touchFinished)
       var now = +new Date
       d.activeTouch = {start: now, moved: false,
                        prev: now - prevTouch.end <= 300 ? prevTouch : null}
       if (e.touches.length == 1) {
         d.activeTouch.left = e.touches[0].pageX
         d.activeTouch.top = e.touches[0].pageY
@@ -9467,13 +9610,13 @@ CodeMirror.defineExtension = function (n
 CodeMirror.defineDocExtension = function (name, func) {
   Doc.prototype[name] = func
 }
 
 CodeMirror.fromTextArea = fromTextArea
 
 addLegacyProps(CodeMirror)
 
-CodeMirror.version = "5.29.0"
+CodeMirror.version = "5.30.0"
 
 return CodeMirror;
 
 })));
\ No newline at end of file
--- a/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js
+++ b/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js
@@ -23,17 +23,17 @@ CodeMirror.defineMode("javascript", func
 
   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 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,
+      "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "void": C, "throw": C, "debugger": C,
       "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"),
       "in": operator, "typeof": operator, "instanceof": operator,
       "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
       "this": kw("this"), "class": kw("class"), "super": kw("atom"),
       "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
       "await": C
@@ -393,17 +393,17 @@ CodeMirror.defineMode("javascript", func
   }
   function parenExpr(type) {
     if (type != "(") return pass()
     return cont(pushlex(")"), expression, expect(")"), poplex)
   }
   function expressionInner(type, noComma) {
     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);
     }
 
     var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
     if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
     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);
@@ -438,16 +438,21 @@ CodeMirror.defineMode("javascript", func
       return cont(expr);
     }
     if (type == "quasi") { return pass(quasi, me); }
     if (type == ";") return;
     if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
     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) {
     if (type != "quasi") return pass();
     if (value.slice(value.length - 2) != "${") return cont(quasi);
     return cont(expression, continueQuasi);
   }
   function continueQuasi(type) {
     if (type == "}") {
@@ -486,16 +491,19 @@ CodeMirror.defineMode("javascript", func
   }
   function objprop(type, value) {
     if (type == "async") {
       cx.marked = "property";
       return cont(objprop);
     } else if (type == "variable" || cx.style == "keyword") {
       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") {
       cx.marked = jsonldMode ? "property" : (cx.style + " property");
       return cont(afterprop);
     } else if (type == "jsonld-keyword") {
       return cont(afterprop);
     } else if (type == "modifier") {
       return cont(objprop)
@@ -643,17 +651,18 @@ CodeMirror.defineMode("javascript", func
     if (type != ")") cont(expression);
   }
   function functiondef(type, value) {
     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);
     if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
   }
-  function funarg(type) {
+  function funarg(type, value) {
+    if (value == "@") cont(expression, funarg)
     if (type == "spread" || type == "modifier") return cont(funarg);
     return pass(pattern, maybetype, maybeAssign);
   }
   function classExpression(type, value) {
     // Class expressions may have an optional name.
     if (type == "variable") return className(type, value);
     return classNameAfter(type, value);
   }
@@ -669,17 +678,17 @@ CodeMirror.defineMode("javascript", func
   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") {
+    if (type == "variable" || cx.style == "keyword") {
       cx.marked = "property";
       return cont(isTS ? classfield : functiondef, classBody);
     }
     if (type == "[")
       return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
     if (value == "*") {
       cx.marked = "keyword";
       return cont(classBody);
@@ -731,17 +740,17 @@ CodeMirror.defineMode("javascript", func
   function isContinuedStatement(state, textAfter) {
     return state.lastType == "operator" || state.lastType == "," ||
       isOperatorChar.test(textAfter.charAt(0)) ||
       /[,.]/.test(textAfter.charAt(0));
   }
 
   function expressionAllowed(stream, state, backUp) {
     return state.tokenize == tokenBase &&
-      /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
+      /^(?:operator|sof|keyword [bc]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
       (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
   }
 
   // Interface
 
   return {
     startState: function(basecolumn) {
       var state = {
--- a/devtools/client/sourceeditor/test/codemirror/test.js
+++ b/devtools/client/sourceeditor/test/codemirror/test.js
@@ -249,16 +249,21 @@ testCM("coordsCharBidi", function(cm) {
         var coords = cm.charCoords(Pos(line, ch), sys);
         var pos = cm.coordsChar({left: coords.left + 1, top: coords.top + 1}, sys);
         eqCharPos(pos, Pos(line, ch));
       }
     }
   }
 }, {lineNumbers: true});
 
+testCM("badBidiOptimization", function(cm) {
+  var coords = cm.charCoords(Pos(0, 34))
+  eqCharPos(cm.coordsChar({left: coords.right, top: coords.top + 2}), Pos(0, 34))
+}, {value: "----------<p class=\"title\">هل يمكنك اختيار مستوى قسط التأمين الذي ترغب بدفعه؟</p>"})
+
 testCM("posFromIndex", function(cm) {
   cm.setValue(
     "This function should\n" +
     "convert a zero based index\n" +
     "to line and ch."
   );
 
   var examples = [
@@ -1151,16 +1156,26 @@ testCM("measureWrappedEndOfLine", functi
     if (i == 1) {
       var node = document.createElement("div");
       node.innerHTML = "hi"; node.style.height = "30px";
       cm.addLineWidget(0, node, {above: true});
     }
   }
 }, {mode: "text/html", value: "0123456789abcde0123456789", lineWrapping: true}, ie_lt8 || opera_lt10);
 
+testCM("measureEndOfLineBidi", function(cm) {
+  eqCursorPos(cm.coordsChar({left: 5000, top: cm.charCoords(Pos(0, 0)).top}), Pos(0, 8, "after"))
+}, {value: "إإإإuuuuإإإإ"})
+
+testCM("measureWrappedBidiLevel2", function(cm) {
+  cm.setSize(cm.charCoords(Pos(0, 6), "editor").right + 60)
+  var c9 = cm.charCoords(Pos(0, 9))
+  eqCharPos(cm.coordsChar({left: c9.right - 1, top: c9.top + 1}), Pos(0, 9))
+}, {value: "foobar إإ إإ إإ إإ 555 بببببب", lineWrapping: true})
+
 testCM("measureWrappedBeginOfLine", function(cm) {
   if (phantom) return;
   cm.setSize(null, "auto");
   var inner = byClassName(cm.getWrapperElement(), "CodeMirror-lines")[0].firstChild;
   var lh = inner.offsetHeight;
   for (var step = 10, w = cm.charCoords(Pos(0, 7), "div").right;; w += step) {
     cm.setSize(w);
     if (inner.offsetHeight < 2.5 * lh) {
@@ -2463,16 +2478,33 @@ function testCoordsWrappedBidi(str) {
 
 testCoordsWrappedBidi("Count ١ ٢ ٣ ٤");
 /*
 for (var i = 0; i < 5; ++i) {
   testCoordsWrappedBidi(getString(50));
 }
 */
 
+testCM("rtl_wrapped_selection", function(cm) {
+  cm.setSelection(Pos(0, 10), Pos(0, 190))
+  is(byClassName(cm.getWrapperElement(), "CodeMirror-selected").length >= 3)
+}, {value: new Array(10).join(" فتي تم تضمينها فتي تم"), lineWrapping: true})
+
+testCM("bidi_wrapped_selection", function(cm) {
+  if (phantom) return
+  cm.setSize(cm.charCoords(Pos(0, 10), "editor").left)
+  cm.setSelection(Pos(0, 37), Pos(0, 80))
+  var blocks = byClassName(cm.getWrapperElement(), "CodeMirror-selected")
+  is(blocks.length >= 2)
+  is(blocks.length <= 3)
+  var boxTop = blocks[0].getBoundingClientRect(), boxBot = blocks[blocks.length - 1].getBoundingClientRect()
+  is(boxTop.left > cm.charCoords(Pos(0, 1)).right)
+  is(boxBot.right < cm.charCoords(Pos(0, cm.getLine(0).length - 2)).left)
+}, {value: "<p>مفتي11 تم تضمينهفتي تم تضمينها فتي تفتي تم تضمينها فتي تفتي تم تضمينها فتي تفتي تم تضمينها فتي تا فت10ي ت</p>", lineWrapping: true})
+
 testCM("delete_wrapped", function(cm) {
   makeItWrapAfter(cm, Pos(0, 2));
   cm.doc.setCursor(Pos(0, 3, "after"));
   cm.deleteH(-1, "char");
   eq(cm.getLine(0), "1245");
 }, {value: "12345", lineWrapping: true})
 
 CodeMirror.defineMode("lookahead_mode", function() {
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ChildIterator.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/XBLChildrenElement.h"
 #include "mozilla/dom/HTMLContentElement.h"
-#include "mozilla/dom/HTMLShadowElement.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsIFrame.h"
 #include "nsCSSAnonBoxes.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -73,27 +72,16 @@ ExplicitChildIterator::GetNextChild()
     MOZ_ASSERT(!mDefaultChild);
 
     MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
     if (mIndexInInserted < assignedChildren.Length()) {
       return assignedChildren[mIndexInInserted++];
     }
     mIndexInInserted = 0;
     mChild = mChild->GetNextSibling();
-  } else if (mShadowIterator) {
-    // If we're inside of a <shadow> element, look through the
-    // explicit children of the projected ShadowRoot via
-    // the mShadowIterator.
-    nsIContent* nextChild = mShadowIterator->GetNextChild();
-    if (nextChild) {
-      return nextChild;
-    }
-
-    mShadowIterator = nullptr;
-    mChild = mChild->GetNextSibling();
   } else if (mDefaultChild) {
     // If we're already in default content, check if there are more nodes there
     MOZ_ASSERT(mChild);
     MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
 
     mDefaultChild = mDefaultChild->GetNextSibling();
     if (mDefaultChild) {
       return mDefaultChild;
@@ -105,33 +93,17 @@ ExplicitChildIterator::GetNextChild()
     mIsFirst = false;
   } else if (mChild) { // in the middle of the child list
     mChild = mChild->GetNextSibling();
   }
 
   // Iterate until we find a non-insertion point, or an insertion point with
   // content.
   while (mChild) {
-    // If the current child being iterated is a shadow insertion point then
-    // the iterator needs to go into the projected ShadowRoot.
-    if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
-      // Look for the next child in the projected ShadowRoot for the <shadow>
-      // element.
-      HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
-      ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
-      if (projectedShadow) {
-        mShadowIterator = new ExplicitChildIterator(projectedShadow);
-        nsIContent* nextChild = mShadowIterator->GetNextChild();
-        if (nextChild) {
-          return nextChild;
-        }
-        mShadowIterator = nullptr;
-      }
-      mChild = mChild->GetNextSibling();
-    } else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
+    if (nsContentUtils::IsContentInsertionPoint(mChild)) {
       // If the current child being iterated is a content insertion point
       // then the iterator needs to return the nodes distributed into
       // the content insertion point.
       MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
       if (!assignedChildren.IsEmpty()) {
         // Iterate through elements projected on insertion point.
         mIndexInInserted = 1;
         return assignedChildren[0];
@@ -191,21 +163,19 @@ FlattenedChildIterator::Init(bool aIgnor
 
 bool
 ExplicitChildIterator::Seek(nsIContent* aChildToFind)
 {
   if (aChildToFind->GetParent() == mParent &&
       !aChildToFind->IsRootOfAnonymousSubtree()) {
     // Fast path: just point ourselves to aChildToFind, which is a
     // normal DOM child of ours.
-    MOZ_ASSERT(!ShadowRoot::IsShadowInsertionPoint(aChildToFind));
     MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
     mChild = aChildToFind;
     mIndexInInserted = 0;
-    mShadowIterator = nullptr;
     mDefaultChild = nullptr;
     mIsFirst = false;
     return true;
   }
 
   // Can we add more fast paths here based on whether the parent of aChildToFind
   // is a shadow insertion point or content insertion point?
 
@@ -216,41 +186,33 @@ ExplicitChildIterator::Seek(nsIContent* 
 nsIContent*
 ExplicitChildIterator::Get() const
 {
   MOZ_ASSERT(!mIsFirst);
 
   if (mIndexInInserted) {
     MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
     return assignedChildren[mIndexInInserted - 1];
-  } else if (mShadowIterator)  {
-    return mShadowIterator->Get();
   }
+
   return mDefaultChild ? mDefaultChild : mChild;
 }
 
 nsIContent*
 ExplicitChildIterator::GetPreviousChild()
 {
   // If we're already in the inserted-children array, look there first
   if (mIndexInInserted) {
     // NB: mIndexInInserted points one past the last returned child so we need
     // to look *two* indices back in order to return the previous child.
     MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
     if (--mIndexInInserted) {
       return assignedChildren[mIndexInInserted - 1];
     }
     mChild = mChild->GetPreviousSibling();
-  } else if (mShadowIterator) {
-    nsIContent* previousChild = mShadowIterator->GetPreviousChild();
-    if (previousChild) {
-      return previousChild;
-    }
-    mShadowIterator = nullptr;
-    mChild = mChild->GetPreviousSibling();
   } else if (mDefaultChild) {
     // If we're already in default content, check if there are more nodes there
     mDefaultChild = mDefaultChild->GetPreviousSibling();
     if (mDefaultChild) {
       return mDefaultChild;
     }
 
     mChild = mChild->GetPreviousSibling();
@@ -260,32 +222,17 @@ ExplicitChildIterator::GetPreviousChild(
     mChild = mChild->GetPreviousSibling();
   } else { // at the end of the child list
     mChild = mParent->GetLastChild();
   }
 
   // Iterate until we find a non-insertion point, or an insertion point with
   // content.
   while (mChild) {
-    if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
-      // If the current child being iterated is a shadow insertion point then
-      // the iterator needs to go into the projected ShadowRoot.
-      HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
-      ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
-      if (projectedShadow) {
-        // Create a ExplicitChildIterator that begins iterating from the end.
-        mShadowIterator = new ExplicitChildIterator(projectedShadow, false);
-        nsIContent* previousChild = mShadowIterator->GetPreviousChild();
-        if (previousChild) {
-          return previousChild;
-        }
-        mShadowIterator = nullptr;
-      }
-      mChild = mChild->GetPreviousSibling();
-    } else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
+    if (nsContentUtils::IsContentInsertionPoint(mChild)) {
       // If the current child being iterated is a content insertion point
       // then the iterator needs to return the nodes distributed into
       // the content insertion point.
       MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
       if (!assignedChildren.IsEmpty()) {
         mIndexInInserted = assignedChildren.Length();
         return assignedChildren[mIndexInInserted - 1];
       }
--- a/dom/base/ChildIterator.h
+++ b/dom/base/ChildIterator.h
@@ -43,26 +43,22 @@ public:
       mIsFirst(aStartAtBeginning),
       mIndexInInserted(0)
   {
   }
 
   ExplicitChildIterator(const ExplicitChildIterator& aOther)
     : mParent(aOther.mParent), mChild(aOther.mChild),
       mDefaultChild(aOther.mDefaultChild),
-      mShadowIterator(aOther.mShadowIterator ?
-                      new ExplicitChildIterator(*aOther.mShadowIterator) :
-                      nullptr),
       mIsFirst(aOther.mIsFirst),
       mIndexInInserted(aOther.mIndexInInserted) {}
 
   ExplicitChildIterator(ExplicitChildIterator&& aOther)
     : mParent(aOther.mParent), mChild(aOther.mChild),
       mDefaultChild(aOther.mDefaultChild),
-      mShadowIterator(Move(aOther.mShadowIterator)),
       mIsFirst(aOther.mIsFirst),
       mIndexInInserted(aOther.mIndexInInserted) {}
 
   nsIContent* GetNextChild();
 
   // Looks for aChildToFind respecting insertion points until aChildToFind is
   // found.  This version can take shortcuts that the two-argument version
   // can't, so can be faster (and in fact can be O(1) instead of O(N) in many
@@ -111,21 +107,16 @@ protected:
   nsIContent* mChild;
 
   // If non-null, this points to the current default content for the current
   // insertion point that we're iterating (i.e. mChild, which must be an
   // nsXBLChildrenElement or HTMLContentElement). Once this transitions back
   // to null, we continue iterating at mChild's next sibling.
   nsIContent* mDefaultChild;
 
-  // If non-null, this points to an iterator of the explicit children of
-  // the ShadowRoot projected by the current shadow element that we're
-  // iterating.
-  nsAutoPtr<ExplicitChildIterator> mShadowIterator;
-
   // A flag to let us know that we haven't started iterating yet.
   bool mIsFirst;
 
   // If not zero, we're iterating inserted children for an insertion point. This
   // is an index into mChild's inserted children array (mChild must be an
   // nsXBLChildrenElement). The index is one past the "current" child (as
   // opposed to mChild which represents the "current" child).
   uint32_t mIndexInInserted;
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -934,17 +934,17 @@ DoUpgrade(Element* aElement,
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 }
 
 } // anonymous namespace
 
 // https://html.spec.whatwg.org/multipage/scripting.html#upgrades
-void
+/* static */ void
 CustomElementRegistry::Upgrade(Element* aElement,
                                CustomElementDefinition* aDefinition,
                                ErrorResult& aRv)
 {
   aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
 
   RefPtr<CustomElementData> data = aElement->GetCustomElementData();
   MOZ_ASSERT(data, "CustomElementData should exist");
@@ -972,18 +972,20 @@ CustomElementRegistry::Upgrade(Element* 
                                                             namespaceURI);
 
         LifecycleCallbackArgs args = {
           nsDependentAtomString(attrName),
           VoidString(),
           (attrValue.IsEmpty() ? VoidString() : attrValue),
           (namespaceURI.IsEmpty() ? VoidString() : namespaceURI)
         };
-        EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, aElement,
-                                 &args, aDefinition);
+        nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
+                                                 nsIDocument::eAttributeChanged,
+                                                 aElement,
+                                                 &args, aDefinition);
       }
     }
   }
 
   // Step 4.
   // TODO: Bug 1334043 - Implement connected lifecycle callbacks for custom elements
 
   // Step 5.
@@ -998,17 +1000,19 @@ CustomElementRegistry::Upgrade(Element* 
     data->mReactionQueue.Clear();
     return;
   }
 
   // Step 8.
   data->mState = CustomElementData::State::eCustom;
 
   // This is for old spec.
-  EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition);
+  nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
+                                           nsIDocument::eCreated,
+                                           aElement, nullptr, aDefinition);
 }
 
 //-----------------------------------------------------
 // CustomElementReactionsStack
 
 void
 CustomElementReactionsStack::CreateAndPushElementQueue()
 {
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -357,32 +357,33 @@ public:
   void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
                                 Element* aCustomElement,
                                 LifecycleCallbackArgs* aArgs,
                                 CustomElementDefinition* aDefinition);
 
   void GetCustomPrototype(nsIAtom* aAtom,
                           JS::MutableHandle<JSObject*> aPrototype);
 
+  void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
+                           Element* aCustomElement,
+                           CustomElementDefinition* aDefinition);
+
   /**
    * Upgrade an element.
    * https://html.spec.whatwg.org/multipage/scripting.html#upgrades
    */
-  void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv);
+  static void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv);
 
 private:
   ~CustomElementRegistry();
 
   UniquePtr<CustomElementCallback> CreateCustomElementCallback(
     nsIDocument::ElementCallbackType aType, Element* aCustomElement,
     LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition);
 
-  void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
-                           Element* aCustomElement,
-                           CustomElementDefinition* aDefinition);
   /**
    * Registers an unresolved custom element that is a candidate for
    * upgrade when the definition is registered via registerElement.
    * |aTypeName| is the name of the custom element type, if it is not
    * provided, then element name is used. |aTypeName| should be provided
    * when registering a custom element that extends an existing
    * element. e.g. <button is="x-button">.
    */
--- a/dom/base/DocumentFragment.cpp
+++ b/dom/base/DocumentFragment.cpp
@@ -106,19 +106,17 @@ DocumentFragment::Constructor(const Glob
   if (!window || !window->GetDoc()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return window->GetDoc()->CreateDocumentFragment();
 }
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(DocumentFragment,
-                                   FragmentOrElement,
-                                   mHost)
+NS_IMPL_CYCLE_COLLECTION_INHERITED(DocumentFragment, FragmentOrElement, mHost)
 
 // QueryInterface implementation for DocumentFragment
 NS_INTERFACE_MAP_BEGIN(DocumentFragment)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(DocumentFragment)
   NS_INTERFACE_MAP_ENTRY(nsIContent)
   NS_INTERFACE_MAP_ENTRY(nsINode)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentFragment)
--- a/dom/base/DocumentFragment.h
+++ b/dom/base/DocumentFragment.h
@@ -38,18 +38,17 @@ public:
   using FragmentOrElement::GetFirstChild;
   using nsINode::QuerySelector;
   using nsINode::QuerySelectorAll;
   // Make sure bindings can see our superclass' protected GetElementById method.
   using nsINode::GetElementById;
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment,
-                                           FragmentOrElement)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment, FragmentOrElement)
 
   // interface nsIDOMNode
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
   // interface nsIDOMDocumentFragment
   NS_DECL_NSIDOMDOCUMENTFRAGMENT
 
   explicit DocumentFragment(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
@@ -117,25 +116,19 @@ public:
     NS_ASSERTION(false, "Trying to unbind a fragment from a tree");
   }
 
   virtual Element* GetNameSpaceElement() override
   {
     return nullptr;
   }
 
-  Element* GetHost() const
-  {
-    return mHost;
-  }
+  Element* GetHost() const { return mHost; }
 
-  void SetHost(Element* aHost)
-  {
-    mHost = aHost;
-  }
+  void SetHost(Element* aHost) { mHost = aHost; }
 
   static already_AddRefed<DocumentFragment>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
 
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const override;
   virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;
 #endif
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1101,16 +1101,21 @@ Element::RemoveFromIdTable()
       doc->RemoveFromIdTable(this, id);
     }
   }
 }
 
 already_AddRefed<ShadowRoot>
 Element::CreateShadowRoot(ErrorResult& aError)
 {
+  if (GetShadowRoot()) {
+    aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+
   nsAutoScriptBlocker scriptBlocker;
 
   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
   nodeInfo = mNodeInfo->NodeInfoManager()->GetNodeInfo(
     nsGkAtoms::documentFragmentNodeName, nullptr, kNameSpaceID_None,
     nsIDOMNode::DOCUMENT_FRAGMENT_NODE);
 
   RefPtr<nsXBLDocumentInfo> docInfo = new nsXBLDocumentInfo(OwnerDoc());
@@ -1137,34 +1142,17 @@ Element::CreateShadowRoot(ErrorResult& a
   // Calling SetPrototypeBinding takes ownership of protoBinding.
   docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
 
   RefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
                                                    protoBinding);
 
   shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
 
-  // Replace the old ShadowRoot with the new one and let the old
-  // ShadowRoot know about the younger ShadowRoot because the old
-  // ShadowRoot is projected into the younger ShadowRoot's shadow
-  // insertion point (if it exists).
-  ShadowRoot* olderShadow = GetShadowRoot();
   SetShadowRoot(shadowRoot);
-  if (olderShadow) {
-    olderShadow->SetYoungerShadow(shadowRoot);
-
-    // Unbind children of older shadow root because they
-    // are no longer in the composed tree.
-    for (nsIContent* child = olderShadow->GetFirstChild(); child;
-         child = child->GetNextSibling()) {
-      child->UnbindFromTree(true, false);
-    }
-
-    olderShadow->SetIsComposedDocParticipant(false);
-  }
 
   // xblBinding takes ownership of docInfo.
   RefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
   shadowRoot->SetAssociatedBinding(xblBinding);
   xblBinding->SetBoundElement(this);
 
   SetXBLBinding(xblBinding);
   return shadowRoot.forget();
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1042,33 +1042,20 @@ nsIContent::GetEventTargetParent(EventCh
   }
 
   nsIContent* parent = GetParent();
 
   // Web components have a special event chain that need to account
   // for destination insertion points where nodes have been distributed.
   nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints();
   if (destPoints && !destPoints->IsEmpty()) {
-    // Push destination insertion points to aVisitor.mDestInsertionPoints
-    // excluding shadow insertion points.
-    bool didPushNonShadowInsertionPoint = false;
+    // Push destination insertion points to aVisitor.mDestInsertionPoints.
     for (uint32_t i = 0; i < destPoints->Length(); i++) {
       nsIContent* point = destPoints->ElementAt(i);
-      if (!ShadowRoot::IsShadowInsertionPoint(point)) {
-        aVisitor.mDestInsertionPoints.AppendElement(point);
-        didPushNonShadowInsertionPoint = true;
-      }
-    }
-
-    // Next node in the event path is the final destination
-    // (non-shadow) insertion point that was pushed.
-    if (didPushNonShadowInsertionPoint) {
-      parent = aVisitor.mDestInsertionPoints.LastElement();
-      aVisitor.mDestInsertionPoints.SetLength(
-        aVisitor.mDestInsertionPoints.Length() - 1);
+      aVisitor.mDestInsertionPoints.AppendElement(point);
     }
   }
 
   ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
   if (thisShadowRoot) {
     if (!aVisitor.mEvent->mFlags.mComposed) {
       // If we do stop propagation, we still want to propagate
       // the event to chrome (nsPIDOMWindow::GetParentTarget()).
@@ -1082,20 +1069,17 @@ nsIContent::GetEventTargetParent(EventCh
       return NS_OK;
     }
 
     if (!aVisitor.mDestInsertionPoints.IsEmpty()) {
       parent = aVisitor.mDestInsertionPoints.LastElement();
       aVisitor.mDestInsertionPoints.SetLength(
         aVisitor.mDestInsertionPoints.Length() - 1);
     } else {
-      // The pool host for the youngest shadow root is shadow DOM host,
-      // for older shadow roots, it is the shadow insertion point
-      // where the shadow root is projected, nullptr if none exists.
-      parent = thisShadowRoot->GetPoolHost();
+      parent = thisShadowRoot->GetHost();
     }
   }
 
   // Event may need to be retargeted if this is the root of a native
   // anonymous content subtree or event is dispatched somewhere inside XBL.
   if (isAnonForEvents) {
 #ifdef DEBUG
     // If a DOM event is explicitly dispatched using node.dispatchEvent(), then
@@ -2614,13 +2598,12 @@ FragmentOrElement::SetIsElementInStyleSc
 }
 
 void
 FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
 {
   NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
                             "on a non-Element is useless");
   ShadowRoot* shadowRoot = GetShadowRoot();
-  while (shadowRoot) {
+  if (shadowRoot) {
     shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
-    shadowRoot = shadowRoot->GetOlderShadowRoot();
   }
 }
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -10,99 +10,90 @@
 #include "mozilla/dom/DocumentFragment.h"
 #include "ChildIterator.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLContentElement.h"
-#include "mozilla/dom/HTMLShadowElement.h"
 #include "nsXBLPrototypeBinding.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
                                                   DocumentFragment)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
   for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
        iter.Next()) {
     iter.Get()->Traverse(&cb);
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
-                                                DocumentFragment)
-  if (tmp->mPoolHost) {
-    tmp->mPoolHost->RemoveMutationObserver(tmp);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
+  if (tmp->GetHost()) {
+    tmp->GetHost()->RemoveMutationObserver(tmp);
   }
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
   tmp->mIdentifierMap.Clear();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
 NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
 
 NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
 NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
 
 ShadowRoot::ShadowRoot(Element* aElement,
                        already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                        nsXBLPrototypeBinding* aProtoBinding)
-  : DocumentFragment(aNodeInfo), mPoolHost(aElement),
-    mProtoBinding(aProtoBinding), mShadowElement(nullptr),
-    mInsertionPointChanged(false), mIsComposedDocParticipant(false)
+  : DocumentFragment(aNodeInfo)
+  , mProtoBinding(aProtoBinding)
+  , mInsertionPointChanged(false)
+  , mIsComposedDocParticipant(false)
 {
   SetHost(aElement);
 
   // Nodes in a shadow tree should never store a value
   // in the subtree root pointer, nodes in the shadow tree
   // track the subtree root using GetContainingShadow().
   ClearSubtreeRootPointer();
 
   SetFlags(NODE_IS_IN_SHADOW_TREE);
 
   ExtendedDOMSlots()->mBindingParent = aElement;
   ExtendedDOMSlots()->mContainingShadow = this;
 
   // Add the ShadowRoot as a mutation observer on the host to watch
   // for mutations because the insertion points in this ShadowRoot
   // may need to be updated when the host children are modified.
-  mPoolHost->AddMutationObserver(this);
+  GetHost()->AddMutationObserver(this);
 }
 
 ShadowRoot::~ShadowRoot()
 {
-  if (mPoolHost) {
+  if (GetHost()) {
     // mPoolHost may have been unlinked or a new ShadowRoot may have been
     // creating, making this one obsolete.
-    mPoolHost->RemoveMutationObserver(this);
+    GetHost()->RemoveMutationObserver(this);
   }
 
   UnsetFlags(NODE_IS_IN_SHADOW_TREE);
 
   // nsINode destructor expects mSubtreeRoot == this.
   SetSubtreeRootPointer(this);
-
-  SetHost(nullptr);
 }
 
 JSObject*
 ShadowRoot::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::ShadowRootBinding::Wrap(aCx, this, aGivenProto);
 }
 
@@ -239,25 +230,16 @@ ShadowRoot::AddInsertionPoint(HTMLConten
 
 void
 ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
 {
   mInsertionPoints.RemoveElement(aInsertionPoint);
 }
 
 void
-ShadowRoot::SetYoungerShadow(ShadowRoot* aYoungerShadow)
-{
-  mYoungerShadow = aYoungerShadow;
-  mYoungerShadow->mOlderShadow = this;
-
-  ChangePoolHost(mYoungerShadow->GetShadowElement());
-}
-
-void
 ShadowRoot::RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
                                      nsTArray<nsIContent*>& aDestInsertionPoints)
 {
   // Remove the insertion point from the destination insertion points.
   // Also remove all succeeding insertion points because it is no longer
   // possible for the content to be distributed into deeper node trees.
   int32_t index = aDestInsertionPoints.IndexOf(aInsertionPoint);
 
@@ -295,18 +277,17 @@ ShadowRoot::DistributeSingleNode(nsICont
   }
 
   // Find the index into the insertion point.
   if (insertionPoint) {
     nsCOMArray<nsIContent>& matchedNodes = insertionPoint->MatchedNodes();
     // Find the appropriate position in the matched node list for the
     // newly distributed content.
     bool isIndexFound = false;
-    MOZ_ASSERT(mPoolHost, "Where did the content come from if there is no pool host?");
-    ExplicitChildIterator childIterator(mPoolHost);
+    ExplicitChildIterator childIterator(GetHost());
     for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
       // Seek through the host's explicit children until the inserted content
       // is found or when the current matched node is reached.
       if (childIterator.Seek(aContent, matchedNodes[i])) {
         // aContent was found before the current matched node.
         insertionPoint->InsertMatchedNode(i, aContent);
         isIndexFound = true;
         break;
@@ -316,42 +297,23 @@ ShadowRoot::DistributeSingleNode(nsICont
     if (!isIndexFound) {
       // We have still not found an index in the insertion point,
       // thus it must be at the end.
       MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
                  "Trying to match a node that is not a candidate to be matched");
       insertionPoint->AppendMatchedNode(aContent);
     }
 
-    // Handle the case where the parent of the insertion point is a ShadowRoot
-    // that is projected into the younger ShadowRoot's shadow insertion point.
-    // The node distributed into the insertion point must be reprojected
-    // to the shadow insertion point.
-    if (insertionPoint->GetParent() == this &&
-        mYoungerShadow && mYoungerShadow->GetShadowElement()) {
-      mYoungerShadow->GetShadowElement()->DistributeSingleNode(aContent);
-    }
-
     // Handle the case where the parent of the insertion point has a ShadowRoot.
     // The node distributed into the insertion point must be reprojected to the
     // insertion points of the parent's ShadowRoot.
     ShadowRoot* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
     if (parentShadow) {
       parentShadow->DistributeSingleNode(aContent);
     }
-
-    // Handle the case where the parent of the insertion point is the <shadow>
-    // element. The node distributed into the insertion point must be reprojected
-    // into the older ShadowRoot's insertion points.
-    if (mShadowElement && mShadowElement == insertionPoint->GetParent()) {
-      ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
-      if (olderShadow) {
-        olderShadow->DistributeSingleNode(aContent);
-      }
-    }
   }
 }
 
 void
 ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
 {
   // Find insertion point containing the content and remove the node.
   for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
@@ -363,63 +325,38 @@ ShadowRoot::RemoveDistributedNode(nsICon
         // Removing the matched node will cause fallback content to be
         // used instead. Give up optimization and distribute all nodes.
         DistributeAllNodes();
         return;
       }
 
       mInsertionPoints[i]->RemoveMatchedNode(aContent);
 
-      // Handle the case where the parent of the insertion point is a ShadowRoot
-      // that is projected into the younger ShadowRoot's shadow insertion point.
-      // The removed node needs to be removed from the shadow insertion point.
-      if (mInsertionPoints[i]->GetParent() == this) {
-        if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
-          mYoungerShadow->GetShadowElement()->RemoveDistributedNode(aContent);
-        }
-      }
-
       // Handle the case where the parent of the insertion point has a ShadowRoot.
       // The removed node needs to be removed from the insertion points of the
       // parent's ShadowRoot.
       ShadowRoot* parentShadow = mInsertionPoints[i]->GetParent()->GetShadowRoot();
       if (parentShadow) {
         parentShadow->RemoveDistributedNode(aContent);
       }
 
-      // Handle the case where the parent of the insertion point is the <shadow>
-      // element. The removed node must be removed from the older ShadowRoot's
-      // insertion points.
-      if (mShadowElement && mShadowElement == mInsertionPoints[i]->GetParent()) {
-        ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
-        if (olderShadow) {
-          olderShadow->RemoveDistributedNode(aContent);
-        }
-      }
-
       break;
     }
   }
 }
 
 void
 ShadowRoot::DistributeAllNodes()
 {
   // Create node pool.
   nsTArray<nsIContent*> nodePool;
-
-  // Make sure there is a pool host, an older shadow may not have
-  // one if the younger shadow does not have a <shadow> element.
-  if (mPoolHost) {
-    ExplicitChildIterator childIterator(mPoolHost);
-    for (nsIContent* content = childIterator.GetNextChild();
-         content;
-         content = childIterator.GetNextChild()) {
-      nodePool.AppendElement(content);
-    }
+  ExplicitChildIterator childIterator(GetHost());
+  for (nsIContent* content = childIterator.GetNextChild(); content;
+       content = childIterator.GetNextChild()) {
+    nodePool.AppendElement(content);
   }
 
   nsTArray<ShadowRoot*> shadowsToUpdate;
 
   for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
     mInsertionPoints[i]->ClearMatchedNodes();
     // Assign matching nodes from node pool.
     for (uint32_t j = 0; j < nodePool.Length(); j++) {
@@ -440,30 +377,16 @@ ShadowRoot::DistributeAllNodes()
     // to the insertion point must be reprojected to the insertion points of the
     // parent's ShadowRoot.
     ShadowRoot* parentShadow = insertionParent->GetShadowRoot();
     if (parentShadow && !shadowsToUpdate.Contains(parentShadow)) {
       shadowsToUpdate.AppendElement(parentShadow);
     }
   }
 
-  // If there is a shadow insertion point in this ShadowRoot, the children
-  // of the shadow insertion point needs to be distributed into the insertion
-  // points of the older ShadowRoot.
-  if (mShadowElement && mOlderShadow) {
-    mOlderShadow->DistributeAllNodes();
-  }
-
-  // If there is a younger ShadowRoot with a shadow insertion point,
-  // then the children of this ShadowRoot needs to be distributed to
-  // the younger ShadowRoot's shadow insertion point.
-  if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
-    mYoungerShadow->GetShadowElement()->DistributeAllNodes();
-  }
-
   for (uint32_t i = 0; i < shadowsToUpdate.Length(); i++) {
     shadowsToUpdate[i]->DistributeAllNodes();
   }
 }
 
 void
 ShadowRoot::GetInnerHTML(nsAString& aInnerHTML)
 {
@@ -510,81 +433,27 @@ ShadowRoot::StyleSheets()
 {
   if (!mStyleSheetList) {
     mStyleSheetList = new ShadowRootStyleSheetList(this);
   }
 
   return mStyleSheetList;
 }
 
-void
-ShadowRoot::SetShadowElement(HTMLShadowElement* aShadowElement)
-{
-  // If there is already a shadow element point, remove
-  // the projected shadow because it is no longer an insertion
-  // point.
-  if (mShadowElement) {
-    mShadowElement->SetProjectedShadow(nullptr);
-  }
-
-  if (mOlderShadow) {
-    // Nodes for distribution will come from the new shadow element.
-    mOlderShadow->ChangePoolHost(aShadowElement);
-  }
-
-  // Set the new shadow element to project the older ShadowRoot because
-  // it is the current shadow insertion point.
-  mShadowElement = aShadowElement;
-  if (mShadowElement) {
-    mShadowElement->SetProjectedShadow(mOlderShadow);
-  }
-}
-
-void
-ShadowRoot::ChangePoolHost(nsIContent* aNewHost)
-{
-  if (mPoolHost) {
-    mPoolHost->RemoveMutationObserver(this);
-  }
-
-  // Clear the nodes matched to content insertion points
-  // because it is no longer relevant.
-  for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
-    mInsertionPoints[i]->ClearMatchedNodes();
-  }
-
-  mPoolHost = aNewHost;
-  if (mPoolHost) {
-    mPoolHost->AddMutationObserver(this);
-  }
-}
-
-bool
-ShadowRoot::IsShadowInsertionPoint(nsIContent* aContent)
-{
-  if (!aContent) {
-    return false;
-  }
-
-  HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(aContent);
-  return shadowElem && shadowElem->IsInsertionPoint();
-}
-
 /**
  * Returns whether the web components pool population algorithm
  * on the host would contain |aContent|. This function ignores
  * insertion points in the pool, thus should only be used to
  * test nodes that have not yet been distributed.
  */
 bool
 ShadowRoot::IsPooledNode(nsIContent* aContent, nsIContent* aContainer,
                          nsIContent* aHost)
 {
-  if (nsContentUtils::IsContentInsertionPoint(aContent) ||
-      IsShadowInsertionPoint(aContent)) {
+  if (nsContentUtils::IsContentInsertionPoint(aContent)) {
     // Insertion points never end up in the pool.
     return false;
   }
 
   if (aContainer == aHost &&
       nsContentUtils::IsInSameAnonymousTree(aContainer, aContent)) {
     // Children of the host will end up in the pool. We check to ensure
     // that the content is in the same anonymous tree as the container
@@ -607,17 +476,17 @@ ShadowRoot::IsPooledNode(nsIContent* aCo
 void
 ShadowRoot::AttributeChanged(nsIDocument* aDocument,
                              Element* aElement,
                              int32_t aNameSpaceID,
                              nsIAtom* aAttribute,
                              int32_t aModType,
                              const nsAttrValue* aOldValue)
 {
-  if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
+  if (!IsPooledNode(aElement, aElement->GetParent(), GetHost())) {
     return;
   }
 
   // Attributes may change insertion point matching, find its new distribution.
   RemoveDistributedNode(aElement);
   DistributeSingleNode(aElement);
 }
 
@@ -640,17 +509,17 @@ ShadowRoot::ContentAppended(nsIDocument*
     // Add insertion point to destination insertion points of fallback content.
     if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
       HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
       if (content->MatchedNodes().IsEmpty()) {
         currentChild->DestInsertionPoints().AppendElement(aContainer);
       }
     }
 
-    if (IsPooledNode(currentChild, aContainer, mPoolHost)) {
+    if (IsPooledNode(currentChild, aContainer, GetHost())) {
       DistributeSingleNode(currentChild);
     }
 
     currentChild = currentChild->GetNextSibling();
   }
 }
 
 void
@@ -662,17 +531,17 @@ ShadowRoot::ContentInserted(nsIDocument*
   if (mInsertionPointChanged) {
     DistributeAllNodes();
     mInsertionPointChanged = false;
     return;
   }
 
   // Watch for new nodes added to the pool because the node
   // may need to be added to an insertion point.
-  if (IsPooledNode(aChild, aContainer, mPoolHost)) {
+  if (IsPooledNode(aChild, aContainer, GetHost())) {
     // Add insertion point to destination insertion points of fallback content.
     if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
       HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
       if (content->MatchedNodes().IsEmpty()) {
         aChild->DestInsertionPoints().AppendElement(aContainer);
       }
     }
 
@@ -699,38 +568,29 @@ ShadowRoot::ContentRemoved(nsIDocument* 
     HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
     if (content->MatchedNodes().IsEmpty()) {
       aChild->DestInsertionPoints().Clear();
     }
   }
 
   // Watch for node that is removed from the pool because
   // it may need to be removed from an insertion point.
-  if (IsPooledNode(aChild, aContainer, mPoolHost)) {
+  if (IsPooledNode(aChild, aContainer, GetHost())) {
     RemoveDistributedNode(aChild);
   }
 }
 
 nsresult
 ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                   bool aPreallocateChildren) const
 {
   *aResult = nullptr;
   return NS_ERROR_DOM_DATA_CLONE_ERR;
 }
 
-void
-ShadowRoot::DestroyContent()
-{
-  if (mOlderShadow) {
-    mOlderShadow->DestroyContent();
-  }
-  DocumentFragment::DestroyContent();
-}
-
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
                                    mShadowRoot)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRootStyleSheetList)
 NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
 
 NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
 NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -20,61 +20,43 @@ class nsIAtom;
 class nsIContent;
 class nsXBLPrototypeBinding;
 
 namespace mozilla {
 namespace dom {
 
 class Element;
 class HTMLContentElement;
-class HTMLShadowElement;
 class ShadowRootStyleSheetList;
 
 class ShadowRoot final : public DocumentFragment,
                          public nsStubMutationObserver
 {
   friend class ShadowRootStyleSheetList;
 public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
                                            DocumentFragment)
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
-  ShadowRoot(Element* aElement, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
+  ShadowRoot(Element* aElement,
+             already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
              nsXBLPrototypeBinding* aProtoBinding);
 
   void AddToIdTable(Element* aElement, nsIAtom* aId);
   void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
   void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
   void RemoveSheet(StyleSheet* aSheet);
   bool ApplyAuthorStyles();
   void SetApplyAuthorStyles(bool aApplyAuthorStyles);
   StyleSheetList* StyleSheets();
-  HTMLShadowElement* GetShadowElement() { return mShadowElement; }
-
-  /**
-   * Sets the current shadow insertion point where the older
-   * ShadowRoot will be projected.
-   */
-  void SetShadowElement(HTMLShadowElement* aShadowElement);
-
-  /**
-   * Change the node that populates the distribution pool with
-   * its children. This is distinct from the ShadowRoot host described
-   * in the specifications. The ShadowRoot host is the element
-   * which created this ShadowRoot and does not change. The pool host
-   * is the same as the ShadowRoot host if this is the youngest
-   * ShadowRoot. If this is an older ShadowRoot, the pool host is
-   * the <shadow> element in the younger ShadowRoot (if it exists).
-   */
-  void ChangePoolHost(nsIContent* aNewHost);
 
   /**
    * Distributes a single explicit child of the pool host to the content
    * insertion points in this ShadowRoot.
    */
   void DistributeSingleNode(nsIContent* aContent);
 
   /**
@@ -87,98 +69,69 @@ public:
    * Distributes all the explicit children of the pool host to the content
    * insertion points in this ShadowRoot.
    */
   void DistributeAllNodes();
 
   void AddInsertionPoint(HTMLContentElement* aInsertionPoint);
   void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
 
-  void SetYoungerShadow(ShadowRoot* aYoungerShadow);
-  ShadowRoot* GetYoungerShadowRoot() { return mYoungerShadow; }
   void SetInsertionPointChanged() { mInsertionPointChanged = true; }
 
   void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
 
-  nsISupports* GetParentObject() const { return mPoolHost; }
-
-  nsIContent* GetPoolHost() { return mPoolHost; }
-  nsTArray<HTMLShadowElement*>& ShadowDescendants() { return mShadowDescendants; }
-
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static bool IsPooledNode(nsIContent* aChild, nsIContent* aContainer,
                            nsIContent* aHost);
   static ShadowRoot* FromNode(nsINode* aNode);
-  static bool IsShadowInsertionPoint(nsIContent* aContent);
 
   static void RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
                                        nsTArray<nsIContent*>& aDestInsertionPoints);
 
   // WebIDL methods.
   Element* GetElementById(const nsAString& aElementId);
   already_AddRefed<nsContentList>
     GetElementsByTagName(const nsAString& aNamespaceURI);
   already_AddRefed<nsContentList>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName);
   already_AddRefed<nsContentList>
     GetElementsByClassName(const nsAString& aClasses);
   void GetInnerHTML(nsAString& aInnerHTML);
   void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
   Element* Host();
-  ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; }
   void StyleSheetChanged();
 
   bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
   void SetIsComposedDocParticipant(bool aIsComposedDocParticipant)
   {
     mIsComposedDocParticipant = aIsComposedDocParticipant;
   }
 
-  virtual void DestroyContent() override;
 protected:
   virtual ~ShadowRoot();
 
-  // The pool host is the parent of the nodes that will be distributed
-  // into the insertion points in this ShadowRoot. See |ChangeShadowRoot|.
-  nsCOMPtr<nsIContent> mPoolHost;
-
   // An array of content insertion points that are a descendant of the ShadowRoot
   // sorted in tree order. Insertion points are responsible for notifying
   // the ShadowRoot when they are removed or added as a descendant. The insertion
   // points are kept alive by the parent node, thus weak references are held
   // by the array.
   nsTArray<HTMLContentElement*> mInsertionPoints;
 
-  // An array of the <shadow> elements that are descendant of the ShadowRoot
-  // sorted in tree order. Only the first may be a shadow insertion point.
-  nsTArray<HTMLShadowElement*> mShadowDescendants;
-
   nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
   nsXBLPrototypeBinding* mProtoBinding;
 
   // It is necessary to hold a reference to the associated nsXBLBinding
   // because the binding holds a reference on the nsXBLDocumentInfo that
   // owns |mProtoBinding|.
   RefPtr<nsXBLBinding> mAssociatedBinding;
 
   RefPtr<ShadowRootStyleSheetList> mStyleSheetList;
 
-  // The current shadow insertion point of this ShadowRoot.
-  HTMLShadowElement* mShadowElement;
-
-  // The ShadowRoot that was created by the host element before
-  // this ShadowRoot was created.
-  RefPtr<ShadowRoot> mOlderShadow;
-
-  // The ShadowRoot that was created by the host element after
-  // this ShadowRoot was created.
-  RefPtr<ShadowRoot> mYoungerShadow;
-
   // A boolean that indicates that an insertion point was added or removed
   // from this ShadowRoot and that the nodes need to be redistributed into
   // the insertion points. After this flag is set, nodes will be distributed
   // on the next mutation event.
   bool mInsertionPointChanged;
 
   // Flag to indicate whether the descendants of this shadow root are part of the
   // composed document. Ideally, we would use a node flag on nodes to
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -180,16 +180,17 @@ EXPORTS.mozilla.dom += [
     'FormData.h',
     'FragmentOrElement.h',
     'FromParser.h',
     'GroupedSHistory.h',
     'IdleDeadline.h',
     'IdleRequest.h',
     'ImageEncoder.h',
     'ImageTracker.h',
+    'IntlUtils.h',
     'Link.h',
     'Location.h',
     'NameSpaceConstants.h',
     'Navigator.h',
     'NodeInfo.h',
     'NodeInfoInlines.h',
     'NodeIterator.h',
     'PartialSHistory.h',
@@ -253,16 +254,17 @@ UNIFIED_SOURCES += [
     'EventSource.cpp',
     'FormData.cpp',
     'FragmentOrElement.cpp',
     'GroupedSHistory.cpp',
     'IdleDeadline.cpp',
     'IdleRequest.cpp',
     'ImageEncoder.cpp',
     'ImageTracker.cpp',
+    'IntlUtils.cpp',
     'Link.cpp',
     'Location.cpp',
     'Navigator.cpp',
     'NodeInfo.cpp',
     'NodeIterator.cpp',
     'nsAtomListUtils.cpp',
     'nsAttrAndChildArray.cpp',
     'nsAttrValue.cpp',
@@ -370,24 +372,16 @@ if CONFIG['MOZ_WEBRTC']:
         'nsDOMDataChannel.cpp',
     ]
 
 if CONFIG['FUZZING']:
     UNIFIED_SOURCES += [
         'FuzzingFunctions.cpp',
     ]
 
-if CONFIG['ENABLE_INTL_API']:
-    UNIFIED_SOURCES += [
-        'IntlUtils.cpp',
-    ]
-    EXPORTS.mozilla.dom += [
-        'IntlUtils.h',
-    ]
-
 # these files couldn't be in UNIFIED_SOURCES for now for reasons given below:
 SOURCES += [
     # Several conflicts with other bindings.
     'DOMIntersectionObserver.cpp',
     # Because of OS X headers.
     'nsContentUtils.cpp',
     # this file doesn't like windows.h
     'nsDOMWindowUtils.cpp',
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -45,17 +45,16 @@
 #include "mozilla/dom/DOMTypes.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "mozilla/dom/FileSystemSecurity.h"
 #include "mozilla/dom/FileBlobImpl.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "mozilla/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/HTMLContentElement.h"
-#include "mozilla/dom/HTMLShadowElement.h"
 #include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/TouchEvent.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/XULCommandEvent.h"
 #include "mozilla/dom/WorkerPrivate.h"
@@ -7562,30 +7561,16 @@ nsContentUtils::HasDistributedChildren(n
   }
 
   if (aContent->GetShadowRoot()) {
     // Children of a shadow root host are distributed
     // to content insertion points in the shadow root.
     return true;
   }
 
-  ShadowRoot* shadow = ShadowRoot::FromNode(aContent);
-  if (shadow) {
-    // Children of a shadow root are distributed to
-    // the shadow insertion point of the younger shadow root.
-    return shadow->GetYoungerShadowRoot();
-  }
-
-  HTMLShadowElement* shadowEl = HTMLShadowElement::FromContent(aContent);
-  if (shadowEl && shadowEl->IsInsertionPoint()) {
-    // Children of a shadow insertion points are distributed
-    // to the insertion points in the older shadow root.
-    return shadowEl->GetOlderShadowRoot();
-  }
-
   HTMLContentElement* contentEl = HTMLContentElement::FromContent(aContent);
   if (contentEl && contentEl->IsInsertionPoint()) {
     // Children of a content insertion point are distributed to the
     // content insertion point if the content insertion point does
     // not match any nodes (fallback content).
     return contentEl->MatchedNodes().IsEmpty();
   }
 
@@ -10150,16 +10135,59 @@ nsContentUtils::GetElementDefinitionIfOb
   if (!definition || !definition->IsInObservedAttributeList(aAttrName)) {
     return nullptr;
   }
 
   return definition;
 }
 
 /* static */ void
+nsContentUtils::SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
+                                    Element* aElement,
+                                    CustomElementDefinition* aDefinition)
+{
+  MOZ_ASSERT(aElement);
+
+  nsIDocument* doc = aElement->OwnerDoc();
+  nsPIDOMWindowInner* window(doc->GetInnerWindow());
+  if (!window) {
+    return;
+  }
+
+  RefPtr<CustomElementRegistry> registry(window->CustomElements());
+  if (!registry) {
+    return;
+  }
+
+  registry->SyncInvokeReactions(aType, aElement, aDefinition);
+}
+
+/* static */ void
+nsContentUtils::EnqueueUpgradeReaction(Element* aElement,
+                                       CustomElementDefinition* aDefinition)
+{
+  MOZ_ASSERT(aElement);
+
+  nsIDocument* doc = aElement->OwnerDoc();
+  nsPIDOMWindowInner* window(doc->GetInnerWindow());
+  if (!window) {
+    return;
+  }
+
+  RefPtr<CustomElementRegistry> registry(window->CustomElements());
+  if (!registry) {
+    return;
+  }
+
+  CustomElementReactionsStack* stack =
+    doc->GetDocGroup()->CustomElementReactionsStack();
+  stack->EnqueueUpgradeReaction(registry, aElement, aDefinition);
+}
+
+/* static */ void
 nsContentUtils::EnqueueLifecycleCallback(nsIDocument* aDoc,
                                          nsIDocument::ElementCallbackType aType,
                                          Element* aCustomElement,
                                          LifecycleCallbackArgs* aArgs,
                                          CustomElementDefinition* aDefinition)
 {
   MOZ_ASSERT(aDoc);
 
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2993,16 +2993,23 @@ public:
   static void SetupCustomElement(Element* aElement,
                                  const nsAString* aTypeExtension = nullptr);
 
   static mozilla::dom::CustomElementDefinition*
   GetElementDefinitionIfObservingAttr(Element* aCustomElement,
                                       nsIAtom* aExtensionType,
                                       nsIAtom* aAttrName);
 
+  static void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
+                                  Element* aCustomElement,
+                                  mozilla::dom::CustomElementDefinition* aDefinition);
+
+  static void EnqueueUpgradeReaction(Element* aElement,
+                                     mozilla::dom::CustomElementDefinition* aDefinition);
+
   static void EnqueueLifecycleCallback(nsIDocument* aDoc,
                                        nsIDocument::ElementCallbackType aType,
                                        Element* aCustomElement,
                                        mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
                                        mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
 
   static void GetCustomPrototype(nsIDocument* aDoc,
                                  int32_t aNamespaceID,
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -274,16 +274,17 @@
 #include "nsISpeculativeConnect.h"
 
 #include "mozilla/MediaManager.h"
 
 #include "nsIURIClassifier.h"
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/ServoRestyleManager.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "nsHTMLTags.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 typedef nsTArray<Link*> LinkArray;
 
 static LazyLogModule gDocumentLeakPRLog("DocumentLeak");
 static LazyLogModule gCspPRLog("CSP");
@@ -6019,16 +6020,20 @@ nsDocument::CreateElement(const nsAStrin
 
   RefPtr<Element> elem = CreateElem(
     needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
 
   if (pseudoType != CSSPseudoElementType::NotPseudo) {
     elem->SetPseudoElementType(pseudoType);
   }
 
+  if (is) {
+    elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
+  }
+
   return elem.forget();
 }
 
 NS_IMETHODIMP
 nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
                             const nsAString& aQualifiedName,
                             nsIDOMElement** aReturn)
 {
@@ -6070,16 +6075,20 @@ nsDocument::CreateElementNS(const nsAStr
 
   nsCOMPtr<Element> element;
   rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
                      NOT_FROM_PARSER, is);
   if (rv.Failed()) {
     return nullptr;
   }
 
+  if (is) {
+    element->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
+  }
+
   return element.forget();
 }
 
 NS_IMETHODIMP
 nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn)
 {
   *aReturn = nsIDocument::CreateTextNode(aData).take();
   return NS_OK;
@@ -6352,21 +6361,36 @@ nsDocument::CustomElementConstructor(JSC
       if (!JS_WrapObject(aCx, &reflector)) {
         return false;
       }
 
       args.rval().setObject(*reflector);
       return true;
     }
   } else {
-    nsDependentAtomString localName(definition->mLocalName);
-    element =
-      document->CreateElem(localName, nullptr, kNameSpaceID_XHTML,
-                           (definition->mLocalName != typeAtom) ? &elemName
-                                                                : nullptr);
+    RefPtr<mozilla::dom::NodeInfo> nodeInfo =
+      document->NodeInfoManager()->GetNodeInfo(definition->mLocalName, nullptr,
+                                               kNameSpaceID_XHTML,
+                                               nsIDOMNode::ELEMENT_NODE);
+
+    int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
+    if (tag == eHTMLTag_userdefined &&
+        nsContentUtils::IsCustomElementName(definition->mType)) {
+      element = NS_NewHTMLElement(nodeInfo.forget(), NOT_FROM_PARSER);
+    } else {
+      element = ::CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
+    }
+
+    element->SetCustomElementData(
+      new CustomElementData(definition->mType,
+                            CustomElementData::State::eCustom));
+
+    // It'll be removed when we deprecate custom elements v0.
+    nsContentUtils::SyncInvokeReactions(nsIDocument::eCreated, element,
+                                        definition);
     NS_ENSURE_TRUE(element, false);
   }
 
   // The prototype setup happens in Element::WrapObject().
   nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
   NS_ENSURE_SUCCESS(rv, true);
 
   return true;
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1655,17 +1655,16 @@ GK_ATOM(requiredExtensions, "requiredExt
 GK_ATOM(requiredFeatures, "requiredFeatures")
 GK_ATOM(rotate, "rotate")
 GK_ATOM(rx, "rx")
 GK_ATOM(ry, "ry")
 GK_ATOM(saturate, "saturate")
 GK_ATOM(saturation, "saturation")
 GK_ATOM(set, "set")
 GK_ATOM(seed, "seed")
-GK_ATOM(shadow, "shadow")
 GK_ATOM(shape_rendering, "shape-rendering")
 GK_ATOM(skewX, "skewX")
 GK_ATOM(skewY, "skewY")
 GK_ATOM(slope, "slope")
 GK_ATOM(softLight, "soft-light")
 GK_ATOM(spacing, "spacing")
 GK_ATOM(spacingAndGlyphs, "spacingAndGlyphs")
 GK_ATOM(specularConstant, "specularConstant")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -228,19 +228,17 @@
 #include "TimeChangeObserver.h"
 #include "mozilla/dom/AudioContext.h"
 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
 #include "mozilla/dom/cache/CacheStorage.h"
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/HashChangeEvent.h"
-#ifdef ENABLE_INTL_API
 #include "mozilla/dom/IntlUtils.h"
-#endif
 #include "mozilla/dom/MozSelfSupportBinding.h"
 #include "mozilla/dom/PopStateEvent.h"
 #include "mozilla/dom/PopupBlockedEvent.h"
 #include "mozilla/dom/PrimitiveConversions.h"
 #include "mozilla/dom/WindowBinding.h"
 #include "nsITabChild.h"
 #include "mozilla/dom/MediaQueryList.h"
 #include "mozilla/dom/ScriptSettings.h"
@@ -2060,19 +2058,17 @@ nsGlobalWindow::CleanUp()
 
   if (mIdleTimer) {
     mIdleTimer->Cancel();
     mIdleTimer = nullptr;
   }
 
   mServiceWorkerRegistrationTable.Clear();
 
-#ifdef ENABLE_INTL_API
   mIntlUtils = nullptr;
-#endif
 }
 
 void
 nsGlobalWindow::ClearControllers()
 {
   if (mControllers) {
     uint32_t count;
     mControllers->GetControllerCount(&count);
@@ -2351,19 +2347,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mU2F)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioWorklet)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMozSelfSupport)
-#ifdef ENABLE_INTL_API
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
-#endif
 
   tmp->TraverseHostObjectURIs(cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
   nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
@@ -2431,19 +2425,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mU2F)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioWorklet)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMozSelfSupport)
-#ifdef ENABLE_INTL_API
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
-#endif
 
   tmp->UnlinkHostObjectURIs();
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
   tmp->DisableIdleCallbackRequests();
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@@ -15086,25 +15078,23 @@ nsGlobalWindow::GetRegionalPrefsLocales(
   AutoTArray<nsCString, 10> rpLocales;
   mozilla::intl::LocaleService::GetInstance()->GetRegionalPrefsLocales(rpLocales);
 
   for (const auto& loc : rpLocales) {
     aLocales.AppendElement(NS_ConvertUTF8toUTF16(loc));
   }
 }
 
-#ifdef ENABLE_INTL_API
 IntlUtils*
 nsGlobalWindow::GetIntlUtils(ErrorResult& aError)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mIntlUtils) {
     mIntlUtils = new IntlUtils(AsInner());
   }
 
   return mIntlUtils;
 }
-#endif
 
 template class nsPIDOMWindow<mozIDOMWindowProxy>;
 template class nsPIDOMWindow<mozIDOMWindow>;
 template class nsPIDOMWindow<nsISupports>;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -118,19 +118,17 @@ class CustomElementRegistry;
 class DocGroup;
 class External;
 class Function;
 class Gamepad;
 enum class ImageBitmapFormat : uint8_t;
 class IdleRequest;
 class IdleRequestCallback;
 class IncrementalRunnable;
-#ifdef ENABLE_INTL_API
 class IntlUtils;
-#endif
 class Location;
 class MediaQueryList;
 class MozSelfSupport;
 class Navigator;
 class OwningExternalOrWindowProxy;
 class Promise;
 class PostMessageEvent;
 struct RequestInit;
@@ -954,20 +952,18 @@ public:
   GetAudioWorklet(mozilla::ErrorResult& aRv);
 
   mozilla::dom::Worklet*
   GetPaintWorklet(mozilla::ErrorResult& aRv);
 
   void
   GetRegionalPrefsLocales(nsTArray<nsString>& aLocales);
 
-#ifdef ENABLE_INTL_API
   mozilla::dom::IntlUtils*
   GetIntlUtils(mozilla::ErrorResult& aRv);
-#endif
 
 protected:
   bool AlertOrConfirm(bool aAlert, const nsAString& aMessage,
                       nsIPrincipal& aSubjectPrincipal,
                       mozilla::ErrorResult& aError);
 
 public:
   void Alert(nsIPrincipal& aSubjectPrincipal,
@@ -2022,19 +2018,17 @@ protected:
   RefPtr<mozilla::dom::VREventObserver> mVREventObserver;
 
   // When non-zero, the document should receive a vrdisplayactivate event
   // after loading.  The value is the ID of the VRDisplay that content should
   // begin presentation on.
   uint32_t mAutoActivateVRDisplayID; // Outer windows only
   int64_t mBeforeUnloadListenerCount; // Inner windows only
 
-#ifdef ENABLE_INTL_API
   RefPtr<mozilla::dom::IntlUtils> mIntlUtils;
-#endif
 
   friend class nsDOMScriptableHelper;
   friend class nsDOMWindowUtils;
   friend class mozilla::dom::PostMessageEvent;
   friend class DesktopNotification;
   friend class mozilla::dom::TimeoutManager;
   friend class IdleRequestExecutor;
 
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -61,17 +61,17 @@ using mozilla::AutoJSContext;
       /* No need to explicitly notify the first observer first    \
          since that'll happen anyway. */                          \
       NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(                    \
         slots->mMutationObservers, nsIMutationObserver, 1,        \
         func_, params_);                                          \
     }                                                             \
     ShadowRoot* shadow = ShadowRoot::FromNode(node);              \
     if (shadow) {                                                 \
-      node = shadow->GetPoolHost();                               \
+      node = shadow->GetHost();                                   \
     } else {                                                      \
       node = node->GetParentNode();                               \
     }                                                             \
   } while (node);                                                 \
   if (needsEnterLeave) {                                          \
     nsDOMMutationObserver::LeaveMutationHandling();               \
   }                                                               \
   PR_END_MACRO
@@ -89,17 +89,17 @@ using mozilla::AutoJSContext;
       /* No need to explicitly notify the first observer first    \
          since that'll happen anyway. */                          \
       NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS_WITH_QI(            \
         slots->mMutationObservers, nsIMutationObserver, 1,        \
         nsIAnimationObserver, func_, params_);                    \
     }                                                             \
     ShadowRoot* shadow = ShadowRoot::FromNode(node);              \
     if (shadow) {                                                 \
-      node = shadow->GetPoolHost();                               \
+      node = shadow->GetHost();                                   \
     } else {                                                      \
       node = node->GetParentNode();                               \
     }                                                             \
   } while (node);                                                 \
   if (needsEnterLeave) {                                          \
     nsDOMMutationObserver::LeaveMutationHandling();               \
   }                                                               \
   PR_END_MACRO
--- a/dom/base/test/test_mutationobservers.html
+++ b/dom/base/test/test_mutationobservers.html
@@ -582,58 +582,32 @@ function testOutsideShadowDOM() {
          "because createShadowRoot is not supported");
     then(testMarquee);
     return;
   }
   var m = new M(function(records, observer) {
     is(records.length, 1);
     is(records[0].type, "attributes", "Should have got attributes");
     observer.disconnect();
-    then(testInsideShadowDOM);
+    then(testMarquee);
   });
   m.observe(div, {
       attributes: true,
       childList: true,
       characterData: true,
       subtree: true
     })
   var sr = div.createShadowRoot();
   sr.innerHTML = "<div" + ">text</" + "div>";
   sr.firstChild.setAttribute("foo", "bar");
   sr.firstChild.firstChild.data = "text2";
   sr.firstChild.appendChild(document.createElement("div"));
   div.setAttribute("foo", "bar");
 }
 
-function testInsideShadowDOM() {
-  var m = new M(function(records, observer) {
-    is(records.length, 4);
-    is(records[0].type, "childList");
-    is(records[1].type, "attributes");
-    is(records[2].type, "characterData");
-    is(records[3].type, "childList");
-    observer.disconnect();
-    then(testMarquee);
-  });
-  var sr = div.createShadowRoot();
-  m.observe(sr, {
-      attributes: true,
-      childList: true,
-      characterData: true,
-      subtree: true
-    });
-
-  sr.innerHTML = "<div" + ">text</" + "div>";
-  sr.firstChild.setAttribute("foo", "bar");
-  sr.firstChild.firstChild.data = "text2";
-  sr.firstChild.appendChild(document.createElement("div"));
-  div.setAttribute("foo", "bar2");
-
-}
-
 function testMarquee() {
   var m = new M(function(records, observer) {
     is(records.length, 1);
     is(records[0].type, "attributes");
     is(records[0].attributeName, "ok");
     is(records[0].oldValue, null);
     observer.disconnect();
     then(testStyleCreate);
--- a/dom/cache/CacheStreamControlChild.cpp
+++ b/dom/cache/CacheStreamControlChild.cpp
@@ -110,21 +110,28 @@ CacheStreamControlChild::OpenStream(cons
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
 
   if (mDestroyStarted) {
     aResolver(nullptr);
     return;
   }
 
+  // If we are on a worker, then we need to hold it alive until the async
+  // IPC operation below completes.  While the IPC layer will trigger a
+  // rejection here in many cases, we must handle the case where the
+  // MozPromise resolve runnable is already in the event queue when the
+  // worker wants to shut down.
+  RefPtr<CacheWorkerHolder> holder = GetWorkerHolder();
+
   SendOpenStream(aId)->Then(GetCurrentThreadSerialEventTarget(), __func__,
-  [aResolver](const OptionalIPCStream& aOptionalStream) {
+  [aResolver, holder](const OptionalIPCStream& aOptionalStream) {
     nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aOptionalStream);
     aResolver(Move(stream));
-  }, [aResolver](PromiseRejectReason aReason) {
+  }, [aResolver, holder](PromiseRejectReason aReason) {
     aResolver(nullptr);
   });
 }
 
 void
 CacheStreamControlChild::NoteClosedAfterForget(const nsID& aId)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
new file mode 100644
--- /dev/null
+++ b/dom/canvas/crashtests/1296410-1.html
@@ -0,0 +1,9 @@
+<canvas id='canv'></canvas>
+<script>
+var ctx=document.getElementById('canv').getContext('2d');
+ctx.globalAlpha=0.81;
+ctx.scale(22,3406781);
+ctx.filter='sepia(80%)';
+ctx.font='52px serif';
+ctx.measureText('A');
+</script>
--- a/dom/canvas/crashtests/crashtests.list
+++ b/dom/canvas/crashtests/crashtests.list
@@ -32,15 +32,16 @@ load 1246775-1.html
 load 1284356-1.html
 load 1284578-1.html
 skip-if(d2d) load 1287515-1.html
 load 1287652-1.html
 load 1288872-1.html
 load 1290628-1.html
 load 1283113-1.html
 load 1286458-1.html
+load 1296410-1.html
 load 1299062-1.html
 load 1305085-1.html
 load 1305312-1.html
 load 1298576-1.html
 load 1334366-1.html
 load 1334647-1.html
 load 1357092.html
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -74,17 +74,17 @@ skip-if = true # Disabled due to timeout
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug591815.html]
 [test_bug593959.html]
 [test_bug603008.html]
 skip-if = toolkit == 'android'
 [test_bug605242.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug607464.html]
-skip-if = toolkit == 'android' || (e10s && os == 'win') || (e10s && os == "mac") #CRASH_DUMP, RANDOM, bug 1252273
+skip-if = toolkit == 'android' || e10s #CRASH_DUMP, RANDOM, bug 1252273, bug 1400586
 [test_bug613634.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug615597.html]
 [test_bug624127.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug635465.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug641477.html]
deleted file mode 100644
--- a/dom/html/HTMLShadowElement.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/dom/ShadowRoot.h"
-
-#include "ChildIterator.h"
-#include "nsContentUtils.h"
-#include "nsDocument.h"
-#include "mozilla/dom/HTMLShadowElement.h"
-#include "mozilla/dom/HTMLUnknownElement.h"
-#include "mozilla/dom/HTMLShadowElementBinding.h"
-
-// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Shadow) to add check for web components
-// being enabled.
-nsGenericHTMLElement*
-NS_NewHTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
-                        mozilla::dom::FromParser aFromParser)
-{
-  // When this check is removed, remove the nsDocument.h and
-  // HTMLUnknownElement.h includes.  Also remove nsINode::IsHTMLShadowElement.
-  //
-  // We have to jump through some hoops to be able to produce both NodeInfo* and
-  // already_AddRefed<NodeInfo>& for our callees.
-  RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
-  if (!nsDocument::IsWebComponentsEnabled(nodeInfo)) {
-    already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
-    return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
-  }
-
-  already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
-  return new mozilla::dom::HTMLShadowElement(nodeInfoArg);
-}
-
-using namespace mozilla::dom;
-
-HTMLShadowElement::HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
-  : nsGenericHTMLElement(aNodeInfo), mIsInsertionPoint(false)
-{
-}
-
-HTMLShadowElement::~HTMLShadowElement()
-{
-  if (mProjectedShadow) {
-    mProjectedShadow->RemoveMutationObserver(this);
-  }
-}
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLShadowElement)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLShadowElement,
-                                                  nsGenericHTMLElement)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProjectedShadow)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLShadowElement,
-                                                nsGenericHTMLElement)
-  if (tmp->mProjectedShadow) {
-    tmp->mProjectedShadow->RemoveMutationObserver(tmp);
-    tmp->mProjectedShadow = nullptr;
-  }
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_ADDREF_INHERITED(HTMLShadowElement, Element)
-NS_IMPL_RELEASE_INHERITED(HTMLShadowElement, Element)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLShadowElement)
-NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
-
-NS_IMPL_ELEMENT_CLONE(HTMLShadowElement)
-
-JSObject*
-HTMLShadowElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return HTMLShadowElementBinding::Wrap(aCx, this, aGivenProto);
-}
-
-void
-HTMLShadowElement::SetProjectedShadow(ShadowRoot* aProjectedShadow)
-{
-  if (mProjectedShadow) {
-    mProjectedShadow->RemoveMutationObserver(this);
-
-    // The currently projected ShadowRoot is going away,
-    // thus the destination insertion points need to be updated.
-    ExplicitChildIterator childIterator(mProjectedShadow);
-    for (nsIContent* content = childIterator.GetNextChild();
-         content;
-         content = childIterator.GetNextChild()) {
-      ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
-    }
-  }
-
-  mProjectedShadow = aProjectedShadow;
-  if (mProjectedShadow) {
-    // A new ShadowRoot is being projected, thus its explcit
-    // children will be distributed to this shadow insertion point.
-    ExplicitChildIterator childIterator(mProjectedShadow);
-    for (nsIContent* content = childIterator.GetNextChild();
-         content;
-         content = childIterator.GetNextChild()) {
-      content->DestInsertionPoints().AppendElement(this);
-    }
-
-    // Watch for mutations on the projected shadow because
-    // it affects the nodes that are distributed to this shadow
-    // insertion point.
-    mProjectedShadow->AddMutationObserver(this);
-  }
-}
-
-static bool
-IsInFallbackContent(nsIContent* aContent)
-{
-  nsINode* parentNode = aContent->GetParentNode();
-  while (parentNode) {
-    if (parentNode->IsHTMLElement(nsGkAtoms::content)) {
-      return true;
-    }
-    parentNode = parentNode->GetParentNode();
-  }
-
-  return false;
-}
-
-nsresult
-HTMLShadowElement::BindToTree(nsIDocument* aDocument,
-                              nsIContent* aParent,
-                              nsIContent* aBindingParent,
-                              bool aCompileEventHandlers)
-{
-  RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
-
-  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
-                                                 aBindingParent,
-                                                 aCompileEventHandlers);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  ShadowRoot* containingShadow = GetContainingShadow();
-  if (containingShadow && !oldContainingShadow) {
-    // Keep track of all descendant <shadow> elements in tree order so
-    // that when the current shadow insertion point is removed, the next
-    // one can be found quickly.
-    TreeOrderComparator comparator;
-    containingShadow->ShadowDescendants().InsertElementSorted(this, comparator);
-
-    if (containingShadow->ShadowDescendants()[0] != this) {
-      // Only the first <shadow> (in tree order) of a ShadowRoot can be an insertion point.
-      return NS_OK;
-    }
-
-    if (IsInFallbackContent(this)) {
-      // If the first shadow element in tree order is invalid (in fallback content),
-      // the containing ShadowRoot will not have a shadow insertion point.
-      containingShadow->SetShadowElement(nullptr);
-    } else {
-      mIsInsertionPoint = true;
-      containingShadow->SetShadowElement(this);
-    }
-
-    containingShadow->SetInsertionPointChanged();
-  }
-
-  if (mIsInsertionPoint && containingShadow) {
-    // Propagate BindToTree calls to projected shadow root children.
-    ShadowRoot* projectedShadow = containingShadow->GetOlderShadowRoot();
-    if (projectedShadow) {
-      projectedShadow->SetIsComposedDocParticipant(IsInComposedDoc());
-
-      for (nsIContent* child = projectedShadow->GetFirstChild(); child;
-           child = child->GetNextSibling()) {
-        rv = child->BindToTree(nullptr, projectedShadow,
-                               projectedShadow->GetBindingParent(),
-                               aCompileEventHandlers);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-void
-HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent)
-{
-  RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
-
-  if (mIsInsertionPoint && oldContainingShadow) {
-    // Propagate UnbindFromTree call to previous projected shadow
-    // root children.
-    ShadowRoot* projectedShadow = oldContainingShadow->GetOlderShadowRoot();
-    if (projectedShadow) {
-      for (nsIContent* child = projectedShadow->GetFirstChild(); child;
-           child = child->GetNextSibling()) {
-        child->UnbindFromTree(true, false);
-      }
-
-      projectedShadow->SetIsComposedDocParticipant(false);
-    }
-  }
-
-  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
-
-  if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
-    nsTArray<HTMLShadowElement*>& shadowDescendants =
-      oldContainingShadow->ShadowDescendants();
-    shadowDescendants.RemoveElement(this);
-    oldContainingShadow->SetShadowElement(nullptr);
-
-    // Find the next shadow insertion point.
-    if (shadowDescendants.Length() > 0 &&
-        !IsInFallbackContent(shadowDescendants[0])) {
-      oldContainingShadow->SetShadowElement(shadowDescendants[0]);
-    }
-
-    oldContainingShadow->SetInsertionPointChanged();
-
-    mIsInsertionPoint = false;
-  }
-}
-
-void
-HTMLShadowElement::DistributeSingleNode(nsIContent* aContent)
-{
-  if (aContent->DestInsertionPoints().Contains(this)) {
-    // Node has already been distrbuted this this node,
-    // we are done.
-    return;
-  }
-
-  aContent->DestInsertionPoints().AppendElement(this);
-
-  // Handle the case where the shadow element is a child of
-  // a node with a ShadowRoot. The nodes that have been distributed to
-  // this shadow insertion point will need to be reprojected into the
-  // insertion points of the parent's ShadowRoot.
-  ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
-  if (parentShadowRoot) {
-    parentShadowRoot->DistributeSingleNode(aContent);
-    return;
-  }
-
-  // Handle the case where the parent of this shadow element is a ShadowRoot
-  // that is projected into a shadow insertion point in the younger ShadowRoot.
-  ShadowRoot* containingShadow = GetContainingShadow();
-  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
-  if (youngerShadow && GetParent() == containingShadow) {
-    HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
-    if (youngerShadowElement) {
-      youngerShadowElement->DistributeSingleNode(aContent);
-    }
-  }
-}
-
-void
-HTMLShadowElement::RemoveDistributedNode(nsIContent* aContent)
-{
-  ShadowRoot::RemoveDestInsertionPoint(this, aContent->DestInsertionPoints());
-
-  // Handle the case where the shadow element is a child of
-  // a node with a ShadowRoot. The nodes that have been distributed to
-  // this shadow insertion point will need to be removed from the
-  // insertion points of the parent's ShadowRoot.
-  ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
-  if (parentShadowRoot) {
-    parentShadowRoot->RemoveDistributedNode(aContent);
-    return;
-  }
-
-  // Handle the case where the parent of this shadow element is a ShadowRoot
-  // that is projected into a shadow insertion point in the younger ShadowRoot.
-  ShadowRoot* containingShadow = GetContainingShadow();
-  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
-  if (youngerShadow && GetParent() == containingShadow) {
-    HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
-    if (youngerShadowElement) {
-      youngerShadowElement->RemoveDistributedNode(aContent);
-    }
-  }
-}
-
-void
-HTMLShadowElement::DistributeAllNodes()
-{
-  // All the explicit children of the projected ShadowRoot are distributed
-  // into this shadow insertion point so update the destination insertion
-  // points.
-  ShadowRoot* containingShadow = GetContainingShadow();
-  ShadowRoot* olderShadow = containingShadow->GetOlderShadowRoot();
-  if (olderShadow) {
-    ExplicitChildIterator childIterator(olderShadow);
-    for (nsIContent* content = childIterator.GetNextChild();
-         content;
-         content = childIterator.GetNextChild()) {
-      ShadowRoot::RemoveDestInsertionPoint(this, content->DestInsertionPoints());
-      content->DestInsertionPoints().AppendElement(this);
-    }
-  }
-
-  // Handle the case where the shadow element is a child of
-  // a node with a ShadowRoot. The nodes that have been distributed to
-  // this shadow insertion point will need to be reprojected into the
-  // insertion points of the parent's ShadowRoot.
-  ShadowRoot* parentShadowRoot = GetParent()->GetShadowRoot();
-  if (parentShadowRoot) {
-    parentShadowRoot->DistributeAllNodes();
-    return;
-  }
-
-  // Handle the case where the parent of this shadow element is a ShadowRoot
-  // that is projected into a shadow insertion point in the younger ShadowRoot.
-  ShadowRoot* youngerShadow = containingShadow->GetYoungerShadowRoot();
-  if (youngerShadow && GetParent() == containingShadow) {
-    HTMLShadowElement* youngerShadowElement = youngerShadow->GetShadowElement();
-    if (youngerShadowElement) {
-      youngerShadowElement->DistributeAllNodes();
-    }
-  }
-}
-
-void
-HTMLShadowElement::ContentAppended(nsIDocument* aDocument,
-                                   nsIContent* aContainer,
-                                   nsIContent* aFirstNewContent,
-                                   int32_t aNewIndexInContainer)
-{
-  // Watch for content appended to the projected shadow (the ShadowRoot that
-  // will be rendered in place of this shadow insertion point) because the
-  // nodes may need to be distributed into other insertion points.
-  nsIContent* currentChild = aFirstNewContent;
-  while (currentChild) {
-    if (ShadowRoot::IsPooledNode(currentChild, aContainer, mProjectedShadow)) {
-      DistributeSingleNode(currentChild);
-    }
-    currentChild = currentChild->GetNextSibling();
-  }
-}
-
-void
-HTMLShadowElement::ContentInserted(nsIDocument* aDocument,
-                                   nsIContent* aContainer,
-                                   nsIContent* aChild,
-                                   int32_t aIndexInContainer)
-{
-  // Watch for content appended to the projected shadow (the ShadowRoot that
-  // will be rendered in place of this shadow insertion point) because the
-  // nodes may need to be distributed into other insertion points.
-  if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
-    return;
-  }
-
-  DistributeSingleNode(aChild);
-}
-
-void
-HTMLShadowElement::ContentRemoved(nsIDocument* aDocument,
-                                  nsIContent* aContainer,
-                                  nsIContent* aChild,
-                                  int32_t aIndexInContainer,
-                                  nsIContent* aPreviousSibling)
-{
-  // Watch for content removed from the projected shadow (the ShadowRoot that
-  // will be rendered in place of this shadow insertion point) because the
-  // nodes may need to be removed from other insertion points.
-  if (!ShadowRoot::IsPooledNode(aChild, aContainer, mProjectedShadow)) {
-    return;
-  }
-
-  RemoveDistributedNode(aChild);
-}
-
deleted file mode 100644
--- a/dom/html/HTMLShadowElement.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_HTMLShadowElement_h__
-#define mozilla_dom_HTMLShadowElement_h__
-
-#include "nsGenericHTMLElement.h"
-
-namespace mozilla {
-namespace dom {
-
-class HTMLShadowElement final : public nsGenericHTMLElement,
-                                public nsStubMutationObserver
-{
-public:
-  explicit HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
-
-  // nsISupports
-  NS_DECL_ISUPPORTS_INHERITED
-
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
-  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLShadowElement,
-                                           nsGenericHTMLElement)
-
-  static HTMLShadowElement* FromContent(nsIContent* aContent)
-  {
-    if (aContent->IsHTMLShadowElement()) {
-      return static_cast<HTMLShadowElement*>(aContent);
-    }
-
-    return nullptr;
-  }
-
-  virtual bool IsHTMLShadowElement() const override { return true; }
-
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
-                         bool aPreallocateChildren) const override;
-
-  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
-                              nsIContent* aBindingParent,
-                              bool aCompileEventHandlers) override;
-
-  virtual void UnbindFromTree(bool aDeep = true,
-                              bool aNullParent = true) override;
-
-  bool IsInsertionPoint() { return mIsInsertionPoint; }
-
-  /**
-   * Sets the ShadowRoot that will be rendered in place of
-   * this shadow insertion point.
-   */
-  void SetProjectedShadow(ShadowRoot* aProjectedShadow);
-
-  /**
-   * Distributes a single explicit child of the projected ShadowRoot
-   * to relevant insertion points.
-   */
-  void DistributeSingleNode(nsIContent* aContent);
-
-  /**
-   * Removes a single explicit child of the projected ShadowRoot
-   * from relevant insertion points.
-   */
-  void RemoveDistributedNode(nsIContent* aContent);
-
-  /**
-   * Distributes all the explicit children of the projected ShadowRoot
-   * to the shadow insertion point in the younger ShadowRoot and
-   * the content insertion point of the parent node's ShadowRoot.
-   */
-  void DistributeAllNodes();
-
-  // WebIDL methods.
-  ShadowRoot* GetOlderShadowRoot() { return mProjectedShadow; }
-
-protected:
-  virtual ~HTMLShadowElement();
-
-  virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
-
-  // The ShadowRoot that will be rendered in place of this shadow insertion point.
-  RefPtr<ShadowRoot> mProjectedShadow;
-
-  bool mIsInsertionPoint;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_HTMLShadowElement_h__
-
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -90,17 +90,16 @@ EXPORTS.mozilla.dom += [
     'HTMLOptionsCollection.h',
     'HTMLOutputElement.h',
     'HTMLParagraphElement.h',
     'HTMLPictureElement.h',
     'HTMLPreElement.h',
     'HTMLProgressElement.h',
     'HTMLScriptElement.h',
     'HTMLSelectElement.h',
-    'HTMLShadowElement.h',
     'HTMLSharedElement.h',
     'HTMLSharedListElement.h',
     'HTMLSourceElement.h',
     'HTMLSpanElement.h',
     'HTMLStyleElement.h',
     'HTMLSummaryElement.h',
     'HTMLTableCaptionElement.h',
     'HTMLTableCellElement.h',
@@ -170,17 +169,16 @@ UNIFIED_SOURCES += [
     'HTMLOptionsCollection.cpp',
     'HTMLOutputElement.cpp',
     'HTMLParagraphElement.cpp',
     'HTMLPictureElement.cpp',
     'HTMLPreElement.cpp',
     'HTMLProgressElement.cpp',
     'HTMLScriptElement.cpp',
     'HTMLSelectElement.cpp',
-    'HTMLShadowElement.cpp',
     'HTMLSharedElement.cpp',
     'HTMLSharedListElement.cpp',
     'HTMLSourceElement.cpp',
     'HTMLSpanElement.cpp',
     'HTMLStyleElement.cpp',
     'HTMLSummaryElement.cpp',
     'HTMLTableCaptionElement.cpp',
     'HTMLTableCellElement.cpp',
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -1576,17 +1576,16 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(OptGroup)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Option)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Output)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Paragraph)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Picture)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Pre)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Progress)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Script)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Select)
-NS_DECLARE_NS_NEW_HTML_ELEMENT(Shadow)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Source)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Span)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Style)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Summary)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCaption)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCell)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCol)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Table)
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -19,16 +19,17 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPermissionManager.h"
 #include "nsIPresShell.h"
 #include "nsIScrollable.h"
 #include "nsPresContext.h"
 #include "nsServiceManagerUtils.h"
 #include "nsSubDocumentFrame.h"
 #include "nsXULElement.h"
+#include "nsAttrValueOrString.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
                                                   nsGenericHTMLElement)
--- a/dom/html/nsHTMLContentSink.cpp
+++ b/dom/html/nsHTMLContentSink.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/dom/NodeInfo.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "nsIAppShell.h"
 #include "nsCRT.h"
 #include "prtime.h"
 #include "mozilla/Logging.h"
 #include "nsNodeUtils.h"
 #include "nsIContent.h"
+#include "mozilla/dom/CustomElementRegistry.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Preferences.h"
 
 #include "nsGenericHTMLElement.h"
 
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIScriptElement.h"
@@ -218,31 +219,126 @@ public:
     nsIContent *Add(nsIContent *child);
   };
 
   Node* mStack;
   int32_t mStackSize;
   int32_t mStackPos;
 };
 
+static void
+DoCustomElementCreate(Element** aElement, nsIDocument* aDoc,
+                      CustomElementConstructor* aConstructor, ErrorResult& aRv)
+{
+  RefPtr<Element> element =
+    aConstructor->Construct("Custom Element Create", aRv);
+  if (aRv.Failed() || !element->IsHTMLElement()) {
+    aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement"));
+    return;
+  }
+
+  if (aDoc != element->OwnerDoc() || element->GetParentNode() ||
+      element->HasChildren() || element->GetAttrCount()) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  element.forget(aElement);
+}
+
 nsresult
 NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                   FromParser aFromParser, const nsAString* aIs)
 {
   *aResult = nullptr;
 
   RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
 
   nsIAtom *name = nodeInfo->NameAtom();
 
   NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
                "Trying to HTML elements that don't have the XHTML namespace");
 
   int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
 
+  // https://dom.spec.whatwg.org/#concept-create-element
+  // We only handle the "synchronous custom elements flag is set" now.
+  // For the unset case (e.g. cloning a node), see bug 1319342 for that.
+  // Step 4.
+  CustomElementDefinition* definition = nullptr;
+  if (CustomElementRegistry::IsCustomElementEnabled()) {
+    definition =
+      nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
+                                                    nodeInfo->LocalName(),
+                                                    nodeInfo->NamespaceID(),
+                                                    aIs);
+  }
+
+  // It might be a problem that parser synchronously calls constructor, so filed
+  // bug 1378079 to figure out what we should do for parser case.
+  if (definition) {
+    /*
+     * Synchronous custom elements flag is determined by 3 places in spec,
+     * 1) create an element for a token, the flag is determined by
+     *    "will execute script" which is not originally created
+     *    for the HTML fragment parsing algorithm.
+     * 2) createElement and createElementNS, the flag is the same as
+     *    NOT_FROM_PARSER.
+     * 3) clone a node, our implementation will not go into this function.
+     * For the unset case which is non-synchronous only applied for
+     * inner/outerHTML.
+     */
+    bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT ||
+                                     aFromParser == dom::NOT_FROM_PARSER;
+    // Per discussion in https://github.com/w3c/webcomponents/issues/635,
+    // use entry global in those places that are called from JS APIs.
+    nsIGlobalObject* global = GetEntryGlobal();
+    MOZ_ASSERT(global);
+    AutoEntryScript aes(global, "create custom elements");
+    JSContext* cx = aes.cx();
+    ErrorResult rv;
+
+    // Step 5.
+    if (definition->IsCustomBuiltIn()) {
+      // SetupCustomElement() should be called with an element that don't have
+      // CustomElementData setup, if not we will hit the assertion in
+      // SetCustomElementData().
+      nsCOMPtr<nsIAtom> tagAtom = nodeInfo->NameAtom();
+      nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom;
+      // Built-in element
+      *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
+      (*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
+      if (synchronousCustomElements) {
+        CustomElementRegistry::Upgrade(*aResult, definition, rv);
+      } else {
+        nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
+      }
+
+      if (rv.MaybeSetPendingException(cx)) {
+        aes.ReportException();
+      }
+      return NS_OK;
+    }
+
+    // Step 6.1.
+    if (synchronousCustomElements) {
+      DoCustomElementCreate(aResult, nodeInfo->GetDocument(),
+                            definition->mConstructor, rv);
+      if (rv.MaybeSetPendingException(cx)) {
+        NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser));
+      }
+      return NS_OK;
+    }
+
+    // Step 6.2.
+    NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
+    nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
+    return NS_OK;
+  }
+
   // Per the Custom Element specification, unknown tags that are valid custom
   // element names should be HTMLElement instead of HTMLUnknownElement.
   bool isCustomElementName = (tag == eHTMLTag_userdefined &&
                               nsContentUtils::IsCustomElementName(name));
   if (isCustomElementName) {
     NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
   } else {
     *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -7710,22 +7710,20 @@ private:
   SendBlockedNotification() override;
 
   nsresult
   DispatchToWorkThread() override;
 
   void
   SendResults() override;
 
-#ifdef ENABLE_INTL_API
   static nsresult
   UpdateLocaleAwareIndex(mozIStorageConnection* aConnection,
                          const IndexMetadata& aIndexMetadata,
                          const nsCString& aLocale);
-#endif
 };
 
 class OpenDatabaseOp::VersionChangeOp final
   : public TransactionDatabaseOperationBase
 {
   friend class OpenDatabaseOp;
 
   RefPtr<OpenDatabaseOp> mOpenDatabaseOp;
@@ -19909,19 +19907,16 @@ DatabaseOperationBase::BindKeyRangeToSta
 
 // static
 nsresult
 DatabaseOperationBase::BindKeyRangeToStatement(
                                             const SerializedKeyRange& aKeyRange,
                                             mozIStorageStatement* aStatement,
                                             const nsCString& aLocale)
 {
-#ifndef ENABLE_INTL_API
-  return BindKeyRangeToStatement(aKeyRange, aStatement);
-#else
   MOZ_ASSERT(!IsOnBackgroundThread());
   MOZ_ASSERT(aStatement);
   MOZ_ASSERT(!aLocale.IsEmpty());
 
   nsresult rv = NS_OK;
 
   if (!aKeyRange.lower().IsUnset()) {
     Key lower;
@@ -19949,17 +19944,16 @@ DatabaseOperationBase::BindKeyRangeToSta
 
     rv = upper.BindToStatement(aStatement, NS_LITERAL_CSTRING("upper_key"));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   return NS_OK;
-#endif
 }
 
 // static
 void
 DatabaseOperationBase::AppendConditionClause(const nsACString& aColumnName,
                                              const nsACString& aArgName,
                                              bool aLessThan,
                                              bool aEquals,
@@ -22012,17 +22006,16 @@ OpenDatabaseOp::LoadDatabaseInformation(
 
     rv = stmt->GetInt32(5, &scratch);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     indexMetadata->mCommonMetadata.multiEntry() = !!scratch;
 
-#ifdef ENABLE_INTL_API
     const bool localeAware = !stmt->IsNull(6);
     if (localeAware) {
       rv = stmt->GetUTF8String(6, indexMetadata->mCommonMetadata.locale());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       rv = stmt->GetInt32(7, &scratch);
@@ -22042,17 +22035,16 @@ OpenDatabaseOp::LoadDatabaseInformation(
         rv = UpdateLocaleAwareIndex(aConnection,
                                     indexMetadata->mCommonMetadata,
                                     systemLocale);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
     }
-#endif
 
     if (NS_WARN_IF(!objectStoreMetadata->mIndexes.Put(indexId, indexMetadata,
                                                       fallible))) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     lastIndexId = std::max(lastIndexId, indexId);
   }
@@ -22068,17 +22060,16 @@ OpenDatabaseOp::LoadDatabaseInformation(
   }
 
   mMetadata->mNextObjectStoreId = lastObjectStoreId + 1;
   mMetadata->mNextIndexId = lastIndexId + 1;
 
   return NS_OK;
 }
 
-#ifdef ENABLE_INTL_API
 /* static */
 nsresult
 OpenDatabaseOp::UpdateLocaleAwareIndex(mozIStorageConnection* aConnection,
                                        const IndexMetadata& aIndexMetadata,
                                        const nsCString& aLocale)
 {
   nsresult rv;
 
@@ -22186,17 +22177,16 @@ OpenDatabaseOp::UpdateLocaleAwareIndex(m
   rv = metaStmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), aIndexMetadata.id());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = metaStmt->Execute();
   return rv;
 }
-#endif
 
 nsresult
 OpenDatabaseOp::BeginVersionChange()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State::BeginVersionChange);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   MOZ_ASSERT(mMetadata->mCommonMetadata.version() <= mRequestedVersion);
@@ -27961,33 +27951,29 @@ OpenOp::GetRangeKeyInfo(bool aLowerBound
   MOZ_ASSERT(aOpen);
 
   if (mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange) {
     const SerializedKeyRange& range =
       mOptionalKeyRange.get_SerializedKeyRange();
     if (range.isOnly()) {
       *aKey = range.lower();
       *aOpen = false;
-#ifdef ENABLE_INTL_API
       if (mCursor->IsLocaleAware()) {
         range.lower().ToLocaleBasedKey(*aKey, mCursor->mLocale);
       }
-#endif
     } else {
       *aKey = aLowerBound ? range.lower() : range.upper();
       *aOpen = aLowerBound ? range.lowerOpen() : range.upperOpen();
-#ifdef ENABLE_INTL_API
       if (mCursor->IsLocaleAware()) {
         if (aLowerBound) {
           range.lower().ToLocaleBasedKey(*aKey, mCursor->mLocale);
         } else {
           range.upper().ToLocaleBasedKey(*aKey, mCursor->mLocale);
         }
       }
-#endif
     }
   } else {
     *aOpen = false;
   }
 }
 
 nsresult
 Cursor::
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -60,23 +60,21 @@ IDBCursor::IDBCursor(Type aType,
   MOZ_ASSERT(mScriptOwner);
 
   if (mScriptOwner) {
     mozilla::HoldJSObjects(this);
     mRooted = true;
   }
 }
 
-#ifdef ENABLE_INTL_API
 bool
 IDBCursor::IsLocaleAware() const
 {
   return mSourceIndex && !mSourceIndex->Locale().IsEmpty();
 }
-#endif
 
 IDBCursor::~IDBCursor()
 {
   AssertIsOnOwningThread();
 
   DropJSObjects();
 
   if (mBackgroundActor) {
@@ -432,30 +430,26 @@ IDBCursor::Continue(JSContext* aCx,
   }
 
   Key key;
   aRv = key.SetFromJSVal(aCx, aKey);
   if (aRv.Failed()) {
     return;
   }
 
-#ifdef ENABLE_INTL_API
   if (IsLocaleAware() && !key.IsUnset()) {
     Key tmp;
     aRv = key.ToLocaleBasedKey(tmp, mSourceIndex->Locale());
     if (aRv.Failed()) {
       return;
     }
     key = tmp;
   }
 
   const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
-#else
-  const Key& sortKey = mKey;
-#endif
 
   if (!key.IsUnset()) {
     switch (mDirection) {
       case NEXT:
       case NEXT_UNIQUE:
         if (key <= sortKey) {
           aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
           return;
@@ -542,30 +536,26 @@ IDBCursor::ContinuePrimaryKey(JSContext*
   }
 
   Key key;
   aRv = key.SetFromJSVal(aCx, aKey);
   if (aRv.Failed()) {
     return;
   }
 
-#ifdef ENABLE_INTL_API
   if (IsLocaleAware() && !key.IsUnset()) {
     Key tmp;
     aRv = key.ToLocaleBasedKey(tmp, mSourceIndex->Locale());
     if (aRv.Failed()) {
       return;
     }
     key = tmp;
   }
 
   const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
-#else
-  const Key& sortKey = mKey;
-#endif
 
   if (key.IsUnset()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
     return;
   }
 
   Key primaryKey;
   aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey);
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -200,21 +200,19 @@ public:
 
 private:
   IDBCursor(Type aType,
             indexedDB::BackgroundCursorChild* aBackgroundActor,
             const Key& aKey);
 
   ~IDBCursor();
 
-#ifdef ENABLE_INTL_API
   // Checks if this is a locale aware cursor (ie. the index's sortKey is unset)
   bool
   IsLocaleAware() const;
-#endif
 
   void
   DropJSObjects();
 
   bool
   IsSourceDeleted() const;
 };
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -1311,19 +1311,17 @@ IDBObjectStore::AppendIndexUpdateInfo(
                                     bool aMultiEntry,
                                     const nsCString& aLocale,
                                     JSContext* aCx,
                                     JS::Handle<JS::Value> aVal,
                                     nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
 {
   nsresult rv;
 
-#ifdef ENABLE_INTL_API
   const bool localeAware = !aLocale.IsEmpty();
-#endif
 
   if (!aMultiEntry) {
     Key key;
     rv = aKeyPath.ExtractKey(aCx, aVal, key);
 
     // If an index's keyPath doesn't match an object, we ignore that object.
     if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) {
       return NS_OK;
@@ -1331,24 +1329,22 @@ IDBObjectStore::AppendIndexUpdateInfo(
 
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
     updateInfo->indexId() = aIndexID;
     updateInfo->value() = key;
-#ifdef ENABLE_INTL_API
     if (localeAware) {
       rv = key.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
-#endif
 
     return NS_OK;
   }
 
   JS::Rooted<JS::Value> val(aCx);
   if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, val.address()))) {
     return NS_OK;
   }
@@ -1378,45 +1374,41 @@ IDBObjectStore::AppendIndexUpdateInfo(
           value.IsUnset()) {
         // Not a value we can do anything with, ignore it.
         continue;
       }
 
       IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
       updateInfo->indexId() = aIndexID;
       updateInfo->value() = value;
-#ifdef ENABLE_INTL_API
       if (localeAware) {
         rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
       }
-#endif
     }
   }
   else {
     Key value;
     if (NS_FAILED(value.SetFromJSVal(aCx, val)) ||
         value.IsUnset()) {
       // Not a value we can do anything with, ignore it.
       return NS_OK;
     }
 
     IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
     updateInfo->indexId() = aIndexID;
     updateInfo->value() = value;
-#ifdef ENABLE_INTL_API
     if (localeAware) {
       rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
-#endif
   }
 
   return NS_OK;
 }
 
 // static
 void
 IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
@@ -2272,21 +2264,19 @@ IDBObjectStore::CreateIndex(const nsAStr
     indexes.IsEmpty() ? nullptr : indexes.Elements();
 
   // With this setup we only validate the passed in locale name by the time we
   // get to encoding Keys. Maybe we should do it here right away and error out.
 
   // Valid locale names are always ASCII as per BCP-47.
   nsCString locale = NS_LossyConvertUTF16toASCII(aOptionalParameters.mLocale);
   bool autoLocale = locale.EqualsASCII("auto");
-#ifdef ENABLE_INTL_API
   if (autoLocale) {
     locale = IndexedDatabaseManager::GetLocale();
   }
-#endif
 
   IndexMetadata* metadata = indexes.AppendElement(
     IndexMetadata(transaction->NextIndexId(), nsString(aName), keyPath,
                   locale,
                   aOptionalParameters.mUnique,
                   aOptionalParameters.mMultiEntry,
                   autoLocale));
 
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -40,35 +40,32 @@
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBKeyRange.h"
 #include "IDBRequest.h"
 #include "ProfilerHelpers.h"
 #include "ScriptErrorHelper.h"
 #include "WorkerScope.h"
 #include "WorkerPrivate.h"
+#include "nsCharSeparatedTokenizer.h"
+#include "unicode/locid.h"
 
 // Bindings for ResolveConstructors
 #include "mozilla/dom/IDBCursorBinding.h"
 #include "mozilla/dom/IDBDatabaseBinding.h"
 #include "mozilla/dom/IDBFactoryBinding.h"
 #include "mozilla/dom/IDBIndexBinding.h"
 #include "mozilla/dom/IDBKeyRangeBinding.h"
 #include "mozilla/dom/IDBMutableFileBinding.h"
 #include "mozilla/dom/IDBObjectStoreBinding.h"
 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
 #include "mozilla/dom/IDBRequestBinding.h"
 #include "mozilla/dom/IDBTransactionBinding.h"
 #include "mozilla/dom/IDBVersionChangeEventBinding.h"
 
-#ifdef ENABLE_INTL_API
-#include "nsCharSeparatedTokenizer.h"
-#include "unicode/locid.h"
-#endif
-
 #define IDB_STR "indexedDB"
 
 // The two possible values for the data argument when receiving the disk space
 // observer notification.
 #define LOW_DISK_SPACE_DATA_FULL "full"
 #define LOW_DISK_SPACE_DATA_FREE "free"
 
 namespace mozilla {
@@ -425,17 +422,16 @@ IndexedDatabaseManager::Init()
                                        kPrefLoggingEnabled);
 
   Preferences::RegisterCallbackAndCall(DataThresholdPrefChangedCallback,
                                        kDataThresholdPref);
 
   Preferences::RegisterCallbackAndCall(MaxSerializedMsgSizePrefChangeCallback,
                                        kPrefMaxSerilizedMsgSize);
 
-#ifdef ENABLE_INTL_API
   nsAutoCString acceptLang;
   Preferences::GetLocalizedCString("intl.accept_languages", acceptLang);
 
   // Split values on commas.
   nsCCharSeparatedTokenizer langTokenizer(acceptLang, ',');
   while (langTokenizer.hasMoreTokens()) {
     nsAutoCString lang(langTokenizer.nextToken());
     icu::Locale locale = icu::Locale::createCanonical(lang.get());
@@ -444,17 +440,16 @@ IndexedDatabaseManager::Init()
       mLocale.AssignASCII(locale.getBaseName());
       break;
     }
   }
 
   if (mLocale.IsEmpty()) {
     mLocale.AssignLiteral("en_US");
   }
-#endif
 
   return NS_OK;
 }
 
 void
 IndexedDatabaseManager::Destroy()
 {
   // Setting the closed flag prevents the service from being recreated.
@@ -1088,27 +1083,25 @@ IndexedDatabaseManager::LoggingModePrefC
     sLoggingMode = logDetails ?
                    Logging_DetailedProfilerMarks :
                    Logging_ConciseProfilerMarks;
   } else {
     sLoggingMode = logDetails ? Logging_Detailed : Logging_Concise;
   }
 }
 
-#ifdef ENABLE_INTL_API
 // static
 const nsCString&
 IndexedDatabaseManager::GetLocale()
 {
   IndexedDatabaseManager* idbManager = Get();
   MOZ_ASSERT(idbManager, "IDBManager is not ready!");
 
   return idbManager->mLocale;
 }
-#endif
 
 NS_IMPL_ADDREF(IndexedDatabaseManager)
 NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
 NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver, nsITimerCallback,
                         nsINamed)
 
 NS_IMETHODIMP
 IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic,
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -184,20 +184,18 @@ public:
                             int32_t* aRefCnt,
                             int32_t* aDBRefCnt,
                             int32_t* aSliceRefCnt,
                             bool* aResult);
 
   nsresult
   FlushPendingFileDeletions();
 
-#ifdef ENABLE_INTL_API
   static const nsCString&
   GetLocale();
-#endif
 
   static mozilla::Mutex&
   FileMutex()
   {
     IndexedDatabaseManager* mgr = Get();
     NS_ASSERTION(mgr, "Must have a manager here!");
 
     return mgr->mFileMutex;
@@ -236,19 +234,17 @@ private:
   nsClassHashtable<nsRefPtrHashKey<FileManager>,
                    nsTArray<int64_t>> mPendingDeleteInfos;
 
   // Lock protecting FileManager.mFileInfos.
   // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt
   // and FileInfo.mSliceRefCnt
   mozilla::Mutex mFileMutex;
 
-#ifdef ENABLE_INTL_API
   nsCString mLocale;
-#endif
 
   indexedDB::BackgroundUtilsChild* mBackgroundActor;
 
   static bool sIsMainProcess;
   static bool sFullSynchronousMode;
   static LazyLogModule sLoggingModule;
   static Atomic<LoggingMode> sLoggingMode;
   static mozilla::Atomic<bool> sLowDiskSpaceMode;
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -17,22 +17,19 @@
 #include "mozilla/CheckedInt.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozIStorageStatement.h"
 #include "mozIStorageValueArray.h"
 #include "nsAlgorithm.h"
 #include "nsJSUtils.h"
 #include "ReportInternalError.h"
+#include "unicode/ucol.h"
 #include "xpcpublic.h"
 
-#ifdef ENABLE_INTL_API
-#include "unicode/ucol.h"
-#endif
-
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 /*
  Here's how we encode keys:
 
  Basic strategy is the following
@@ -105,17 +102,17 @@ namespace indexedDB {
  end of the encoded buffer.
 
  "foo"         // 0x30 s s s
  1             // 0x10 bf f0
  ["a", "b"]    // 0x80 s 0 0x30 s
  [1, 2]        // 0x60 bf f0 0 0 0 0 0 0 0x10 c0
  [[]]          // 0x80
 */
-#ifdef ENABLE_INTL_API
+
 nsresult
 Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const
 {
   if (IsUnset()) {
     aTarget.Unset();
     return NS_OK;
   }
 
@@ -202,17 +199,16 @@ Key::ToLocaleBasedKey(Key& aTarget, cons
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
   aTarget.TrimBuffer();
   return NS_OK;
 }
-#endif
 
 nsresult
 Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
                          uint8_t aTypeOffset, uint16_t aRecursionDepth)
 {
   static_assert(eMaxType * kMaxArrayCollapse < 256,
                 "Unable to encode jsvals.");
 
@@ -502,17 +498,16 @@ Key::EncodeAsString(const T* aStart, con
   // Write end marker
   *(buffer++) = eTerminator;
 
   NS_ASSERTION(buffer == mBuffer.EndReading(), "Wrote wrong number of bytes");
 
   return NS_OK;
 }
 
-#ifdef ENABLE_INTL_API
 nsresult
 Key::EncodeLocaleString(const nsDependentString& aString, uint8_t aTypeOffset,
                         const nsCString& aLocale)
 {
   const int length = aString.Length();
   if (length == 0) {
     return NS_OK;
   }
@@ -540,17 +535,16 @@ Key::EncodeLocaleString(const nsDependen
   if (NS_WARN_IF(sortKeyLength == 0)) {
     return NS_ERROR_FAILURE;
   }
 
   return EncodeString(keyBuffer.Elements(),
                       keyBuffer.Elements()+sortKeyLength,
                       aTypeOffset);
 }
-#endif
 
 // static
 nsresult
 Key::DecodeJSVal(const unsigned char*& aPos,
                  const unsigned char* aEnd,
                  JSContext* aCx,
                  JS::MutableHandle<JS::Value> aVal)
 {
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -209,20 +209,18 @@ public:
   ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const;
 
   nsresult
   ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aVal) const;
 
   nsresult
   AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal);
 
-#ifdef ENABLE_INTL_API
   nsresult
   ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const;
-#endif
 
   void
   FinishArray()
   {
     TrimBuffer();
   }
 
   const nsCString&
@@ -293,21 +291,19 @@ private:
   template <typename T>
   nsresult
   EncodeString(const T* aStart, const T* aEnd, uint8_t aTypeOffset);
 
   template <typename T>
   nsresult
   EncodeAsString(const T* aStart, const T* aEnd, uint8_t aType);
 
-#ifdef ENABLE_INTL_API
   nsresult
   EncodeLocaleString(const nsDependentString& aString, uint8_t aTypeOffset,
                      const nsCString& aLocale);
-#endif
 
   void
   EncodeNumber(double aFloat, uint8_t aType);
 
   nsresult
   EncodeBinary(JSObject* aObject, bool aIsViewObject, uint8_t aTypeOffset);
 
   // Decoding functions. aPos points into mBuffer and is adjusted to point
--- a/dom/indexedDB/moz.build
+++ b/dom/indexedDB/moz.build
@@ -2,30 +2,30 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: IndexedDB")
 
-MOCHITEST_MANIFESTS += ['test/mochitest.ini']
+MOCHITEST_MANIFESTS += [
+    'test/mochitest-intl-api.ini',
+    'test/mochitest.ini',
+]
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 XPCSHELL_TESTS_MANIFESTS += [
     'test/unit/xpcshell-child-process.ini',
     'test/unit/xpcshell-parent-process.ini'
 ]
 
-if CONFIG['ENABLE_INTL_API']:
-    MOCHITEST_MANIFESTS += ['test/mochitest-intl-api.ini']
-
 EXPORTS.mozilla.dom += [
     'IDBCursor.h',
     'IDBDatabase.h',
     'IDBEvents.h',
     'IDBFactory.h',
     'IDBFileHandle.h',
     'IDBFileRequest.h',
     'IDBIndex.h',
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -101,19 +101,19 @@ void CubebLogCallback(const char* aFmt, 
 // This mutex protects the variables below.
 StaticMutex sMutex;
 enum class CubebState {
   Uninitialized = 0,
   Initialized,
   Shutdown
 } sCubebState = CubebState::Uninitialized;
 cubeb* sCubebContext;
-double sVolumeScale;
-uint32_t sCubebPlaybackLatencyInMilliseconds;
-uint32_t sCubebMSGLatencyInFrames;
+double sVolumeScale = 1.0;
+uint32_t sCubebPlaybackLatencyInMilliseconds = 100;
+uint32_t sCubebMSGLatencyInFrames = 512;
 bool sCubebPlaybackLatencyPrefSet;
 bool sCubebMSGLatencyPrefSet;
 bool sAudioStreamInitEverSucceeded = false;
 #ifdef MOZ_CUBEB_REMOTING
 bool sCubebSandbox;
 #endif
 StaticAutoPtr<char> sBrandName;
 StaticAutoPtr<char> sCubebBackendName;
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -1,13 +1,14 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+include('/media/webrtc/webrtc.mozbuild')
 
 FILES_PER_UNIFIED_FILE = 6
 
 with Files('*'):
     BUG_COMPONENT = ('Core', 'Audio/Video')
 
 with Files('test/**'):
     BUG_COMPONENT = ('Core', 'Audio/Video: Playback')
@@ -311,21 +312,16 @@ LOCAL_INCLUDES += [
 if CONFIG['MOZ_WEBRTC']:
     LOCAL_INCLUDES += [
         '/media/webrtc/signaling/src/common',
         '/media/webrtc/trunk',
     ]
 
 DEFINES['MOZILLA_INTERNAL_API'] = True
 
-if CONFIG['OS_TARGET'] == 'WINNT':
-    DEFINES['WEBRTC_WIN'] = True
-else:
-    DEFINES['WEBRTC_POSIX'] = True
-
 if CONFIG['ANDROID_VERSION'] > '15':
     DEFINES['MOZ_OMX_WEBM_DECODER'] = True
 
 if CONFIG['MOZ_ANDROID_HLS_SUPPORT']:
     DEFINES['MOZ_ANDROID_HLS_SUPPORT'] = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/dom/media/systemservices/moz.build
+++ b/dom/media/systemservices/moz.build
@@ -1,13 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+include('/media/webrtc/webrtc.mozbuild')
 
 if CONFIG['MOZ_WEBRTC']:
     EXPORTS += [
         'CamerasChild.h',
         'CamerasParent.h',
         'VideoEngine.h',
         'VideoFrameUtils.h'
     ]
@@ -17,22 +18,16 @@ if CONFIG['MOZ_WEBRTC']:
         'ShmemPool.cpp',
         'VideoEngine.cpp',
         'VideoFrameUtils.cpp'
     ]
     LOCAL_INCLUDES += [
         '/media/webrtc/signaling',
         '/media/webrtc/trunk',
     ]
-if CONFIG['OS_TARGET'] == 'WINNT':
-    DEFINES['WEBRTC_WIN'] = True
-else:
-    DEFINES['WEBRTC_POSIX'] = True
-    # Must match build/gyp.mozbuild: enable_libevent
-    DEFINES['WEBRTC_BUILD_LIBEVENT'] = True
 
 if CONFIG['OS_TARGET'] == 'Android':
     DEFINES['WEBRTC_ANDROID'] = True
 
 
 if CONFIG['OS_TARGET'] == 'Android':
     EXPORTS += [
         'OpenSLESProvider.h'
--- a/dom/media/webrtc/moz.build
+++ b/dom/media/webrtc/moz.build
@@ -1,13 +1,14 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+include('/media/webrtc/webrtc.mozbuild')
 
 with Files('*'):
     BUG_COMPONENT = ('Core', 'WebRTC: Audio/Video')
 
 with Files('PeerIdentity.*'):
     BUG_COMPONENT = ('Core', 'WebRTC: Signaling')
 
 XPIDL_MODULE = 'content_webrtc'
@@ -15,20 +16,16 @@ XPIDL_MODULE = 'content_webrtc'
 EXPORTS += [
     'MediaEngine.h',
     'MediaEngineCameraVideoSource.h',
     'MediaEngineDefault.h',
     'MediaTrackConstraints.h',
 ]
 
 if CONFIG['MOZ_WEBRTC']:
-    if CONFIG['OS_TARGET'] == 'WINNT':
-        DEFINES['WEBRTC_WIN'] = True
-    else:
-        DEFINES['WEBRTC_POSIX'] = True
     EXPORTS += ['AudioOutputObserver.h',
                 'MediaEngineRemoteVideoSource.h',
                 'MediaEngineWebRTC.h']
     EXPORTS.mozilla.dom += [ 'RTCIdentityProviderRegistrar.h' ]
     UNIFIED_SOURCES += [
         'MediaEngineCameraVideoSource.cpp',
         'MediaEngineRemoteVideoSource.cpp',
         'MediaEngineTabVideoSource.cpp',
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -1,19 +1,21 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "BasicCardPayment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/PaymentRequest.h"
 #include "mozilla/dom/PaymentResponse.h"
 #include "nsContentUtils.h"
-#include "BasicCardPayment.h"
+#include "nsIURLParser.h"
+#include "nsNetCID.h"
 #include "PaymentRequestManager.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PaymentRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PaymentRequest,
@@ -48,31 +50,217 @@ NS_IMPL_RELEASE_INHERITED(PaymentRequest
 
 bool
 PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj)
 {
   return Preferences::GetBool("dom.payments.request.enabled");
 }
 
 nsresult
+PaymentRequest::IsValidStandardizedPMI(const nsAString& aIdentifier,
+                                       nsAString& aErrorMsg)
+{
+  /*
+   *   The syntax of a standardized payment method identifier is given by the
+   *   following [ABNF]:
+   *
+   *       stdpmi = part *( "-" part )
+   *       part = 1loweralpha *( DIGIT / loweralpha )
+   *       loweralpha =  %x61-7A
+   */
+  nsString::const_iterator start, end;
+  aIdentifier.BeginReading(start);
+  aIdentifier.EndReading(end);
+  while (start != end) {
+    // the first char must be in the range %x61-7A
+    if ((*start < 'a' || *start > 'z')) {
+      aErrorMsg.AssignLiteral("'");
+      aErrorMsg.Append(aIdentifier);
+      aErrorMsg.AppendLiteral("' is not valid. The character '");
+      aErrorMsg.Append(*start);
+      aErrorMsg.AppendLiteral("' at the beginning or after the '-' must be in the range [a-z].");
+      return NS_ERROR_RANGE_ERR;
+    }
+    ++start;
+    // the rest can be in the range %x61-7A + DIGITs
+    while (start != end && *start != '-' &&
+           ((*start >= 'a' && *start <= 'z') || (*start >= '0' && *start <= '9'))) {
+      ++start;
+    }
+    // if the char is not in the range %x61-7A + DIGITs, it must be '-'
+    if (start != end && *start != '-') {
+      aErrorMsg.AssignLiteral("'");
+      aErrorMsg.Append(aIdentifier);
+      aErrorMsg.AppendLiteral("' is not valid. The character '");
+      aErrorMsg.Append(*start);
+      aErrorMsg.AppendLiteral("' must be in the range [a-zA-z0-9-].");
+      return NS_ERROR_RANGE_ERR;
+    }
+    if (*start == '-') {
+      ++start;
+      // the last char can not be '-'
+      if (start == end) {
+        aErrorMsg.AssignLiteral("'");
+        aErrorMsg.Append(aIdentifier);
+        aErrorMsg.AppendLiteral("' is not valid. The last character '");
+        aErrorMsg.Append(*start);
+        aErrorMsg.AppendLiteral("' must be in the range [a-z0-9].");
+        return NS_ERROR_RANGE_ERR;
+      }
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+PaymentRequest::IsValidPaymentMethodIdentifier(const nsAString& aIdentifier,
+                                               nsAString& aErrorMsg)
+{
+  if (aIdentifier.IsEmpty()) {
+    aErrorMsg.AssignLiteral("Payment method identifier is required.");
+    return NS_ERROR_TYPE_ERR;
+  }
+  /*
+   *  URL-based payment method identifier
+   *
+   *  1. If url's scheme is not "https", return false.
+   *  2. If url's username or password is not the empty string, return false.
+   *  3. Otherwise, return true.
+   */
+  nsCOMPtr<nsIURLParser> urlParser = do_GetService(NS_STDURLPARSER_CONTRACTID);
+  MOZ_ASSERT(urlParser);
+  uint32_t schemePos = 0;
+  int32_t schemeLen = 0;
+  uint32_t authorityPos = 0;
+  int32_t authorityLen = 0;
+  NS_ConvertUTF16toUTF8 url(aIdentifier);
+  nsresult rv = urlParser->ParseURL(url.get(),
+                                    url.Length(),
+                                    &schemePos, &schemeLen,
+                                    &authorityPos, &authorityLen,
+                                    nullptr, nullptr);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_RANGE_ERR);
+  if (schemeLen == -1) {
+    // The PMI is not a URL-based PMI, check if it is a standardized PMI
+    return IsValidStandardizedPMI(aIdentifier, aErrorMsg);
+  }
+  if (!Substring(aIdentifier, schemePos, schemeLen).EqualsASCII("https")) {
+    aErrorMsg.AssignLiteral("'");
+    aErrorMsg.Append(aIdentifier);
+    aErrorMsg.AppendLiteral("' is not valid. The scheme must be 'https'.");
+    return NS_ERROR_RANGE_ERR;
+  }
+  if (Substring(aIdentifier, authorityPos, authorityLen).IsEmpty()) {
+    aErrorMsg.AssignLiteral("'");
+    aErrorMsg.Append(aIdentifier);
+    aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty.");
+    return NS_ERROR_RANGE_ERR;
+  }
+
+  uint32_t usernamePos = 0;
+  int32_t usernameLen = 0;
+  uint32_t passwordPos = 0;
+  int32_t passwordLen = 0;
+  uint32_t hostnamePos = 0;
+  int32_t hostnameLen = 0;
+  int32_t port = 0;
+
+  NS_ConvertUTF16toUTF8 authority(Substring(aIdentifier, authorityPos, authorityLen));
+  rv = urlParser->ParseAuthority(authority.get(),
+                                 authority.Length(),
+                                 &usernamePos, &usernameLen,
+                                 &passwordPos, &passwordLen,
+                                 &hostnamePos, &hostnameLen,
+                                 &port);
+  if (NS_FAILED(rv)) {
+    // Handle the special cases that URLParser treats it as an invalid URL, but
+    // are used in web-platform-test
+    // For exmaple:
+    //     https://:@example.com             // should be considered as valid
+    //     https://:password@example.com.    // should be considered as invalid
+    int32_t atPos = authority.FindChar('@');
+    if (atPos >= 0) {
+      // only accept the case https://:@xxx
+      if (atPos == 1 && authority.CharAt(0) == ':') {
+        usernamePos = 0;
+        usernameLen = 0;
+        passwordPos = 0;
+        passwordLen = 0;
+      } else {
+        // for the fail cases, don't care about what the actual length is.
+        usernamePos = 0;
+        usernameLen = INT32_MAX;
+        passwordPos = 0;
+        passwordLen = INT32_MAX;
+      }
+    } else {
+      usernamePos = 0;
+      usernameLen = -1;
+      passwordPos = 0;
+      passwordLen = -1;
+    }
+    // Parse server information when both username and password are empty or do not
+    // exist.
+    if ((usernameLen <= 0) && (passwordLen <= 0)) {
+      if (authority.Length() - atPos - 1 == 0) {
+        aErrorMsg.AssignLiteral("'");
+        aErrorMsg.Append(aIdentifier);
+        aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty.");
+        return NS_ERROR_RANGE_ERR;
+      }
+      // Re-using nsIURLParser::ParseServerInfo to extract the hostname and port
+      // information. This can help us to handle complicated IPv6 cases.
+      nsAutoCString serverInfo(Substring(authority,
+                                         atPos + 1,
+                                         authority.Length() - atPos - 1));
+      rv = urlParser->ParseServerInfo(serverInfo.get(),
+                                      serverInfo.Length(),
+                                      &hostnamePos, &hostnameLen, &port);
+      if (NS_FAILED(rv)) {
+        // ParseServerInfo returns NS_ERROR_MALFORMED_URI in all fail cases, we
+        // probably need a followup bug to figure out the fail reason.
+        return NS_ERROR_RANGE_ERR;
+      }
+    }
+  }
+  // PMI is valid when usernameLen/passwordLen equals to -1 or 0.
+  if (usernameLen > 0 || passwordLen > 0) {
+    aErrorMsg.AssignLiteral("'");
+    aErrorMsg.Append(aIdentifier);
+    aErrorMsg.AssignLiteral("' is not valid. Username and password must be empty.");
+    return NS_ERROR_RANGE_ERR;
+  }
+
+  // PMI is valid when hostnameLen is larger than 0
+  if (hostnameLen <= 0) {
+    aErrorMsg.AssignLiteral("'");
+    aErrorMsg.Append(aIdentifier);
+    aErrorMsg.AppendLiteral("' is not valid. hostname can not be empty.");
+    return NS_ERROR_RANGE_ERR;
+  }
+  return NS_OK;
+}
+
+nsresult
 PaymentRequest::IsValidMethodData(JSContext* aCx,
                                   const Sequence<PaymentMethodData>& aMethodData,
                                   nsAString& aErrorMsg)
 {
   if (!aMethodData.Length()) {
     aErrorMsg.AssignLiteral("At least one payment method is required.");
     return NS_ERROR_TYPE_ERR;
   }
 
   for (const PaymentMethodData& methodData : aMethodData) {
-    if (methodData.mSupportedMethods.IsEmpty()) {
-      aErrorMsg.AssignLiteral(
-        "Payment method identifier is required.");
-      return NS_ERROR_TYPE_ERR;
+    nsresult rv = IsValidPaymentMethodIdentifier(methodData.mSupportedMethods,
+                                                 aErrorMsg);
+    if (NS_FAILED(rv)) {
+      return rv;
     }
+
     RefPtr<BasicCardService> service = BasicCardService::GetService();
     MOZ_ASSERT(service);
     if (service->IsBasicCardPayment(methodData.mSupportedMethods)) {
       if (!methodData.mData.WasPassed()) {
         continue;
       }
       MOZ_ASSERT(aCx);
       if (!service->IsValidBasicCardRequest(aCx,
@@ -294,16 +482,20 @@ PaymentRequest::IsValidDetailsBase(const
       seenIDs.AppendElement(shippingOption.mId);
     }
   }
 
   // Check payment details modifiers
   if (aDetails.mModifiers.WasPassed()) {
     const Sequence<PaymentDetailsModifier>& modifiers = aDetails.mModifiers.Value();
     for (const PaymentDetailsModifier& modifier : modifiers) {
+      rv = IsValidPaymentMethodIdentifier(modifier.mSupportedMethods, aErrorMsg);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
       rv = IsValidCurrencyAmount(NS_LITERAL_STRING("details.modifiers.total"),
                                  modifier.mTotal.mAmount,
                                  true, // isTotalItem
                                  aErrorMsg);
       if (NS_FAILED(rv)) {
         return rv;
       }
       if (modifier.mAdditionalDisplayItems.WasPassed()) {
@@ -372,17 +564,21 @@ PaymentRequest::Constructor(const Global
   } while (node);
 
   // Check payment methods and details
   nsAutoString message;
   nsresult rv = IsValidMethodData(aGlobal.Context(),
                                   aMethodData,
                                   message);
   if (NS_FAILED(rv)) {
-    aRv.ThrowTypeError<MSG_ILLEGAL_TYPE_PR_CONSTRUCTOR>(message);
+    if (rv == NS_ERROR_TYPE_ERR) {
+      aRv.ThrowTypeError<MSG_ILLEGAL_TYPE_PR_CONSTRUCTOR>(message);
+    } else if (rv == NS_ERROR_RANGE_ERR) {
+      aRv.ThrowRangeError<MSG_ILLEGAL_RANGE_PR_CONSTRUCTOR>(message);
+    }
     return nullptr;
   }
   rv = IsValidDetailsInit(aDetails, message);
   if (NS_FAILED(rv)) {
     if (rv == NS_ERROR_TYPE_ERR) {
       aRv.ThrowTypeError<MSG_ILLEGAL_TYPE_PR_CONSTRUCTOR>(message);
     } else if (rv == NS_ERROR_RANGE_ERR) {
       aRv.ThrowRangeError<MSG_ILLEGAL_RANGE_PR_CONSTRUCTOR>(message);
--- a/dom/payments/PaymentRequest.h
+++ b/dom/payments/PaymentRequest.h
@@ -31,16 +31,22 @@ public:
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   static already_AddRefed<PaymentRequest>
   CreatePaymentRequest(nsPIDOMWindowInner* aWindow, nsresult& aRv);
 
   static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
 
+  static nsresult IsValidStandardizedPMI(const nsAString& aIdentifier,
+                                         nsAString& aErrorMsg);
+
+  static nsresult IsValidPaymentMethodIdentifier(const nsAString& aIdentifier,
+                                                 nsAString& aErrorMsg);
+
   static nsresult IsValidMethodData(JSContext* aCx,
                                     const Sequence<PaymentMethodData>& aMethodData,
                                     nsAString& aErrorMsg);
 
   static nsresult
   IsValidNumber(const nsAString& aItem,
                 const nsAString& aStr,
                 nsAString& aErrorMsg);
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/PMIValidationChromeScript.js
@@ -0,0 +1,58 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+
+const UIService = {
+  showPayment: function(requestId) {
+    paymentSrv.changeShippingOption(requestId, "");
+  },
+  abortPayment: function(requestId) {
+    let abortResponse = Cc["@mozilla.org/dom/payments/payment-abort-action-response;1"].
+                           createInstance(Ci.nsIPaymentAbortActionResponse);
+    abortResponse.init(requestId, Ci.nsIPaymentActionResponse.ABORT_SUCCEEDED);
+    paymentSrv.respondPayment(abortResponse.QueryInterface(Ci.nsIPaymentActionResponse));
+  },
+  completePayment: function(requestId) {
+    const completeResponse = Cc["@mozilla.org/dom/payments/payment-complete-action-response;1"].
+                           createInstance(Ci.nsIPaymentCompleteActionResponse);
+    completeResponse.init(requestId, Ci.nsIPaymentActionResponse.COMPLETE_SUCCEEDED);
+    paymentSrv.respondPayment(completeResponse.QueryInterface(Ci.nsIPaymentActionResponse));
+  },
+  updatePayment: function(requestId) {
+    const showResponseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
+                                createInstance(Ci.nsIGeneralResponseData);
+    showResponseData.initData({ paymentToken: "6880281f-0df3-4b8e-916f-66575e2457c1",});
+
+    const showResponse = Cc["@mozilla.org/dom/payments/payment-show-action-response;1"].
+                      createInstance(Ci.nsIPaymentShowActionResponse);
+    showResponse.init(requestId,
+                      Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
+                      "https://example.com",   // payment method
+                      showResponseData,           // payment method data
+                      "Bill A. Pacheco",          // payer name
+                      "",                         // payer email
+                      "");                        // payer phone
+    paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+};
+
+function emitTestFail(message) {
+  sendAsyncMessage("test-fail", message);
+}
+
+addMessageListener("set-ui-service", function() {
+  paymentSrv.setTestingUIService(UIService.QueryInterface(Ci.nsIPaymentUIService));
+});
+
+addMessageListener("teardown", function() {
+  paymentSrv.cleanup();
+  sendAsyncMessage("teardown-complete");
+});
--- a/dom/payments/test/head.js
+++ b/dom/payments/test/head.js
@@ -2,17 +2,17 @@ const kTestRoot = getRootDirectory(gTest
                                                       "https://example.com");
 
 function checkSimplePayment(aSimplePayment) {
   // checking the passed PaymentMethods parameter
   is(aSimplePayment.paymentMethods.length, 1, "paymentMethods' length should be 1.");
 
   const methodData = aSimplePayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
   ok(methodData, "Fail to get payment methodData.");
-  is(methodData.supportedMethods, "MyPay", "supported method should be 'MyPay'.");
+  is(methodData.supportedMethods, "basic-card", "supported method should be 'basic-card'.");
   ok(!methodData.data, "methodData.data should not exist.");
 
   // checking the passed PaymentDetails parameter
   const details = aSimplePayment.paymentDetails;
   is(details.id, "simple details", "details.id should be 'simple details'.");
   is(details.totalItem.label, "Donation", "total item's label should be 'Donation'.");
   is(details.totalItem.amount.currency, "USD", "total item's currency should be 'USD'.");
   is(details.totalItem.amount.value, "55.00", "total item's value should be '55.00'.");
@@ -31,17 +31,17 @@ function checkSimplePayment(aSimplePayme
 }
 
 function checkDupShippingOptionsPayment(aPayment) {
   // checking the passed PaymentMethods parameter
   is(aPayment.paymentMethods.length, 1, "paymentMethods' length should be 1.");
 
   const methodData = aPayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
   ok(methodData, "Fail to get payment methodData.");
-  is(methodData.supportedMethods, "MyPay", "methodData.supportedMethod name should be 'MyPay'.");
+  is(methodData.supportedMethods, "basic-card", "methodData.supportedMethod name should be 'basic-card'.");
   ok(!methodData.data, "methodData.data should not exist.");
 
   // checking the passed PaymentDetails parameter
   const details = aPayment.paymentDetails;
   is(details.id, "duplicate shipping options details", "details.id should be 'duplicate shipping options details'.");
   is(details.totalItem.label, "Donation", "total item's label should be 'Donation'.");
   is(details.totalItem.amount.currency, "USD", "total item's currency should be 'USD'.");
   is(details.totalItem.amount.value, "55.00", "total item's value should be '55.00'.");
--- a/dom/payments/test/mochitest.ini
+++ b/dom/payments/test/mochitest.ini
@@ -3,19 +3,21 @@
 skip-if = !e10s
 scheme = https
 support-files =
   simple_payment_request.html
   BasiccardChromeScript.js
   ConstructorChromeScript.js
   CurrencyAmountValidationChromeScript.js
   GeneralChromeScript.js
+  PMIValidationChromeScript.js
   ShowPaymentChromeScript.js
 
 [test_abortPayment.html]
 run-if = nightly_build # Bug 1390018: Depends on the Nightly-only UI service
 [test_basiccard.html]
 [test_canMakePayment.html]
 run-if = nightly_build # Bug 1390737: Depends on the Nightly-only UI service
 [test_constructor.html]
 [test_currency_amount_validation.html]
 [test_payment-request-in-iframe.html]
+[test_pmi_validation.html]
 [test_showPayment.html]
--- a/dom/payments/test/simple_payment_request.html
+++ b/dom/payments/test/simple_payment_request.html
@@ -4,17 +4,17 @@
     <title>Payment Request Testing</title>
     <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
     <meta content="utf-8" http-equiv="encoding">
   </head>
   <body>
     <script type="text/javascript">
 
     const supportedInstruments = [{
-      supportedMethods: "MyPay",
+      supportedMethods: "basic-card",
     }];
     const details = {
       id: "simple details",
       total: {
         label: "Donation",
         amount: { currency: "USD", value: "55.00" }
       },
     };
--- a/dom/payments/test/test_abortPayment.html
+++ b/dom/payments/test/test_abortPayment.html
@@ -83,16 +83,11 @@ https://bugzilla.mozilla.org/show_bug.cg
       ]
     }, runTests);
   });
 
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1345367">Mozilla Bug 1345367</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
 </pre>
 </body>
 </html>
--- a/dom/payments/test/test_basiccard.html
+++ b/dom/payments/test/test_basiccard.html
@@ -283,16 +283,10 @@ https://bugzilla.mozilla.org/show_bug.cg
       ]
     }, runTests);
   });
 
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1375345">Mozilla Bug 1375345</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
 </body>
 </html>
--- a/dom/payments/test/test_canMakePayment.html
+++ b/dom/payments/test/test_canMakePayment.html
@@ -154,16 +154,10 @@ https://bugzilla.mozilla.org/show_bug.cg
       ]
     }, runTests);
   });
 
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1345365">Mozilla Bug 1345365</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
 </body>
 </html>
--- a/dom/payments/test/test_currency_amount_validation.html
+++ b/dom/payments/test/test_currency_amount_validation.html
@@ -371,16 +371,10 @@ https://bugzilla.mozilla.org/show_bug.cg
     }, runTests);
   });
 
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1367669">Mozilla Bug 1367669</a>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1388661">Mozilla Bug 1388661</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
 </body>
 </html>
--- a/dom/payments/test/test_payment-request-in-iframe.html
+++ b/dom/payments/test/test_payment-request-in-iframe.html
@@ -88,15 +88,10 @@ https://bugzilla.mozilla.org/show_bug.cg
         ['dom.payments.request.enabled', true],
       ]
     }, runTests);
   });
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1318988">Mozilla Bug 1318988</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-</pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/test_pmi_validation.html
@@ -0,0 +1,241 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1389418
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for PaymentRequest API payment method identifier validation</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript">
+
+  "use strict";
+  SimpleTest.waitForExplicitFinish();
+
+  var gUrl = SimpleTest.getTestFileURL('PMIValidationChromeScript.js');
+  var gScript = SpecialPowers.loadChromeScript(gUrl);
+
+  function testFailHandler(message) {
+    ok(false, message);
+  }
+  gScript.addMessageListener("test-fail", testFailHandler);
+
+  const defaultMethods = [{
+    supportedMethods: "basic-card",
+  }];
+
+  const defaultDetails = {
+    total: {
+      label: "total",
+      amount: {
+        currency: "usd",
+        value: "1.00",
+      },
+    },
+  };
+
+  const validPMIs = [
+    "https://wpt",
+    "https://wpt.fyi/",
+    "https://wpt.fyi/payment",
+    "https://wpt.fyi/payment-request",
+    "https://wpt.fyi/payment-request?",
+    "https://wpt.fyi/payment-request?this=is",
+    "https://wpt.fyi/payment-request?this=is&totally",
+    "https://wpt.fyi:443/payment-request?this=is&totally",
+    "https://wpt.fyi:443/payment-request?this=is&totally#fine",
+    "https://:@wpt.fyi:443/payment-request?this=is&totally#👍",
+    " \thttps://wpt\n ",
+    "https://xn--c1yn36f",
+    "https://點看",
+    "e",
+    "n6jzof05mk2g4lhxr-u-q-w1-c-i-pa-ty-bdvs9-ho-ae7-p-md8-s-wq3-h-qd-e-q-sa",
+    "a-b-q-n-s-pw0",
+    "m-u",
+    "s-l5",
+    "k9-f",
+    "m-l",
+    "u4-n-t",
+    "i488jh6-g18-fck-yb-v7-i",
+    "x-x-t-t-c34-o",
+    "basic-card",
+  ];
+
+  const invalidPMIs = [
+    "https://:password@example.com",
+    "https://username@example.com",
+    "https://username:password@example.com/pay",
+    "http://username:password@example.com/pay",
+    "https://:@example.com:100000000/pay",
+    "https://foo.com:100000000/pay",
+    "basic-💳",
+    "not-https://wpt.fyi/payment-request",
+    "../realitive/url",
+    "/absolute/../path?",
+    "https://",
+    "¡basic-*-card!",
+    "Basic-Card",
+    "0",
+    "-",
+    "--",
+    "a--b",
+    "-a--b",
+    "a-b-",
+    "0-",
+    "0-a",
+    "a0--",
+    "A-",
+    "A-B",
+    "A-b",
+    "a-0",
+    "a-0b",
+    " a-b",
+    "\t\na-b",
+    "a-b ",
+    "a-b\n\t",
+  ];
+
+  function testWithValidPMIs() {
+    return new Promise((resolve, reject) => {
+      for (const validPMI of validPMIs) {
+        try {
+          const validMethods = [{supportedMethods: validPMI},];
+          const payRequest = new PaymentRequest(validMethods, defaultDetails);
+          resolve();
+        } catch (e) {
+          ok(false, "Unexpected error '" + e.name + "'.");
+          resolve();
+        }
+      }
+    });
+  }
+
+  function testWithInvalidPMIs() {
+    return new Promise((resolve, reject) => {
+      for (const invalidPMI of invalidPMIs) {
+        try {
+          const invalidMethods = [{supportedMethods: invalidPMI},];
+          const payRequest = new PaymentRequest(invalidMethods, defaultDetails);
+          ok(false, "Expected throw 'RangeError', but got resolved");
+          resolve();
+        } catch (e) {
+          is(e.name, "RangeError", "Expected 'RangeError'.");
+          resolve();
+        }
+      }
+    });
+  }
+
+  function testUpdateWithValidPMI() {
+    gScript.sendAsyncMessage("set-ui-service");
+    return new Promise((resolve, reject) => {
+      const payRequest = new PaymentRequest(defaultMethods, defaultDetails);
+      payRequest.addEventListener("shippingoptionchange", event => {
+        const validDetails = {
+          total: {
+            label: "total",
+            amount: {
+              currency: "USD",
+              value: "1.00",
+            },
+          },
+          modifiers: [{
+            supportedMethods: "https://example.com",
+            total: {
+              label: "total",
+              amount: {
+                currency: "USD",
+                value: "1.00",
+              },
+            }
+          },],
+        }
+        event.updateWith(validDetails);
+      });
+      payRequest.show().then((response) => {
+        response.complete("success").then(() => {
+          resolve();
+        }).catch((e) => {
+          ok(false, "Unexpected error '" + e.name + "'.");
+          resolve();
+        });
+      }).catch((e) => {
+        ok(false, "Unexpected error '" + e.name + "'.");
+        resolve();
+      });
+    });
+  }
+
+  function testUpdateWithInvalidPMI() {
+    gScript.sendAsyncMessage("set-ui-service");
+    return new Promise((resolve, reject) => {
+      const payRequest = new PaymentRequest(defaultMethods, defaultDetails);
+      payRequest.addEventListener("shippingoptionchange", event => {
+        const invalidDetails = {
+          total: {
+            label: "total",
+            amount: {
+              currency: "USD",
+              value: "1.00",
+            },
+          },
+          modifiers: [{
+            supportedMethods: "https://username:password@example.com",
+            total: {
+              label: "total",
+              amount: {
+                currency: "USD",
+                value: "1.00",
+              },
+            },
+          },],
+        }
+        event.updateWith(invalidDetails);
+      });
+      payRequest.show().then((result) => {
+        ok(false, "Expected throw 'RangeError', but got resolved.");
+        resolve();
+      }).catch((e) => {
+        is(e.name, "RangeError", "Expected 'RangeError'.");
+        resolve();
+      });
+    });
+  }
+
+  function teardown() {
+    gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
+      gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
+      gScript.removeMessageListener("test-fail", testFailHandler)
+      gScript.destroy();
+      SimpleTest.finish();
+    });
+    gScript.sendAsyncMessage("teardown");
+  }
+
+  function runTests() {
+    testWithValidPMIs()
+    .then(testWithInvalidPMIs)
+    .then(testUpdateWithValidPMI)
+    .then(testUpdateWithInvalidPMI)
+    .then(teardown)
+    .catch( e => {
+      ok(false, "Unexpected error: " + e.name);
+      SimpleTest.finish();
+    });
+  }
+
+  window.addEventListener('load', function() {
+    SpecialPowers.pushPrefEnv({
+      'set': [
+        ['dom.payments.request.enabled', true],
+      ]
+    }, runTests);
+  });
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1389418">Mozilla Bug 1389418</a>
+</body>
+</html>
--- a/dom/payments/test/test_showPayment.html
+++ b/dom/payments/test/test_showPayment.html
@@ -295,16 +295,10 @@ https://bugzilla.mozilla.org/show_bug.cg
       ]
     }, runTests);
   });
 
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1345366">Mozilla Bug 1345366</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
 </body>
 </html>
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -509,18 +509,16 @@ var interfaceNamesInGlobalScope =
     "HTMLProgressElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLQuoteElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLScriptElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLSelectElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "HTMLShadowElement", stylo: false},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLSourceElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLSpanElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLStyleElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLTableCaptionElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -28,18 +28,16 @@ skip-if = true || stylo # disabled - See
 [test_custom_element_upgrade.html]
 support-files =
   test_upgrade_page.html
   upgrade_tests.js
 [test_nested_content_element.html]
 skip-if = stylo # bug 1293844
 [test_dest_insertion_points.html]
 skip-if = stylo # bug 1293844
-[test_dest_insertion_points_shadow.html]
-skip-if = stylo # bug 1293844
 [test_fallback_dest_insertion_points.html]
 skip-if = stylo # bug 1293844
 [test_detached_style.html]
 skip-if = stylo # bug 1293844
 [test_dynamic_content_element_matching.html]
 skip-if = stylo # bug 1293844
 [test_document_adoptnode.html]
 skip-if = stylo # bug 1293844
@@ -48,37 +46,29 @@ skip-if = stylo # bug 1293844
 [test_document_register.html]
 [test_document_register_base_queue.html]
 [test_document_register_lifecycle.html]
 skip-if = true # disabled - See bug 1390396
 [test_document_register_parser.html]
 [test_document_register_stack.html]
 skip-if = true # disabled - See bug 1390396
 [test_document_shared_registry.html]
-[test_event_dispatch.html]
-skip-if = stylo # bug 1293844
 [test_event_retarget.html]
 skip-if = stylo # bug 1293844
 [test_event_stopping.html]
 skip-if = stylo # bug 1293844
 [test_template.html]
 [test_template_xhtml.html]
 [test_template_custom_elements.html]
 [test_shadowroot.html]
 skip-if = stylo # bug 1293844
 [test_shadowroot_inert_element.html]
 skip-if = stylo # bug 1293844
-[test_shadowroot_host.html]
-skip-if = stylo # bug 1293844
 [test_shadowroot_style.html]
 skip-if = stylo # bug 1293844
-[test_shadowroot_style_multiple_shadow.html]
-skip-if = stylo # bug 1293844
 [test_shadowroot_style_order.html]
 skip-if = stylo # bug 1293844
-[test_shadowroot_youngershadowroot.html]
-skip-if = stylo # bug 1293844
 [test_style_fallback_content.html]
 skip-if = stylo # bug 1293844
 [test_unresolved_pseudo_class.html]
 [test_link_prefetch.html]
 [test_bug1269155.html]
 skip-if = stylo # bug 1293844
deleted file mode 100644
--- a/dom/tests/mochitest/webcomponents/test_dest_insertion_points_shadow.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=999999
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 999999</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=999999">Mozilla Bug 999999</a>
-<p id="display"></p>
-<div id="content">
-<div id="shadowhost"></div>
-</div>
-<pre id="test">
-</pre>
-<script type="application/javascript">
-
-/** Test for Bug 999999 **/
-var host = document.getElementById("shadowhost");
-
-// Test destination insertion points of node distributed to shadow element.
-var olderShadowRoot = host.createShadowRoot();
-var youngerShadowRoot = host.createShadowRoot();
-
-var shadowElem = document.createElement("shadow");
-youngerShadowRoot.appendChild(shadowElem);
-
-var span = document.createElement("span");
-olderShadowRoot.appendChild(span);
-
-is(span.getDestinationInsertionPoints().length, 1, "Child of ShadowRoot should be distributed to shadow insertion point.");
-is(span.getDestinationInsertionPoints()[0], shadowElem, "Shadow element should be in destination insertion point list.");
-
-// Test destination insertion points of node removed from tree.
-olderShadowRoot.removeChild(span);
-is(span.getDestinationInsertionPoints().length, 0, "Node removed from tree should no longer be distributed.");
-
-// Test destination insertion points of fallback content being reprojected into a shadow element.
-var content = document.createElement("content");
-var fallback = document.createElement("span");
-
-content.appendChild(fallback);
-olderShadowRoot.appendChild(content);
-
-is(fallback.getDestinationInsertionPoints().length, 2, "The fallback content should have 2 destination insertion points, the parent content and the shadow element to which it is reprojected.");
-is(fallback.getDestinationInsertionPoints()[0], content, "First destination of the fallback content should be the parent content element.");
-is(fallback.getDestinationInsertionPoints()[1], shadowElem, "Second destination of the fallback content should be the shadow element to which the element is reprojected.");
-
-// Test destination insertion points of fallback content being removed from tree.
-content.removeChild(fallback);
-is(fallback.getDestinationInsertionPoints().length, 0, "The content should no longer be distributed to any nodes because it is no longer fallback content.");
-
-// Test destination insertion points of distributed content after removing shadow insertion point.
-var div = document.createElement("div");
-olderShadowRoot.appendChild(div);
-is(div.getDestinationInsertionPoints().length, 1, "Children in older shadow root should be distributed to shadow insertion point.");
-is(div.getDestinationInsertionPoints()[0], shadowElem, "Destination insertion point should include shadow element.");
-
-youngerShadowRoot.removeChild(shadowElem);
-is(div.getDestinationInsertionPoints().length, 0, "Destination insertion points should be empty after removing shadow element.");
-
-</script>
-</body>
-</html>
--- a/dom/tests/mochitest/webcomponents/test_document_register.html
+++ b/dom/tests/mochitest/webcomponents/test_document_register.html
@@ -102,17 +102,16 @@ function startTest() {
   is(extendedButton.__proto__, extendedProto, "Created element should have the prototype of the extended type.");
   is(extendedButton.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type.");
   is(extendedButton.type, "submit", "Created element should be a button with type of \"submit\"");
 
   // Custom element constructor.
   var constructedButton = new buttonConstructor();
   is(constructedButton.tagName, "BUTTON", "Created element should have local name of BUTTON");
   is(constructedButton.__proto__, extendedProto, "Created element should have the prototype of the extended type.");
-  is(constructedButton.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type.");
 
   // Try creating an element with a custom element name, but not in the html namespace.
   var htmlNamespaceProto = Object.create(HTMLElement.prototype);
   document.registerElement("x-in-html-namespace", { prototype: htmlNamespaceProto });
   var wrongNamespaceElem = document.createElementNS("http://www.w3.org/2000/svg", "x-in-html-namespace");
   isnot(wrongNamespaceElem.__proto__, htmlNamespaceProto, "Definition for element in html namespace should not apply to SVG elements.");
 }
 
--- a/dom/tests/mochitest/webcomponents/test_document_register_lifecycle.html
+++ b/dom/tests/mochitest/webcomponents/test_document_register_lifecycle.html
@@ -286,21 +286,24 @@ function testAttributeChanged() {
   createdElement.setAttribute("changeme", "newvalue");
   createdElement.setAttribute("changeme", "nextvalue");
   createdElement.setAttribute("changeme", "");
   createdElement.removeAttribute("changeme");
 }
 
 function testAttributeChangedExtended() {
   var p = Object.create(HTMLButtonElement.prototype);
-  var callbackCalled = false;
+  var callbackCalled = 0;
   p.attributeChangedCallback = function(name, oldValue, newValue) {
-    is(callbackCalled, false, "Callback should only be called once in this test.");
-    callbackCalled = true;
-    runNextTest();
+    callbackCalled++;
+    if (callbackCalled > 2) {
+      is(false, "Got unexpected attribute changed callback.");
+    } else if (callbackCalled === 2) {
+      runNextTest();
+    }
   };
 
   document.registerElement("x-extended-attribute-change", { prototype: p, extends: "button" });
 
   var elem = document.createElement("button", {is: "x-extended-attribute-change"});
   elem.setAttribute("foo", "bar");
 }
 
deleted file mode 100644
--- a/dom/tests/mochitest/webcomponents/test_event_dispatch.html
+++ /dev/null
@@ -1,458 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=887541
--->
-<head>
-  <title>Test for event model in web components</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887541">Bug 887541</a>
-<script>
-
-var els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"]
-            .getService(SpecialPowers.Ci.nsIEventListenerService);
-
-function eventListener(e) {
-  eventChain.push(this);
-}
-
-function isEventChain(actual, expected, msg) {
-  is(actual.length, expected.length, msg);
-  for (var i = 0; i < expected.length; i++) {
-    is(actual[i], expected[i], msg + " at " + i);
-  }
-
-  // Check to make sure the event chain matches what we get back from nsIEventListenerService.getEventTargetChainFor
-  if (0 < actual.length) {
-    var chain = els.getEventTargetChainFor(actual[0], true); // Events should be dispatched on actual[0].
-    for (var i = 0; i < expected.length; i++) {
-      ok(SpecialPowers.compare(chain[i], expected[i]), msg + " at " + i + " for nsIEventListenerService");
-    }
-  }
-}
-
-/*
- * Test 1: Test of event dispatch through a basic ShadowRoot with content a insertion point.
- *
- * <div elemOne> ------ <shadow-root shadowOne>
- *        |                        |
- * <div elemTwo>            <span elemThree>
- *                                 |
- *                         <content elemFour>
- */
-
-var elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-var elemTwo = document.createElement("div");
-elemTwo.addEventListener("custom", eventListener);
-
-var elemThree = document.createElement("span");
-elemThree.addEventListener("custom", eventListener);
-
-var elemFour = document.createElement("content");
-elemFour.addEventListener("custom", eventListener);
-
-var shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemThree.appendChild(elemFour);
-shadowOne.appendChild(elemThree);
-elemOne.appendChild(elemTwo);
-
-var eventChain = [];
-var customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemFour, elemThree, shadowOne, elemOne], "Event path for test 1 for event dispatched on elemTwo.");
-
-/*
- * Test 2: Test of event dispatch through a nested ShadowRoots with content insertion points.
- *
- * <div elemFive> --- <shadow-root shadowTwo>
- *       |                       |
- * <div elemOne>          <div elemFour> ----- <shadow-root shadowOne>
- *                               |                        |
- *                       <content elemTwo>           <p elemSix>
- *                                                        |
- *                                               <content elemThree>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("content");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("content");
-elemThree.addEventListener("custom", eventListener);
-
-var elemFour = document.createElement("div");
-elemFour.addEventListener("custom", eventListener);
-
-var elemFive = document.createElement("div");
-elemFive.addEventListener("custom", eventListener);
-
-var elemSix = document.createElement("p");
-elemSix.addEventListener("custom", eventListener);
-
-var shadowOne = elemFour.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-var shadowTwo = elemFive.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-elemFive.appendChild(elemOne);
-shadowTwo.appendChild(elemFour);
-elemFour.appendChild(elemTwo);
-shadowOne.appendChild(elemSix);
-elemSix.appendChild(elemThree);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemOne.dispatchEvent(customEvent);
-is(elemOne.getDestinationInsertionPoints().length, 2, "yes");
-isEventChain(eventChain, [elemOne, elemThree, elemSix, shadowOne, elemTwo, elemFour, shadowTwo, elemFive], "Event path for test 2 for event dispatched on elemOne.");
-
-/*
- * Test 3: Test of event dispatch through nested ShadowRoot with content insertion points.
- *
- * <div elemOne> ------- <shadow-root shadowOne>
- *        |                        |
- * <span elemTwo>          <span elemThree> ------------ <shadow-root shadowTwo>
- *                                 |                               |
- *                          <span elemFour>                <content elemSix>
- *                                 |
- *                         <content elemFive>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("span");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("span");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("span");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("content");
-elemSix.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-shadowTwo = elemThree.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-elemOne.appendChild(elemTwo);
-shadowOne.appendChild(elemThree);
-elemThree.appendChild(elemFour);
-elemFour.appendChild(elemFive);
-shadowTwo.appendChild(elemSix);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemFive, elemFour, elemSix, shadowTwo, elemThree, shadowOne, elemOne], "Event path for test 3 for event dispatched on elemTwo.");
-
-/*
- * Test 4: Test of event dispatch through host with multiple ShadowRoots with shadow insertion point.
- *
- * <div elemSeven> --- <shadow-root shadowTwo> (younger ShadowRoot)
- *       |         |             |
- * <div elemOne>   |      <div elemSix> -------- <shadow-root shadowOne>
- *                 |             |                         |
- *                 |     <shadow elemFour>         <content elemFive>
- *                 |             |
- *                 |     <content elemTwo>
- *                 |
- *                 --- <shadow-root shadowThree> (older ShadowRoot)
- *                         |                |
- *                         |       <content elemThree>
- *                         |
- *                  <div elemEight>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("content");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("content");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("shadow");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("div");
-elemSix.addEventListener("custom", eventListener);
-
-var elemSeven = document.createElement("div");
-elemSeven.addEventListener("custom", eventListener);
-
-var elemEight = document.createElement("div");
-elemEight.addEventListener("custom", eventListener);
-
-var shadowThree = elemSeven.createShadowRoot();
-shadowThree.addEventListener("custom", eventListener);
-
-shadowTwo = elemSeven.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemSix.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemSeven.appendChild(elemOne);
-shadowTwo.appendChild(elemSix);
-elemSix.appendChild(elemFour);
-elemFour.appendChild(elemTwo);
-shadowThree.appendChild(elemEight);
-shadowThree.appendChild(elemThree);
-shadowOne.appendChild(elemFive);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemOne.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemOne, elemFive, shadowOne, elemThree, shadowThree, elemTwo, elemFour, elemSix, shadowTwo, elemSeven], "Event path for test 4 for event dispatched on elemOne.");
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemEight.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemEight, elemFive, shadowOne, elemSix, shadowTwo, elemSeven], "Event path for test 4 for event dispatched on elemEight.");
-
-/*
- * Test 5: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
- *
- * <div elemOne> --------- <shadow-root shadowOne>
- *    |      |                        |
- *    |  <p elemThree>        <span elemFour> ------------------------ <shadow-root shadowTwo>
- *    |                          |       |                                        |
- * <span elemTwo>                |   <content select="p" elemFive>       <content elemSeven>
- *                               |
- *                       <content select="span" elemSix>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("span");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("p");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("span");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.select = "p";
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("content");
-elemSix.select = "span";
-elemSix.addEventListener("custom", eventListener);
-
-elemSeven = document.createElement("content");
-elemSeven.addEventListener("custom", eventListener);
-
-shadowTwo = elemFour.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemOne.appendChild(elemTwo);
-elemOne.appendChild(elemThree);
-shadowOne.appendChild(elemFour);
-elemFour.appendChild(elemSix);
-elemFour.appendChild(elemFive);
-shadowTwo.appendChild(elemSeven);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemSeven, shadowTwo, elemSix, elemFour, shadowOne, elemOne], "Event path for test 5 for event dispatched on elemTwo.");
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemThree.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemThree, elemSeven, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 5 for event dispatched on elemThree.");
-
-/*
- * Test 6: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
- *
- * <div elemOne> --------- <shadow-root shadowOne>;
- *    |      |                        |
- *    |  <p elemThree>         <span elemFour> ------ <shadow-root shadowTwo>
- *    |                               |                   |            |
- * <span elemTwo>            <content elemFive>           |  <content select="p" elemSeven>
- *                                                        |
- *                                                 <content select="span" elemSix>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("span");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("p");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("span");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("content");
-elemSix.select = "span";
-elemSix.addEventListener("custom", eventListener);
-
-elemSeven = document.createElement("content");
-elemSeven.select = "p";
-elemSeven.addEventListener("custom", eventListener);
-
-shadowTwo = elemFour.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemOne.appendChild(elemTwo);
-elemOne.appendChild(elemThree);
-shadowOne.appendChild(elemFour);
-elemFour.appendChild(elemFive);
-shadowTwo.appendChild(elemSix);
-shadowTwo.appendChild(elemSeven);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemSix, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 6 for event dispatched on elemTwo.");
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemThree.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemThree, elemSeven, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 6 for event dispatched on elemThree.");
-
-/*
- * Test 7: Test of event dispatch through nested shadowroot with insertion points that match specific tags.
- *
- * <div elemOne> --------- <shadow-root shadowOne>
- *    |      |                        |
- *    |  <p elemThree>         <span elemFour> ------ <shadow-root shadowTwo>
- *    |                               |                         |
- * <span elemTwo>            <content elemFive>           <span elemEight>
- *                                                           |        |
- *                                                           |   <content select="p" elemSeven>
- *                                                           |
- *                                              <content select="span" elemSix>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("span");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("p");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("span");
-elemFour.addEventListener("custom", eventListener);
-
-elemFive = document.createElement("content");
-elemFive.addEventListener("custom", eventListener);
-
-elemSix = document.createElement("content");
-elemSix.select = "span";
-elemSix.addEventListener("custom", eventListener);
-
-elemSeven = document.createElement("content");
-elemSeven.select = "p";
-elemSeven.addEventListener("custom", eventListener);
-
-elemEight = document.createElement("span");
-elemEight.addEventListener("custom", eventListener);
-
-shadowTwo = elemFour.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-elemOne.appendChild(elemTwo);
-elemOne.appendChild(elemThree);
-shadowOne.appendChild(elemFour);
-elemFour.appendChild(elemFive);
-shadowTwo.appendChild(elemEight);
-elemEight.appendChild(elemSix);
-elemEight.appendChild(elemSeven);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemTwo.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemTwo, elemSix, elemEight, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 7 for event dispatched on elemTwo.");
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemThree.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemThree, elemSeven, elemEight, shadowTwo, elemFive, elemFour, shadowOne, elemOne], "Event path for test 7 for event dispatched on elemThree.");
-
-/*
- * Test 8: Test of event dispatch through host with multiple ShadowRoots with shadow insertion point.
- *
- * <div elemOne> --- <shadow-root shadowOne> (younger ShadowRoot)
- *               |             |
- *               |      <div elemFour>
- *               |             |
- *               |     <shadow elemTwo>
- *               |
- *               --- <shadow-root shadowTwo> (older ShadowRoot)
- *                             |
- *                      <div elemThree>
- */
-
-elemOne = document.createElement("div");
-elemOne.addEventListener("custom", eventListener);
-
-elemTwo = document.createElement("shadow");
-elemTwo.addEventListener("custom", eventListener);
-
-elemThree = document.createElement("div");
-elemThree.addEventListener("custom", eventListener);
-
-elemFour = document.createElement("div");
-elemFour.addEventListener("custom", eventListener);
-
-shadowTwo = elemOne.createShadowRoot();
-shadowTwo.addEventListener("custom", eventListener);
-
-shadowOne = elemOne.createShadowRoot();
-shadowOne.addEventListener("custom", eventListener);
-
-shadowOne.appendChild(elemFour);
-elemFour.appendChild(elemTwo);
-shadowTwo.appendChild(elemThree);
-
-eventChain = [];
-customEvent = new CustomEvent("custom", { "bubbles" : true, "composed" : true });
-elemThree.dispatchEvent(customEvent);
-isEventChain(eventChain, [elemThree, shadowTwo, elemTwo, elemFour, shadowOne, elemOne], "Event path for test 8 for event dispatched on elemThree.");
-
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_host.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1083587
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 1083587</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1083587">Mozilla Bug 1083587</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-<div id="host"></div>
-</div>
-<pre id="test">
-</pre>
-<script type="application/javascript">
-
-/** Test for Bug 1083587 **/
-var hostInDoc = document.getElementById("host");
-var shadowOne = hostInDoc.createShadowRoot();
-is(shadowOne.host, hostInDoc);
-
-var shadowTwo = hostInDoc.createShadowRoot();
-is(shadowOne.host, hostInDoc);
-is(shadowTwo.host, hostInDoc);
-
-var hostNotInDoc = document.createElement("div");
-var shadowThree = hostNotInDoc.createShadowRoot();
-is(shadowThree.host, hostNotInDoc);
-
-var shadowFour = hostNotInDoc.createShadowRoot();
-is(shadowThree.host, hostNotInDoc);
-is(shadowFour.host, hostNotInDoc);
-
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=806506
--->
-<head>
-  <title>Test for ShadowRoot styles with multiple ShadowRoot on host.</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<div class="tall" id="bodydiv"></div>
-<div id="container"></div>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
-<script>
-// Create ShadowRoot.
-var container = document.getElementById("container");
-var elem = document.createElement("div");
-container.appendChild(elem); // Put ShadowRoot host in document.
-var firstRoot = elem.createShadowRoot();
-var secondRoot = elem.createShadowRoot();
-var thirdRoot = elem.createShadowRoot();
-
-// A style element that will be appended into the ShadowRoot.
-var firstStyle = document.createElement("style");
-firstRoot.appendChild(firstStyle);
-is(firstRoot.styleSheets.length, 1, "firstStyle should be the only style in firstRoot.");
-is(firstRoot.styleSheets[0].ownerNode, firstStyle, "firstStyle should in the ShadowRoot styleSheets.");
-
-var secondStyle = document.createElement("style");
-secondRoot.appendChild(secondStyle);
-is(secondRoot.styleSheets.length, 1, "secondStyle should be the only style in secondRoot.");
-is(secondRoot.styleSheets[0].ownerNode, secondStyle, "secondStyle should in the ShadowRoot styleSheets.");
-
-var thirdStyle = document.createElement("style");
-thirdRoot.appendChild(thirdStyle);
-is(thirdRoot.styleSheets.length, 1, "thirdStyle should be the only style in thirdRoot.");
-is(thirdRoot.styleSheets[0].ownerNode, thirdStyle, "thirdStyle should in the ShadowRoot styleSheets.");
-
-// Check the stylesheet counts again to make sure that none of the style sheets leaked into the older ShadowRoots.
-is(firstRoot.styleSheets.length, 1, "Adding a stylesheet to a younger ShadowRoot should not affect stylesheets in the older ShadowRoot.");
-is(secondRoot.styleSheets.length, 1, "Adding a stylesheet to a younger ShadowRoot should not affect stylesheets in the older ShadowRoot.");
-
-// Remove styles and make sure they are removed from the correct ShadowRoot.
-firstRoot.removeChild(firstStyle);
-is(firstRoot.styleSheets.length, 0, "firstRoot should no longer have any styles.");
-
-thirdRoot.removeChild(thirdStyle);
-is(thirdRoot.styleSheets.length, 0, "thirdRoot should no longer have any styles.");
-
-secondRoot.removeChild(secondStyle);
-is(secondRoot.styleSheets.length, 0, "secondRoot should no longer have any styles.");
-
-</script>
-</body>
-</html>
-
deleted file mode 100644
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_youngershadowroot.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1083587
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 1083587</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1083587">Mozilla Bug 1083587</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-<div id="host"></div>
-</div>
-<pre id="test">
-</pre>
-<script type="application/javascript">
-
-/** Test for Bug 1083587 **/
-var hostInDoc = document.getElementById("host");
-var shadowOne = hostInDoc.createShadowRoot();
-is(shadowOne.olderShadowRoot, null);
-
-var shadowTwo = hostInDoc.createShadowRoot();
-is(shadowOne.olderShadowRoot, null);
-is(shadowTwo.olderShadowRoot, shadowOne);
-
-var hostNotInDoc = document.createElement("div");
-var shadowThree = hostNotInDoc.createShadowRoot();
-is(shadowThree.olderShadowRoot, null);
-
-var shadowFour = hostNotInDoc.createShadowRoot();
-is(shadowThree.olderShadowRoot, null);
-is(shadowFour.olderShadowRoot, shadowThree);
-
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/dom/webidl/HTMLShadowElement.webidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * The origin of this IDL file is
- * https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html
- *
- * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
- * Opera Software ASA. You are granted a license to use, reproduce
- * and create derivative works of this document.
- */
-
-[Func="nsDocument::IsWebComponentsEnabled"]
-interface HTMLShadowElement : HTMLElement
-{
-  readonly attribute ShadowRoot? olderShadowRoot;
-};
-
--- a/dom/webidl/ShadowRoot.webidl
+++ b/dom/webidl/ShadowRoot.webidl
@@ -15,13 +15,12 @@ interface ShadowRoot : DocumentFragment
 {
   Element? getElementById(DOMString elementId);
   HTMLCollection getElementsByTagName(DOMString localName);
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);
   [CEReactions, SetterThrows, TreatNullAs=EmptyString]
   attribute DOMString innerHTML;
   readonly attribute Element host;
-  readonly attribute ShadowRoot? olderShadowRoot;
   attribute boolean applyAuthorStyles;
   readonly attribute StyleSheetList styleSheets;
 };
 
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -515,17 +515,15 @@ partial interface Window {
    *
    * This API always returns at least one locale.
    *
    * Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"]
    */
   [Func="IsChromeOrXBL"]
   sequence<DOMString> getRegionalPrefsLocales();
 
-#ifdef ENABLE_INTL_API
   /**
    * Getter funcion for IntlUtils, which provides helper functions for
    * localization.
    */
   [Throws, Func="IsChromeOrXBL"]
   readonly attribute IntlUtils intlUtils;
-#endif
 };
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -611,17 +611,16 @@ WEBIDL_FILES = [
     'HTMLParagraphElement.webidl',
     'HTMLParamElement.webidl',
     'HTMLPictureElement.webidl',
     'HTMLPreElement.webidl',
     'HTMLProgressElement.webidl',
     'HTMLQuoteElement.webidl',
     'HTMLScriptElement.webidl',
     'HTMLSelectElement.webidl',
-    'HTMLShadowElement.webidl',
     'HTMLSourceElement.webidl',
     'HTMLSpanElement.webidl',
     'HTMLStyleElement.webidl',
     'HTMLTableCaptionElement.webidl',
     'HTMLTableCellElement.webidl',
     'HTMLTableColElement.webidl',
     'HTMLTableElement.webidl',
     'HTMLTableRowElement.webidl',
@@ -651,16 +650,17 @@ WEBIDL_FILES = [
     'ImageBitmap.webidl',
     'ImageBitmapRenderingContext.webidl',
     'ImageCapture.webidl',
     'ImageData.webidl',
     'ImageDocument.webidl',
     'InputEvent.webidl',
     'InspectorUtils.webidl',
     'IntersectionObserver.webidl',
+    'IntlUtils.webidl',
     'IterableIterator.webidl',
     'KeyAlgorithm.webidl',
     'KeyboardEvent.webidl',
     'KeyEvent.webidl',
     'KeyframeAnimationOptions.webidl',
     'KeyframeEffect.webidl',
     'KeyIdsInitData.webidl',
     'LegacyQueryInterface.webidl',
@@ -1139,13 +1139,8 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser'
     WEBIDL_FILES += [
         'External.webidl',
     ]
 
 if CONFIG['ACCESSIBILITY']:
     WEBIDL_FILES += [
         'AccessibleNode.webidl',
     ]
-
-if CONFIG['ENABLE_INTL_API']:
-    WEBIDL_FILES += [
-        'IntlUtils.webidl',
-    ]
--- a/editor/libeditor/HTMLEditUtils.cpp
+++ b/editor/libeditor/HTMLEditUtils.cpp
@@ -715,17 +715,16 @@ static const ElementInfo kElements[eHTML
   ELEM(rtc, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(ruby, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(s, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   ELEM(samp, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(script, true, false, GROUP_HEAD_CONTENT | GROUP_SPECIAL,
        GROUP_LEAF),
   ELEM(section, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
   ELEM(select, true, false, GROUP_FORMCONTROL, GROUP_SELECT_CONTENT),
-  ELEM(shadow, true, false, GROUP_NONE, GROUP_INLINE_ELEMENT),
   ELEM(small, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   ELEM(source, false, false, GROUP_PICTURE_CONTENT, GROUP_NONE),
   ELEM(span, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(strike, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
   ELEM(strong, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
   ELEM(style, true, false, GROUP_HEAD_CONTENT, GROUP_LEAF),
   ELEM(sub, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
   ELEM(summary, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
--- a/gfx/moz.build
+++ b/gfx/moz.build
@@ -26,17 +26,17 @@ DIRS += [
     'vr',
     'config',
     'webrender_bindings',
 ]
 
 if CONFIG['MOZ_ENABLE_SKIA']:
     DIRS += ['skia']
 
-if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY'] and CONFIG['ENABLE_INTL_API']:
+if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
      DIRS += ['sfntly/cpp/src']
 
 if CONFIG['ENABLE_TESTS']:
     DIRS += ['tests/gtest']
 
 TEST_DIRS += ['tests']
 
 SPHINX_TREES['gfx'] = 'docs'
--- a/gfx/skia/generate_mozbuild.py
+++ b/gfx/skia/generate_mozbuild.py
@@ -96,17 +96,17 @@ elif CONFIG['_MSC_VER']:
     SOURCES['skia/src/opts/SkOpts_hsw.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=52']
 elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:
     CXXFLAGS += CONFIG['NEON_FLAGS']
 elif CONFIG['CPU_ARCH'] == 'aarch64' and CONFIG['GNU_CC']:
     SOURCES['skia/src/opts/SkOpts_crc32.cpp'].flags += ['-march=armv8-a+crc']
 
 DEFINES['SKIA_IMPLEMENTATION'] = 1
 
-if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY'] and CONFIG['ENABLE_INTL_API']:
+if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
     DEFINES['SK_PDF_USE_SFNTLY'] = 1
 
 if not CONFIG['MOZ_ENABLE_SKIA_GPU']:
     DEFINES['SK_SUPPORT_GPU'] = 0
 
 if CONFIG['MOZ_TREE_FREETYPE']:
     DEFINES['SK_CAN_USE_DLOPEN'] = 0
 
--- a/gfx/skia/moz.build
+++ b/gfx/skia/moz.build
@@ -738,17 +738,17 @@ elif CONFIG['_MSC_VER']:
     SOURCES['skia/src/opts/SkOpts_hsw.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=52']
 elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:
     CXXFLAGS += CONFIG['NEON_FLAGS']
 elif CONFIG['CPU_ARCH'] == 'aarch64' and CONFIG['GNU_CC']:
     SOURCES['skia/src/opts/SkOpts_crc32.cpp'].flags += ['-march=armv8-a+crc']
 
 DEFINES['SKIA_IMPLEMENTATION'] = 1
 
-if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY'] and CONFIG['ENABLE_INTL_API']:
+if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
     DEFINES['SK_PDF_USE_SFNTLY'] = 1
 
 if not CONFIG['MOZ_ENABLE_SKIA_GPU']:
     DEFINES['SK_SUPPORT_GPU'] = 0
 
 if CONFIG['MOZ_TREE_FREETYPE']:
     DEFINES['SK_CAN_USE_DLOPEN'] = 0
 
--- a/image/ImageFactory.cpp
+++ b/image/ImageFactory.cpp
@@ -81,40 +81,60 @@ ComputeImageFlags(ImageURL* uri, const n
   rv = uri->SchemeIs("data", &isDataURI);
   if (NS_SUCCEEDED(rv) && isDataURI) {
     imageFlags |= Image::INIT_FLAG_SYNC_LOAD;
   }
 
   return imageFlags;
 }
 
+#ifdef DEBUG
+static void
+NotifyImageLoading(ImageURL* aURI)
+{
+  if (!NS_IsMainThread()) {
+    RefPtr<ImageURL> uri(aURI);
+    nsCOMPtr<nsIRunnable> ev =
+      NS_NewRunnableFunction("NotifyImageLoading", [uri] () -> void {
+        NotifyImageLoading(uri);
+    });
+    SystemGroup::Dispatch(TaskCategory::Other, ev.forget());
+    return;
+  }
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
+  if (obs) {
+    nsAutoCString spec;
+    aURI->GetSpec(spec);
+    obs->NotifyObservers(nullptr, "image-loading", NS_ConvertUTF8toUTF16(spec).get());
+  }
+}
+#endif
+
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateImage(nsIRequest* aRequest,
                           ProgressTracker* aProgressTracker,
                           const nsCString& aMimeType,
                           ImageURL* aURI,
                           bool aIsMultiPart,
                           uint32_t aInnerWindowId)
 {
   MOZ_ASSERT(gfxPrefs::SingletonExists(),
              "Pref observers should have been initialized already");
 
   // Compute the image's initialization flags.
   uint32_t imageFlags = ComputeImageFlags(aURI, aMimeType, aIsMultiPart);
 
 #ifdef DEBUG
   // Record the image load for startup performance testing.
-  if (NS_IsMainThread()) {
-    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-    NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
-    if (obs) {
-      nsAutoCString spec;
-      aURI->GetSpec(spec);
-      obs->NotifyObservers(nullptr, "image-loading", NS_ConvertUTF8toUTF16(spec).get());
-    }
+  bool match = false;
+  if ((NS_SUCCEEDED(aURI->SchemeIs("resource", &match)) && match) ||
+      (NS_SUCCEEDED(aURI->SchemeIs("chrome", &match)) && match)) {
+    NotifyImageLoading(aURI);
   }
 #endif
 
   // Select the type of image to create based on MIME type.
   if (aMimeType.EqualsLiteral(IMAGE_SVG_XML)) {
     return CreateVectorImage(aRequest, aProgressTracker, aMimeType,
                              aURI, imageFlags, aInnerWindowId);
   } else {
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -1695,16 +1695,22 @@ RasterImage::GetFramesNotified(uint32_t*
 #ifdef DEBUG
 void
 RasterImage::NotifyDrawingObservers()
 {
   if (!mURI || !NS_IsMainThread()) {
     return;
   }
 
+  bool match = false;
+  if ((NS_FAILED(mURI->SchemeIs("resource", &match)) || !match) &&
+      (NS_FAILED(mURI->SchemeIs("chrome", &match)) || !match)) {
+    return;
+  }
+
   // Record the image drawing for startup performance testing.
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
   if (obs) {
     nsCOMPtr<nsIURI> imageURI = mURI->ToIURI();
     nsAutoCString spec;
     imageURI->GetSpec(spec);
     obs->NotifyObservers(nullptr, "image-drawing", NS_ConvertUTF8toUTF16(spec).get());
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -454,23 +454,36 @@ imgRequest::GetCurrentURI(nsIURI** aURI)
     NS_ADDREF(*aURI);
     return NS_OK;
   }
 
   return NS_ERROR_FAILURE;
 }
 
 bool
+imgRequest::IsScheme(const char* aScheme) const
+{
+  MOZ_ASSERT(aScheme);
+  bool isScheme = false;
+  if (NS_WARN_IF(NS_FAILED(mURI->SchemeIs(aScheme, &isScheme)))) {
+    return false;
+  }
+  return isScheme;
+}
+
+bool
 imgRequest::IsChrome() const
 {
-  bool isChrome = false;
-  if (NS_WARN_IF(NS_FAILED(mURI->SchemeIs("chrome", &isChrome)))) {
-    return false;
-  }
-  return isChrome;
+  return IsScheme("chrome");
+}
+
+bool
+imgRequest::IsData() const
+{
+  return IsScheme("data");
 }
 
 nsresult
 imgRequest::GetImageErrorCode()
 {
   return mImageErrorCode;
 }
 
@@ -814,23 +827,27 @@ imgRequest::OnStartRequest(nsIRequest* a
 
   // Shouldn't we be dead already if this gets hit?
   // Probably multipart/x-mixed-replace...
   RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
   if (progressTracker->ObserverCount() == 0) {
     this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
   }
 
-  // Try to retarget OnDataAvailable to a decode thread.
-  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
+  // Try to retarget OnDataAvailable to a decode thread. We must process data
+  // URIs synchronously as per the spec however.
+  if (!channel || IsData()) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsIThreadRetargetableRequest> retargetable =
     do_QueryInterface(aRequest);
-  if (httpChannel && retargetable) {
+  if (retargetable) {
     nsAutoCString mimeType;
-    nsresult rv = httpChannel->GetContentType(mimeType);
+    nsresult rv = channel->GetContentType(mimeType);
     if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) {
       // Retarget OnDataAvailable to the DecodePool's IO thread.
       nsCOMPtr<nsIEventTarget> target =
         DecodePool::Singleton()->GetIOEventTarget();
       rv = retargetable->RetargetDeliveryTo(target);
     }
     MOZ_LOG(gImgLog, LogLevel::Warning,
            ("[this=%p] imgRequest::OnStartRequest -- "
--- a/image/imgRequest.h
+++ b/image/imgRequest.h
@@ -148,17 +148,19 @@ public:
   const ImageCacheKey& CacheKey() const { return mCacheKey; }
 
   // Resize the cache entry to 0 if it exists
   void ResetCacheEntry();
 
   // OK to use on any thread.
   nsresult GetURI(ImageURL** aURI);
   nsresult GetCurrentURI(nsIURI** aURI);
+  bool IsScheme(const char* aScheme) const;
   bool IsChrome() const;
+  bool IsData() const;
 
   nsresult GetImageErrorCode(void);
 
   /// Returns true if we've received any data.
   bool HasTransferredData() const;
 
   /// Returns a non-owning pointer to this imgRequest's MIME type.
   const char* GetMimeType() const { return mContentType.get(); }
--- a/intl/lwbrk/nsJISx4051LineBreaker.cpp
+++ b/intl/lwbrk/nsJISx4051LineBreaker.cpp
@@ -551,20 +551,18 @@ GetClass(uint32_t u)
     /* CONDITIONAL_JAPANESE_STARTER = 37, [CJ] */ CLASS_CLOSE,
     /* HEBREW_LETTER = 38,                [HL] */ CLASS_CHARACTER,
     /* REGIONAL_INDICATOR = 39,           [RI] */ CLASS_CHARACTER,
     /* E_BASE = 40,                       [EB] */ CLASS_BREAKABLE,
     /* E_MODIFIER = 41,                   [EM] */ CLASS_CHARACTER,
     /* ZWJ = 42,                          [ZWJ]*/ CLASS_CHARACTER
   };
 
-#if ENABLE_INTL_API
   static_assert(U_LB_COUNT == mozilla::ArrayLength(sUnicodeLineBreakToClass),
                 "Gecko vs ICU LineBreak class mismatch");
-#endif
 
   auto cls = mozilla::unicode::GetLineBreakClass(u);
   MOZ_ASSERT(cls < mozilla::ArrayLength(sUnicodeLineBreakToClass));
   return sUnicodeLineBreakToClass[cls];
 }
 
 static bool
 GetPair(int8_t c1, int8_t c2)
--- a/intl/unicharutil/tools/genUnicodePropertyData.pl
+++ b/intl/unicharutil/tools/genUnicodePropertyData.pl
@@ -4,31 +4,28 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # This tool is used to prepare lookup tables of Unicode character properties
 # needed by gfx code to support text shaping operations. The properties are
 # read from the Unicode Character Database and compiled into multi-level arrays
 # for efficient lookup.
 #
+# Note that for most properties, we now rely on ICU; this tool and the tables
+# it generates are used only for a couple of properties not readily exposed
+# via ICU APIs.
+#
 # To regenerate the tables in nsUnicodePropertyData.cpp:
 #
 # (1) Download the current Unicode data files from
 #
 #         http://www.unicode.org/Public/UNIDATA/
 #
 #     NB: not all the files are actually needed; currently, we require
 #       - UnicodeData.txt
-#       - Scripts.txt
-#       - BidiMirroring.txt
-#       - BidiBrackets.txt
-#       - HangulSyllableType.txt
-#       - LineBreak.txt
-#       - EastAsianWidth.txt
-#       - DerivedCoreProperties.txt
 #       - ReadMe.txt (to record version/date of the UCD)
 #       - Unihan_Variants.txt (from Unihan.zip)
 #     though this may change if we find a need for additional properties.
 #
 #     The Unicode data files listed above should be together in one directory.
 #
 #     We also require the file
 #        http://www.unicode.org/Public/security/latest/IdentifierStatus.txt
@@ -39,103 +36,74 @@
 #        http://www.unicode.org/Public/vertical/revision-17/VerticalOrientation-17.txt
 #     This file should be in a sub-directory "vertical" immediately below the
 #        directory containing the other Unicode data files.
 #
 #
 # (2) Run this tool using a command line of the form
 #
 #         perl genUnicodePropertyData.pl      \
-#                 /path/to/harfbuzz/src       \
 #                 /path/to/icu/common/unicode \
 #                 /path/to/UCD-directory
 #
 #     This will generate (or overwrite!) the files
 #
 #         nsUnicodePropertyData.cpp
 #         nsUnicodeScriptCodes.h
 #
 #     in the current directory.
 
 use strict;
 use List::Util qw(first);
 
-if ($#ARGV != 2) {
+if ($#ARGV != 1) {
     print <<__EOT;
 # Run this tool using a command line of the form
 #
 #     perl genUnicodePropertyData.pl      \\
-#             /path/to/harfbuzz/src       \\
 #             /path/to/icu/common/unicode \\
 #             /path/to/UCD-directory
 #
-# where harfbuzz/src is the directory containing harfbuzz .cc and .hh files,
-# icu/common/unicode is the directory containing ICU 'common' public headers,
+# where icu/common/unicode is the directory containing ICU 'common' headers,
 # and UCD-directory is a directory containing the current Unicode Character
 # Database files (UnicodeData.txt, etc), available from
 # http://www.unicode.org/Public/UNIDATA/, with additional resources as
 # detailed in the source comments.
 #
 # This will generate (or overwrite!) the files
 #
 #     nsUnicodePropertyData.cpp
 #     nsUnicodeScriptCodes.h
 #
 # in the current directory.
 __EOT
     exit 0;
 }
 
-my $HARFBUZZ = $ARGV[0];
-my $ICU = $ARGV[1];
-my $UNICODE = $ARGV[2];
-
-# load HB_Category constants
-
-my $cc = -1;
-my %catCode;
+my $ICU = $ARGV[0];
+my $UNICODE = $ARGV[1];
 
-sub readHarfBuzzHeader
-{
-    my $file = shift;
-    open FH, "< $HARFBUZZ/$file" or die "can't open harfbuzz header $HARFBUZZ/$file\n";
-    while (<FH>) {
-        if (m/HB_UNICODE_GENERAL_CATEGORY_([A-Z_]+)/) {
-            $cc++;
-            $catCode{$1} = $cc;
-        }
-    }
-    close FH;
-}
-
-&readHarfBuzzHeader("hb-unicode.h");
-
-die "didn't find HarfBuzz category codes\n" if $cc == -1;
-
-my %scriptCode;
-my @scriptCodeToTag;
 my @scriptCodeToName;
+my @idtype;
 
 my $sc = -1;
 
 sub readIcuHeader
 {
     my $file = shift;
     open FH, "< $ICU/$file" or die "can't open ICU header $ICU/$file\n";
     while (<FH>) {
         # adjust for ICU vs UCD naming discrepancies
         s/LANNA/TAI_THAM/;
         s/MEITEI_MAYEK/MEETEI_MAYEK/;
         s/ORKHON/OLD_TURKIC/;
         s/MENDE/MENDE_KIKAKUI/;
         s/SIGN_WRITING/SIGNWRITING/;
         if (m|USCRIPT_([A-Z_]+)\s*=\s*([0-9]+),\s*/\*\s*([A-Z][a-z]{3})\s*\*/|) {
             $sc = $2;
-            $scriptCode{$1} = $sc;
-            $scriptCodeToTag[$sc] = $3;
             $scriptCodeToName[$sc] = $1;
         }
     }
     close FH;
 }
 
 &readIcuHeader("uscript.h");
 
@@ -165,254 +133,66 @@ my %idType = (
 );
 
 # These match the IdentifierType enum in nsUnicodeProperties.h.
 my %mappedIdType = (
   "Restricted"   => 0,
   "Allowed"      => 1
 );
 
-my %bidicategoryCode = (
-  "L"   =>  0, # Left-to-Right
-  "R"   =>  1, # Right-to-Left
-  "EN"  =>  2, # European Number
-  "ES"  =>  3, # European Number Separator
-  "ET"  =>  4, # European Number Terminator
-  "AN"  =>  5, # Arabic Number
-  "CS"  =>  6, # Common Number Separator
-  "B"   =>  7, # Paragraph Separator
-  "S"   =>  8, # Segment Separator
-  "WS"  =>  9, # Whitespace
-  "ON"  => 10, # Other Neutrals
-  "LRE" => 11, # Left-to-Right Embedding
-  "LRO" => 12, # Left-to-Right Override
-  "AL"  => 13, # Right-to-Left Arabic
-  "RLE" => 14, # Right-to-Left Embedding
-  "RLO" => 15, # Right-to-Left Override
-  "PDF" => 16, # Pop Directional Format
-  "NSM" => 17, # Non-Spacing Mark
-  "BN"  => 18, # Boundary Neutral
-  "FSI" => 19, # First Strong Isolate
-  "LRI" => 20, # Left-to-Right Isolate
-  "RLI" => 21, # Right-to-left Isolate
-  "PDI" => 22  # Pop Direcitonal Isolate
-);
-
 my %verticalOrientationCode = (
   'U' => 0,  #   U - Upright, the same orientation as in the code charts
   'R' => 1,  #   R - Rotated 90 degrees clockwise compared to the code charts
   'Tu' => 2, #   Tu - Transformed typographically, with fallback to Upright
   'Tr' => 3  #   Tr - Transformed typographically, with fallback to Rotated
 );
 
-my %lineBreakCode = ( # ordering matches ICU's ULineBreak enum
-  "XX" => 0,
-  "AI" => 1,
-  "AL" => 2,
-  "B2" => 3,
-  "BA" => 4,
-  "BB" => 5,
-  "BK" => 6,
-  "CB" => 7,
-  "CL" => 8,
-  "CM" => 9,
-  "CR" => 10,
-  "EX" => 11,
-  "GL" => 12,
-  "HY" => 13,
-  "ID" => 14,
-  "IN" => 15,
-  "IS" => 16,
-  "LF" => 17,
-  "NS" => 18,
-  "NU" => 19,
-  "OP" => 20,
-  "PO" => 21,
-  "PR" => 22,
-  "QU" => 23,
-  "SA" => 24,
-  "SG" => 25,
-  "SP" => 26,
-  "SY" => 27,
-  "ZW" => 28,
-  "NL" => 29,
-  "WJ" => 30,
-  "H2" => 31,
-  "H3" => 32,
-  "JL" => 33,
-  "JT" => 34,
-  "JV" => 35,
-  "CP" => 36,
-  "CJ" => 37,
-  "HL" => 38,
-  "RI" => 39,
-  "EB" => 40,
-  "EM" => 41,
-  "ZWJ" => 42
-);
-
-my %eastAsianWidthCode = (
-  "N" => 0,
-  "A" => 1,
-  "H" => 2,
-  "W" => 3,
-  "F" => 4,
-  "Na" => 5
-);
-
 # initialize default properties
-my @script;
-my @category;
-my @combining;
-my @mirror;
-my @pairedBracketType;
-my @hangul;
-my @casemap;
-my @idtype;
-my @numericvalue;
 my @hanVariant;
-my @bidicategory;
 my @fullWidth;
 my @fullWidthInverse;
 my @verticalOrientation;
-my @lineBreak;
-my @eastAsianWidthFWH;
-my @defaultIgnorable;
 for (my $i = 0; $i < 0x110000; ++$i) {
-    $script[$i] = $scriptCode{"UNKNOWN"};
-    $category[$i] = $catCode{"UNASSIGNED"};
-    $combining[$i] = 0;
-    $pairedBracketType[$i] = 0;
-    $casemap[$i] = 0;
-    $idtype[$i] = $mappedIdType{'Restricted'};
-    $numericvalue[$i] = -1;
     $hanVariant[$i] = 0;
-    $bidicategory[$i] = $bidicategoryCode{"L"};
     $fullWidth[$i] = 0;
     $fullWidthInverse[$i] = 0;
     $verticalOrientation[$i] = 1; # default for unlisted codepoints is 'R'
-    $lineBreak[$i] = $lineBreakCode{"XX"};
-    $eastAsianWidthFWH[$i] = 0;
-    $defaultIgnorable[$i] = 0;
 }
 
-# blocks where the default for bidi category is not L
-for my $i (0x0600..0x07BF, 0x08A0..0x08FF, 0xFB50..0xFDCF, 0xFDF0..0xFDFF, 0xFE70..0xFEFF, 0x1EE00..0x0001EEFF) {
-  $bidicategory[$i] = $bidicategoryCode{"AL"};
-}
-for my $i (0x0590..0x05FF, 0x07C0..0x089F, 0xFB1D..0xFB4F, 0x00010800..0x00010FFF, 0x0001E800..0x0001EDFF, 0x0001EF00..0x0001EFFF) {
-  $bidicategory[$i] = $bidicategoryCode{"R"};
-}
-for my $i (0x20A0..0x20CF) {
-  $bidicategory[$i] = $bidicategoryCode{"ET"};
-}
-
-my %ucd2hb = (
-'Cc' => 'CONTROL',
-'Cf' => 'FORMAT',
-'Cn' => 'UNASSIGNED',
-'Co' => 'PRIVATE_USE',
-'Cs' => 'SURROGATE',
-'Ll' => 'LOWERCASE_LETTER',
-'Lm' => 'MODIFIER_LETTER',
-'Lo' => 'OTHER_LETTER',
-'Lt' => 'TITLECASE_LETTER',
-'Lu' => 'UPPERCASE_LETTER',
-'Mc' => 'SPACING_MARK',
-'Me' => 'ENCLOSING_MARK',
-'Mn' => 'NON_SPACING_MARK',
-'Nd' => 'DECIMAL_NUMBER',
-'Nl' => 'LETTER_NUMBER',
-'No' => 'OTHER_NUMBER',
-'Pc' => 'CONNECT_PUNCTUATION',
-'Pd' => 'DASH_PUNCTUATION',
-'Pe' => 'CLOSE_PUNCTUATION',
-'Pf' => 'FINAL_PUNCTUATION',
-'Pi' => 'INITIAL_PUNCTUATION',
-'Po' => 'OTHER_PUNCTUATION',
-'Ps' => 'OPEN_PUNCTUATION',
-'Sc' => 'CURRENCY_SYMBOL',
-'Sk' => 'MODIFIER_SYMBOL',
-'Sm' => 'MATH_SYMBOL',
-'So' => 'OTHER_SYMBOL',
-'Zl' => 'LINE_SEPARATOR',
-'Zp' => 'PARAGRAPH_SEPARATOR',
-'Zs' => 'SPACE_SEPARATOR'
-);
-
 # read ReadMe.txt
 my @versionInfo;
 open FH, "< $UNICODE/ReadMe.txt" or die "can't open Unicode ReadMe.txt file\n";
 while (<FH>) {
     chomp;
     push @versionInfo, $_;
 }
 close FH;
 
-my $kTitleToUpper = 0x80000000;
-my $kUpperToLower = 0x40000000;
-my $kLowerToTitle = 0x20000000;
-my $kLowerToUpper = 0x10000000;
-my $kCaseMapCharMask = 0x001fffff;
-
 # read UnicodeData.txt
 open FH, "< $UNICODE/UnicodeData.txt" or die "can't open UCD file UnicodeData.txt\n";
 while (<FH>) {
     chomp;
     my @fields = split /;/;
     if ($fields[1] =~ /First/) {
         my $first = hex "0x$fields[0]";
         $_ = <FH>;
         @fields = split /;/;
         if ($fields[1] =~ /Last/) {
             my $last = hex "0x$fields[0]";
             do {
-                $category[$first] = $catCode{$ucd2hb{$fields[2]}};
-                $combining[$first] = $fields[3];
-                $bidicategory[$first] = $bidicategoryCode{$fields[4]};
-                unless (length($fields[7]) == 0) {
-                  $numericvalue[$first] = $fields[7];
-                }
                 if ($fields[1] =~ /CJK/) {
                   @hanVariant[$first] = 3;
                 }
                 $first++;
             } while ($first <= $last);
         } else {
             die "didn't find Last code for range!\n";
         }
     } else {
         my $usv = hex "0x$fields[0]";
-        $category[$usv] = $catCode{$ucd2hb{$fields[2]}};
-        $combining[$usv] = $fields[3];
-        my $upper = hex $fields[12];
-        my $lower = hex $fields[13];
-        my $title = hex $fields[14];
-        # we only store one mapping for each character,
-        # but also record what kind of mapping it is
-        if ($upper && $lower) {
-            $casemap[$usv] |= $kTitleToUpper;
-            $casemap[$usv] |= ($usv ^ $upper);
-        }
-        elsif ($lower) {
-            $casemap[$usv] |= $kUpperToLower;
-            $casemap[$usv] |= ($usv ^ $lower);
-        }
-        elsif ($title && ($title != $upper)) {
-            $casemap[$usv] |= $kLowerToTitle;
-            $casemap[$usv] |= ($usv ^ $title);
-        }
-        elsif ($upper) {
-            $casemap[$usv] |= $kLowerToUpper;
-            $casemap[$usv] |= ($usv ^ $upper);
-        }
-        $bidicategory[$usv] = $bidicategoryCode{$fields[4]};
-        unless (length($fields[7]) == 0) {
-          $numericvalue[$usv] = $fields[7];
-        }
         if ($fields[1] =~ /CJK/) {
           @hanVariant[$usv] = 3;
         }
         if ($fields[5] =~ /^<narrow>/) {
           my $wideChar = hex(substr($fields[5], 9));
           die "didn't expect supplementary-plane values here" if $usv > 0xffff || $wideChar > 0xffff;
           $fullWidth[$usv] = $wideChar;
           $fullWidthInverse[$wideChar] = $usv;
@@ -422,188 +202,16 @@ while (<FH>) {
           die "didn't expect supplementary-plane values here" if $usv > 0xffff || $narrowChar > 0xffff;
           $fullWidth[$narrowChar] = $usv;
           $fullWidthInverse[$usv] = $narrowChar;
         }
     }
 }
 close FH;
 
-# read Scripts.txt
-open FH, "< $UNICODE/Scripts.txt" or die "can't open UCD file Scripts.txt\n";
-push @versionInfo, "";
-while (<FH>) {
-    chomp;
-    push @versionInfo, $_;
-    last if /Date:/;
-}
-while (<FH>) {
-    if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s+;\s+([^ ]+)/) {
-        my $script = uc($3);
-        unless (exists $scriptCode{$script}) {
-            warn "unknown ICU script $script";
-            $scriptCode{$script} = $scriptCode{"UNKNOWN"};
-        }
-        $script = $scriptCode{$script};
-        my $start = hex "0x$1";
-        my $end = (defined $2) ? hex "0x$2" : $start;
-        for (my $i = $start; $i <= $end; ++$i) {
-            $script[$i] = $script;
-        }
-    }
-}
-close FH;
-
-# read BidiMirroring.txt
-my @offsets = ();
-push @offsets, 0;
-
-open FH, "< $UNICODE/BidiMirroring.txt" or die "can't open UCD file BidiMirroring.txt\n";
-push @versionInfo, "";
-while (<FH>) {
-    chomp;
-    push @versionInfo, $_;
-    last if /Date:/;
-}
-while (<FH>) {
-    s/#.*//;
-    if (m/([0-9A-F]{4,6});\s*([0-9A-F]{4,6})/) {
-        my $mirrorOffset = hex("0x$2") - hex("0x$1");
-        my $offsetIndex = first { $offsets[$_] eq $mirrorOffset } 0..$#offsets;
-        if ($offsetIndex == undef) {
-            die "too many offset codes\n" if scalar @offsets == 31;
-            push @offsets, $mirrorOffset;
-            $offsetIndex = $#offsets;
-        }
-        $mirror[hex "0x$1"] = $offsetIndex;
-    }
-}
-close FH;
-
-# read BidiBrackets.txt
-my %pairedBracketTypeCode = (
-  'N' => 0,
-  'O' => 1,
-  'C' => 2
-);
-open FH, "< $UNICODE/BidiBrackets.txt" or die "can't open UCD file BidiBrackets.txt\n";
-push @versionInfo, "";
-while (<FH>) {
-    chomp;
-    push @versionInfo, $_;
-    last if /Date:/;
-}
-while (<FH>) {
-    s/#.*//;
-    if (m/([0-9A-F]{4,6});\s*([0-9A-F]{4,6});\s*(.)/) {
-        my $mirroredChar = $offsets[$mirror[hex "0x$1"]] + hex "0x$1";
-        die "bidi bracket does not match mirrored char\n" unless $mirroredChar == hex "0x$2";
-        my $pbt = uc($3);
-        warn "unknown Bidi Bracket type" unless exists $pairedBracketTypeCode{$pbt};
-        $pairedBracketType[hex "0x$1"] = $pairedBracketTypeCode{$pbt};
-    }
-}
-close FH;
-
-# read HangulSyllableType.txt
-my %hangulType = (
-  'L'   => 0x01,
-  'V'   => 0x02,
-  'T'   => 0x04,
-  'LV'  => 0x03,
-  'LVT' => 0x07
-);
-open FH, "< $UNICODE/HangulSyllableType.txt" or die "can't open UCD file HangulSyllableType.txt\n";
-push @versionInfo, "";
-while (<FH>) {
-    chomp;
-    push @versionInfo, $_;
-    last if /Date:/;
-}
-while (<FH>) {
-    s/#.*//;
-    if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) {
-        my $hangul = uc($3);
-        warn "unknown Hangul syllable type" unless exists $hangulType{$hangul};
-        $hangul = $hangulType{$hangul};
-        my $start = hex "0x$1";
-        my $end = (defined $2) ? hex "0x$2" : $start;
-        for (my $i = $start; $i <= $end; ++$i) {
-            $hangul[$i] = $hangul;
-        }
-    }
-}
-close FH;
-
-# read LineBreak.txt
-open FH, "< $UNICODE/LineBreak.txt" or die "can't open UCD file LineBreak.txt\n";
-push @versionInfo, "";
-while (<FH>) {
-    chomp;
-    push @versionInfo, $_;
-    last if /Date:/;
-}
-while (<FH>) {
-    s/#.*//;
-    if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) {
-        my $lb = uc($3);
-        warn "unknown LineBreak class" unless exists $lineBreakCode{$lb};
-        $lb = $lineBreakCode{$lb};
-        my $start = hex "0x$1";
-        my $end = (defined $2) ? hex "0x$2" : $start;
-        for (my $i = $start; $i <= $end; ++$i) {
-            $lineBreak[$i] = $lb;
-        }
-    }
-}
-close FH;
-
-# read EastAsianWidth.txt
-open FH, "< $UNICODE/EastAsianWidth.txt" or die "can't open UCD file EastAsianWidth.txt\n";
-push @versionInfo, "";
-while (<FH>) {
-    chomp;
-    push @versionInfo, $_;
-    last if /Date:/;
-}
-while (<FH>) {
-    s/#.*//;
-    if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) {
-        my $start = hex "0x$1";
-        my $end = (defined $2) ? hex "0x$2" : $start;
-        my $eaw = $3;
-        warn "unknown EastAsianWidth class" unless exists $eastAsianWidthCode{$eaw};
-        my $isFWH = ($eaw =~ m/^[FWH]$/) ? 1 : 0;
-        for (my $i = $start; $i <= $end; ++$i) {
-            $eastAsianWidthFWH[$i] = $isFWH;
-        }
-    }
-}
-close FH;
-
-# read DerivedCoreProperties.txt (for Default-Ignorables)
-open FH, "< $UNICODE/DerivedCoreProperties.txt" or die "can't open UCD file DerivedCoreProperties.txt\n";
-push @versionInfo, "";
-while (<FH>) {
-    chomp;
-    push @versionInfo, $_;
-    last if /Date:/;
-}
-while (<FH>) {
-    s/#.*//;
-    if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*Default_Ignorable_Code_Point/) {
-        my $start = hex "0x$1";
-        my $end = (defined $2) ? hex "0x$2" : $start;
-        for (my $i = $start; $i <= $end; ++$i) {
-            $defaultIgnorable[$i] = 1;
-        }
-    }
-}
-close FH;
-
 # read IdentifierStatus.txt
 open FH, "< $UNICODE/security/IdentifierStatus.txt" or die "can't open UCD file IdentifierStatus.txt\n";
 push @versionInfo, "";
 while (<FH>) {
   chomp;
   s/\xef\xbb\xbf//;
   push @versionInfo, $_;
   last if /Date:/;
@@ -730,162 +338,77 @@ print HEADER <<__END;
  * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
  */
 
 #ifndef NS_UNICODE_SCRIPT_CODES
 #define NS_UNICODE_SCRIPT_CODES
 
 __END
 
-print DATA_TABLES "#if !ENABLE_INTL_API\n";
-print DATA_TABLES "static const uint32_t sScriptCodeToTag[] = {\n";
-for (my $i = 0; $i < scalar @scriptCodeToTag; ++$i) {
-  printf DATA_TABLES "  HB_TAG('%c','%c','%c','%c')", unpack('cccc', $scriptCodeToTag[$i]);
-  print DATA_TABLES $i < $#scriptCodeToTag ? ",\n" : "\n";
-}
-print DATA_TABLES "};\n";
-print DATA_TABLES "#endif\n\n";
-
 our $totalData = 0;
 
-print DATA_TABLES "#if !ENABLE_INTL_API\n";
-print DATA_TABLES "static const int16_t sMirrorOffsets[] = {\n";
-for (my $i = 0; $i < scalar @offsets; ++$i) {
-    printf DATA_TABLES "  $offsets[$i]";
-    print DATA_TABLES $i < $#offsets ? ",\n" : "\n";
-}
-print DATA_TABLES "};\n";
-print DATA_TABLES "#endif\n\n";
-
 print HEADER "#pragma pack(1)\n\n";
 
-sub sprintCharProps1
-{
-  my $usv = shift;
-  return sprintf("{%d,%d,%d}, ", $mirror[$usv], $hangul[$usv], $combining[$usv]);
-}
-my $type = q/
-struct nsCharProps1 {
-  unsigned char mMirrorOffsetIndex:5;
-  unsigned char mHangulType:3;
-  unsigned char mCombiningClass:8;
-};
-/;
-&genTables("#if !ENABLE_INTL_API", "#endif",
-           "CharProp1", $type, "nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1);
-
 sub sprintCharProps2_short
 {
   my $usv = shift;
   return sprintf("{%d,%d},",
                  $verticalOrientation[$usv], $idtype[$usv]);
 }
-$type = q|
+my $type = q|
 struct nsCharProps2 {
   // Currently only 4 bits are defined here, so 4 more could be added without
   // affecting the storage requirements for this struct. Or we could pack two
   // records per byte, at the cost of a slightly more complex accessor.
   unsigned char mVertOrient:2;
   unsigned char mIdType:2;
 };
 |;
-&genTables("#if ENABLE_INTL_API", "#endif",
-           "CharProp2", $type, "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1);
-
-sub sprintCharProps2_full
-{
-  my $usv = shift;
-  return sprintf("{%d,%d,%d,%d,%d,%d,%d,%d,%d,%d},",
-                 $script[$usv], $pairedBracketType[$usv],
-                 $eastAsianWidthFWH[$usv], $category[$usv],
-                 $idtype[$usv], $defaultIgnorable[$usv], $bidicategory[$usv],
-                 $verticalOrientation[$usv], $lineBreak[$usv],
-                 $numericvalue[$usv]);
-}
-$type = q|
-// This struct currently requires 5 bytes. We try to ensure that whole-byte
-// fields will not straddle byte boundaries, to optimize access to them.
-struct nsCharProps2 {
-  unsigned char mScriptCode:8;
-  // -- byte boundary --
-  unsigned char mPairedBracketType:2;
-  unsigned char mEastAsianWidthFWH:1;
-  unsigned char mCategory:5;
-  // -- byte boundary --
-  unsigned char mIdType:2;
-  unsigned char mDefaultIgnorable:1;
-  unsigned char mBidiCategory:5;
-  // -- byte boundary --
-  unsigned char mVertOrient:2;
-  unsigned char mLineBreak:6;
-  // -- byte boundary --
-  signed char   mNumericValue; // only 5 bits are actually needed here
-};
-|;
-&genTables("#if !ENABLE_INTL_API", "#endif",
-           "CharProp2", $type, "nsCharProps2", 12, 4, \&sprintCharProps2_full, 16, 5, 1);
+&genTables("CharProp2", $type, "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1);
 
 print HEADER "#pragma pack()\n\n";
 
 sub sprintHanVariants
 {
   my $baseUsv = shift;
   my $varShift = 0;
   my $val = 0;
   while ($varShift < 8) {
     $val |= $hanVariant[$baseUsv++] << $varShift;
     $varShift += 2;
   }
   return sprintf("0x%02x,", $val);
 }
 ## Han Variant data currently unused but may be needed in future, see bug 857481
-## &genTables("", "", "HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4);
+## &genTables("HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4);
 
 sub sprintFullWidth
 {
   my $usv = shift;
   return sprintf("0x%04x,", $fullWidth[$usv]);
 }
-&genTables("", "", "FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1);
+&genTables("FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1);
 
 sub sprintFullWidthInverse
 {
   my $usv = shift;
   return sprintf("0x%04x,", $fullWidthInverse[$usv]);
 }
-&genTables("", "", "FullWidthInverse", "", "uint16_t", 10, 6, \&sprintFullWidthInverse, 0, 2, 1);
-
-sub sprintCasemap
-{
-  my $usv = shift;
-  return sprintf("0x%08x,", $casemap[$usv]);
-}
-&genTables("#if !ENABLE_INTL_API", "#endif",
-           "CaseMap", "", "uint32_t", 11, 5, \&sprintCasemap, 1, 4, 1);
+&genTables("FullWidthInverse", "", "uint16_t", 10, 6, \&sprintFullWidthInverse, 0, 2, 1);
 
 print STDERR "Total data = $totalData\n";
 
-printf DATA_TABLES "const uint32_t kTitleToUpper = 0x%08x;\n", $kTitleToUpper;
-printf DATA_TABLES "const uint32_t kUpperToLower = 0x%08x;\n", $kUpperToLower;
-printf DATA_TABLES "const uint32_t kLowerToTitle = 0x%08x;\n", $kLowerToTitle;
-printf DATA_TABLES "const uint32_t kLowerToUpper = 0x%08x;\n", $kLowerToUpper;
-printf DATA_TABLES "const uint32_t kCaseMapCharMask = 0x%08x;\n\n", $kCaseMapCharMask;
-
 sub genTables
 {
-  my ($guardBegin, $guardEnd,
-      $prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_;
+  my ($prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_;
 
   if ($typedef ne '') {
-    print HEADER "$guardBegin\n";
     print HEADER "$typedef\n";
-    print HEADER "$guardEnd\n\n";
   }
 
-  print DATA_TABLES "\n$guardBegin\n";
   print DATA_TABLES "#define k${prefix}MaxPlane  $maxPlane\n";
   print DATA_TABLES "#define k${prefix}IndexBits $indexBits\n";
   print DATA_TABLES "#define k${prefix}CharBits  $charBits\n";
 
   my $indexLen = 1 << $indexBits;
   my $charsPerPage = 1 << $charBits;
   my %charIndex = ();
   my %pageMapIndex = ();
@@ -944,17 +467,16 @@ sub genTables
   my $pageLen = $charsPerPage / $charsPerEntry;
   print DATA_TABLES "static const $type s${prefix}Values[$chCount][$pageLen] = {\n";
   for (my $i = 0; $i < scalar @char; ++$i) {
     print DATA_TABLES "  {";
     print DATA_TABLES $char[$i];
     print DATA_TABLES $i < $#char ? "},\n" : "}\n";
   }
   print DATA_TABLES "};\n";
-  print DATA_TABLES "$guardEnd\n";
 
   my $dataSize = $pmCount * $indexLen * $pmBits/8 +
                  $chCount * $pageLen * $bytesPerEntry + 
                  $maxPlane;
   $totalData += $dataSize;
 
   print STDERR "Data for $prefix = $dataSize\n";
 }
--- a/intl/unicharutil/util/nsUnicodeProperties.cpp
+++ b/intl/unicharutil/util/nsUnicodeProperties.cpp
@@ -8,40 +8,16 @@
 #include "nsUnicodePropertyData.cpp"
 
 #include "mozilla/ArrayUtils.h"
 #include "nsCharTraits.h"
 
 #define UNICODE_BMP_LIMIT 0x10000
 #define UNICODE_LIMIT     0x110000
 
-#ifndef ENABLE_INTL_API
-static const nsCharProps1&
-GetCharProps1(uint32_t aCh)
-{
-    if (aCh < UNICODE_BMP_LIMIT) {
-        return sCharProp1Values[sCharProp1Pages[0][aCh >> kCharProp1CharBits]]
-                               [aCh & ((1 << kCharProp1CharBits) - 1)];
-    }
-    if (aCh < (kCharProp1MaxPlane + 1) * 0x10000) {
-        return sCharProp1Values[sCharProp1Pages[sCharProp1Planes[(aCh >> 16) - 1]]
-                                               [(aCh & 0xffff) >> kCharProp1CharBits]]
-                               [aCh & ((1 << kCharProp1CharBits) - 1)];
-    }
-
-    // Default values for unassigned
-    static const nsCharProps1 undefined = {
-        0,       // Index to mirrored char offsets
-        0,       // Hangul Syllable type
-        0        // Combining class
-    };
-    return undefined;
-}
-#endif
-
 const nsCharProps2&
 GetCharProps2(uint32_t aCh)
 {
     if (aCh < UNICODE_BMP_LIMIT) {
         return sCharProp2Values[sCharProp2Pages[0][aCh >> kCharProp2CharBits]]
                               [aCh & ((1 << kCharProp2CharBits) - 1)];
     }
     if (aCh < (kCharProp2MaxPlane + 1) * 0x10000) {
@@ -49,31 +25,18 @@ GetCharProps2(uint32_t aCh)
                                                [(aCh & 0xffff) >> kCharProp2CharBits]]
                                [aCh & ((1 << kCharProp2CharBits) - 1)];
     }
 
     NS_NOTREACHED("Getting CharProps for codepoint outside Unicode range");
     // Default values for unassigned
     using namespace mozilla::unicode;
     static const nsCharProps2 undefined = {
-#if ENABLE_INTL_API
         VERTICAL_ORIENTATION_R,
         0 // IdentifierType
-#else
-        uint8_t(Script::UNKNOWN),
-        PAIRED_BRACKET_TYPE_NONE,
-        0, // EastAsianWidthFWH
-        HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,
-        0, // IdentifierType
-        0, // DefaultIgnorable
-        eCharType_LeftToRight,
-        VERTICAL_ORIENTATION_R,
-        0, // LineBreak
-        -1 // Numeric Value
-#endif
     };
     return undefined;
 }
 
 namespace mozilla {
 
 namespace unicode {
 
@@ -130,17 +93,16 @@ const nsUGenCategory sDetailedToGeneralC
   /* MODIFIER_SYMBOL */     nsUGenCategory::kSymbol,
   /* MATH_SYMBOL */         nsUGenCategory::kSymbol,
   /* OTHER_SYMBOL */        nsUGenCategory::kSymbol,
   /* LINE_SEPARATOR */      nsUGenCategory::kSeparator,
   /* PARAGRAPH_SEPARATOR */ nsUGenCategory::kSeparator,
   /* SPACE_SEPARATOR */     nsUGenCategory::kSeparator
 };
 
-#ifdef ENABLE_INTL_API
 const hb_unicode_general_category_t sICUtoHBcategory[U_CHAR_CATEGORY_COUNT] = {
   HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, // U_GENERAL_OTHER_TYPES = 0,
   HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, // U_UPPERCASE_LETTER = 1,
   HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, // U_LOWERCASE_LETTER = 2,
   HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, // U_TITLECASE_LETTER = 3,
   HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, // U_MODIFIER_LETTER = 4,
   HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, // U_OTHER_LETTER = 5,
   HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, // U_NON_SPACING_MARK = 6,
@@ -163,152 +125,16 @@ const hb_unicode_general_category_t sICU
   HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, // U_OTHER_PUNCTUATION = 23,
   HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, // U_MATH_SYMBOL = 24,
   HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, // U_CURRENCY_SYMBOL = 25,
   HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, // U_MODIFIER_SYMBOL = 26,
   HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, // U_OTHER_SYMBOL = 27,
   HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, // U_INITIAL_PUNCTUATION = 28,
   HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, // U_FINAL_PUNCTUATION = 29,
 };
-#endif
-
-#if !ENABLE_INTL_API
-uint8_t GetGeneralCategory(uint32_t aCh) {
-  return GetCharProps2(aCh).mCategory;
-}
-
-nsCharType GetBidiCat(uint32_t aCh) {
-  return nsCharType(GetCharProps2(aCh).mBidiCategory);
-}
-
-int8_t GetNumericValue(uint32_t aCh) {
-  return GetCharProps2(aCh).mNumericValue;
-}
-
-uint32_t
-GetMirroredChar(uint32_t aCh)
-{
-    return aCh + sMirrorOffsets[GetCharProps1(aCh).mMirrorOffsetIndex];
-}
-
-bool
-HasMirroredChar(uint32_t aCh)
-{
-    return GetCharProps1(aCh).mMirrorOffsetIndex != 0;
-}
-
-uint8_t
-GetCombiningClass(uint32_t aCh)
-{
-    return GetCharProps1(aCh).mCombiningClass;
-}
-
-uint8_t
-GetLineBreakClass(uint32_t aCh)
-{
-    return GetCharProps2(aCh).mLineBreak;
-}
-
-Script
-GetScriptCode(uint32_t aCh)
-{
-    return Script(GetCharProps2(aCh).mScriptCode);
-}
-
-uint32_t
-GetScriptTagForCode(Script aScriptCode)
-{
-    // this will safely return 0 for negative script codes, too :)
-    if (static_cast<uint32_t>(aScriptCode) > ArrayLength(sScriptCodeToTag)) {
-        return 0;
-    }
-    return sScriptCodeToTag[static_cast<uint32_t>(aScriptCode)];
-}
-
-PairedBracketType GetPairedBracketType(uint32_t aCh)
-{
-  return PairedBracketType(GetCharProps2(aCh).mPairedBracketType);
-}
-
-uint32_t GetPairedBracket(uint32_t aCh)
-{
-  return GetPairedBracketType(aCh) != PAIRED_BRACKET_TYPE_NONE
-         ? GetMirroredChar(aCh) : aCh;
-}
-
-static inline uint32_t
-GetCaseMapValue(uint32_t aCh)
-{
-    if (aCh < UNICODE_BMP_LIMIT) {
-        return sCaseMapValues[sCaseMapPages[0][aCh >> kCaseMapCharBits]]
-                             [aCh & ((1 << kCaseMapCharBits) - 1)];
-    }
-    if (aCh < (kCaseMapMaxPlane + 1) * 0x10000) {
-        return sCaseMapValues[sCaseMapPages[sCaseMapPlanes[(aCh >> 16) - 1]]
-                                           [(aCh & 0xffff) >> kCaseMapCharBits]]
-                             [aCh & ((1 << kCaseMapCharBits) - 1)];
-    }
-    return 0;
-}
-
-uint32_t
-GetUppercase(uint32_t aCh)
-{
-    uint32_t mapValue = GetCaseMapValue(aCh);
-    if (mapValue & (kLowerToUpper | kTitleToUpper)) {
-        return aCh ^ (mapValue & kCaseMapCharMask);
-    }
-    if (mapValue & kLowerToTitle) {
-        return GetUppercase(aCh ^ (mapValue & kCaseMapCharMask));
-    }
-    return aCh;
-}
-
-uint32_t
-GetLowercase(uint32_t aCh)
-{
-    uint32_t mapValue = GetCaseMapValue(aCh);
-    if (mapValue & kUpperToLower) {
-        return aCh ^ (mapValue & kCaseMapCharMask);
-    }
-    if (mapValue & kTitleToUpper) {
-        return GetLowercase(aCh ^ (mapValue & kCaseMapCharMask));
-    }
-    return aCh;
-}
-
-uint32_t
-GetTitlecaseForLower(uint32_t aCh)
-{
-    uint32_t mapValue = GetCaseMapValue(aCh);
-    if (mapValue & (kLowerToTitle | kLowerToUpper)) {
-        return aCh ^ (mapValue & kCaseMapCharMask);
-    }
-    return aCh;
-}
-
-uint32_t
-GetTitlecaseForAll(uint32_t aCh)
-{
-    uint32_t mapValue = GetCaseMapValue(aCh);
-    if (mapValue & (kLowerToTitle | kLowerToUpper)) {
-        return aCh ^ (mapValue & kCaseMapCharMask);
-    }
-    if (mapValue & kUpperToLower) {
-        return GetTitlecaseForLower(aCh ^ (mapValue & kCaseMapCharMask));
-    }
-    return aCh;
-}
-
-bool IsEastAsianWidthFWH(uint32_t aCh)
-{
-    return GetCharProps2(aCh).mEastAsianWidthFWH;
-}
-
-#endif
 
 #define DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(prefix_) \
   uint32_t Get##prefix_(uint32_t aCh) \
   { \
     if (aCh >= UNICODE_BMP_LIMIT) { \
       return aCh; \
     } \
     auto page = s##prefix_##Pages[aCh >> k##prefix_##CharBits]; \
@@ -327,41 +153,28 @@ IsClusterExtender(uint32_t aCh, uint8_t 
 {
     return ((aCategory >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK &&
              aCategory <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) ||
             (aCh >= 0x200c && aCh <= 0x200d) || // ZWJ, ZWNJ
             (aCh >= 0xff9e && aCh <= 0xff9f));  // katakana sound marks
 }
 
 enum HSType {
-#if ENABLE_INTL_API
     HST_NONE = U_HST_NOT_APPLICABLE,
     HST_L    = U_HST_LEADING_JAMO,
     HST_V    = U_HST_VOWEL_JAMO,
     HST_T    = U_HST_TRAILING_JAMO,
     HST_LV   = U_HST_LV_SYLLABLE,
     HST_LVT  = U_HST_LVT_SYLLABLE
-#else
-    HST_NONE = 0x00,
-    HST_L    = 0x01,
-    HST_V    = 0x02,
-    HST_T    = 0x04,
-    HST_LV   = 0x03,
-    HST_LVT  = 0x07
-#endif
 };
 
 static HSType
 GetHangulSyllableType(uint32_t aCh)
 {
-#if ENABLE_INTL_API
     return HSType(u_getIntPropertyValue(aCh, UCHAR_HANGUL_SYLLABLE_TYPE));
-#else
-    return HSType(GetCharProps1(aCh).mHangulType);
-#endif
 }
 
 void
 ClusterIterator::Next()
 {
     if (AtEnd()) {
         NS_WARNING("ClusterIterator has already reached the end");
         return;
--- a/intl/unicharutil/util/nsUnicodeProperties.h
+++ b/intl/unicharutil/util/nsUnicodeProperties.h
@@ -7,20 +7,18 @@
 #ifndef NS_UNICODEPROPERTIES_H
 #define NS_UNICODEPROPERTIES_H
 
 #include "nsBidiUtils.h"
 #include "nsUGenCategory.h"
 #include "nsUnicodeScriptCodes.h"
 #include "harfbuzz/hb.h"
 
-#if ENABLE_INTL_API
 #include "unicode/uchar.h"
 #include "unicode/uscript.h"
-#endif
 
 const nsCharProps2& GetCharProps2(uint32_t aCh);
 
 namespace mozilla {
 
 namespace unicode {
 
 extern const nsUGenCategory sDetailedToGeneralCategory[];
@@ -43,18 +41,16 @@ enum PairedBracketType {
 /* Flags for Unicode security IdentifierType.txt attributes. Only a subset
    of these are currently checked by Gecko, so we only define flags for the
    ones we need. */
 enum IdentifierType {
   IDTYPE_RESTRICTED = 0,
   IDTYPE_ALLOWED = 1,
 };
 
-#if ENABLE_INTL_API // ICU is available, so simply forward to its API
-
 extern const hb_unicode_general_category_t sICUtoHBcategory[];
 
 inline uint32_t
 GetMirroredChar(uint32_t aCh)
 {
   return u_charMirror(aCh);
 }
 
@@ -171,73 +167,16 @@ IsEastAsianWidthFWH(uint32_t aCh)
 }
 
 inline bool
 IsDefaultIgnorable(uint32_t aCh)
 {
   return u_hasBinaryProperty(aCh, UCHAR_DEFAULT_IGNORABLE_CODE_POINT);
 }
 
-#else // not ENABLE_INTL_API
-
-// Return whether the char has a mirrored-pair counterpart.
-uint32_t GetMirroredChar(uint32_t aCh);
-
-bool HasMirroredChar(uint32_t aChr);
-
-uint8_t GetCombiningClass(uint32_t aCh);
-
-// returns the detailed General Category in terms of HB_UNICODE_* values
-uint8_t GetGeneralCategory(uint32_t aCh);
-
-nsCharType GetBidiCat(uint32_t aCh);
-
-uint8_t GetLineBreakClass(uint32_t aCh);
-
-Script GetScriptCode(uint32_t aCh);
-
-// We don't support ScriptExtensions.txt data when building without ICU.
-// The most important cases will still be handled in gfxScriptItemizer
-// by checking IsClusterExtender to avoid breaking script runs within
-// a cluster.
-inline bool
-HasScript(uint32_t aCh, Script aScript)
-{
-  return false;
-}
-
-uint32_t GetScriptTagForCode(Script aScriptCode);
-
-PairedBracketType GetPairedBracketType(uint32_t aCh);
-uint32_t GetPairedBracket(uint32_t aCh);
-
-/**
- * Return the numeric value of the character. The value returned is the value
- * of the Numeric_Value in field 7 of the UCD, or -1 if field 7 is empty.
- * To restrict to decimal digits, the caller should also check whether
- * GetGeneralCategory returns HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER
- */
-int8_t GetNumericValue(uint32_t aCh);
-
-uint32_t GetUppercase(uint32_t aCh);
-uint32_t GetLowercase(uint32_t aCh);
-uint32_t GetTitlecaseForLower(uint32_t aCh); // maps LC to titlecase, UC unchanged
-uint32_t GetTitlecaseForAll(uint32_t aCh); // maps both UC and LC to titlecase
-
-// Return whether the char has EastAsianWidth class F or W or H.
-bool IsEastAsianWidthFWH(uint32_t aCh);
-
-// Return whether the char is default-ignorable.
-inline bool IsDefaultIgnorable(uint32_t aCh)
-{
-  return GetCharProps2(aCh).mDefaultIgnorable;
-}
-
-#endif // !ENABLE_INTL_API
-
 // returns the simplified Gen Category as defined in nsUGenCategory
 inline nsUGenCategory GetGenCategory(uint32_t aCh) {
   return sDetailedToGeneralCategory[GetGeneralCategory(aCh)];
 }
 
 inline VerticalOrientation GetVerticalOrientation(uint32_t aCh) {
   return VerticalOrientation(GetCharProps2(aCh).mVertOrient);
 }
--- a/intl/unicharutil/util/nsUnicodePropertyData.cpp
+++ b/intl/unicharutil/util/nsUnicodePropertyData.cpp
@@ -6,17 +6,17 @@
 
 /*
  * Derived from the Unicode Character Database by genUnicodePropertyData.pl
  *
  * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html
  */
 
 /*
- * Created on Wed Jun 28 17:08:23 2017 from UCD data files with version info:
+ * Created on Thu Sep 21 20:35:51 2017 from UCD data files with version info:
  *
 
 # Unicode Character Database
 # Date: 2017-06-18, 23:32:00 GMT [KW]
 # © 2017 Unicode®, Inc.
 # For terms of use, see http://www.unicode.org/terms_of_use.html
 #
 # For documentation, see the following:
@@ -24,37 +24,16 @@
 # UAX #38, "Unicode Han Database (Unihan)"
 # UAX #44, "Unicode Character Database."
 #
 # The UAXes can be accessed at http://www.unicode.org/versions/Unicode10.0.0/
 
 This directory contains the final data files
 for the Unicode Character Database, for Version 10.0.0 of the Unicode Standard.
 
-# Scripts-10.0.0.txt
-# Date: 2017-03-11, 06:40:37 GMT
-
-# BidiMirroring-10.0.0.txt
-# Date: 2017-04-12, 17:30:00 GMT [KW, LI]
-
-# BidiBrackets-10.0.0.txt
-# Date: 2017-04-12, 17:30:00 GMT [AG, LI, KW]
-
-# HangulSyllableType-10.0.0.txt
-# Date: 2017-02-14, 04:26:11 GMT
-
-# LineBreak-10.0.0.txt
-# Date: 2017-03-08, 02:00:00 GMT [KW, LI]
-
-# EastAsianWidth-10.0.0.txt
-# Date: 2017-03-08, 02:00:00 GMT [KW, LI]
-
-# DerivedCoreProperties-10.0.0.txt
-# Date: 2017-03-19, 00:05:15 GMT
-
 # IdentifierStatus.txt
 # Date: 2017-04-08, 16:13:41 GMT
 
 #
 # Unihan_Variants.txt
 # Date: 2017-05-14 07:01:48 GMT [JHJ]
 
 # VerticalOrientation-17.txt
@@ -62,407 +41,16 @@ for the Unicode Character Database, for 
 
  *
  * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
  */
 
 #include <stdint.h>
 #include "harfbuzz/hb.h"
 
-#if !ENABLE_INTL_API
-static const uint32_t sScriptCodeToTag[] = {
-  HB_TAG('Z','y','y','y'),
-  HB_TAG('Z','i','n','h'),
-  HB_TAG('A','r','a','b'),
-  HB_TAG('A','r','m','n'),
-  HB_TAG('B','e','n','g'),
-  HB_TAG('B','o','p','o'),
-  HB_TAG('C','h','e','r'),
-  HB_TAG('C','o','p','t'),
-  HB_TAG('C','y','r','l'),
-  HB_TAG('D','s','r','t'),
-  HB_TAG('D','e','v','a'),
-  HB_TAG('E','t','h','i'),
-  HB_TAG('G','e','o','r'),
-  HB_TAG('G','o','t','h'),
-  HB_TAG('G','r','e','k'),
-  HB_TAG('G','u','j','r'),
-  HB_TAG('G','u','r','u'),
-  HB_TAG('H','a','n','i'),
-  HB_TAG('H','a','n','g'),
-  HB_TAG('H','e','b','r'),
-  HB_TAG('H','i','r','a'),
-  HB_TAG('K','n','d','a'),
-  HB_TAG('K','a','n','a'),
-  HB_TAG('K','h','m','r'),
-  HB_TAG('L','a','o','o'),
-  HB_TAG('L','a','t','n'),
-  HB_TAG('M','l','y','m'),
-  HB_TAG('M','o','n','g'),
-  HB_TAG('M','y','m','r'),
-  HB_TAG('O','g','a','m'),
-  HB_TAG('I','t','a','l'),
-  HB_TAG('O','r','y','a'),
-  HB_TAG('R','u','n','r'),
-  HB_TAG('S','i','n','h'),
-  HB_TAG('S','y','r','c'),
-  HB_TAG('T','a','m','l'),
-  HB_TAG('T','e','l','u'),
-  HB_TAG('T','h','a','a'),
-  HB_TAG('T','h','a','i'),
-  HB_TAG('T','i','b','t'),
-  HB_TAG('C','a','n','s'),
-  HB_TAG('Y','i','i','i'),
-  HB_TAG('T','g','l','g'),
-  HB_TAG('H','a','n','o'),
-  HB_TAG('B','u','h','d'),
-  HB_TAG('T','a','g','b'),
-  HB_TAG('B','r','a','i'),
-  HB_TAG('C','p','r','t'),
-  HB_TAG('L','i','m','b'),
-  HB_TAG('L','i','n','b'),
-  HB_TAG('O','s','m','a'),
-  HB_TAG('S','h','a','w'),
-  HB_TAG('T','a','l','e'),
-  HB_TAG('U','g','a','r'),
-  HB_TAG('H','r','k','t'),
-  HB_TAG('B','u','g','i'),
-  HB_TAG('G','l','a','g'),
-  HB_TAG('K','h','a','r'),
-  HB_TAG('S','y','l','o'),
-  HB_TAG('T','a','l','u'),
-  HB_TAG('T','f','n','g'),
-  HB_TAG('X','p','e','o'),
-  HB_TAG('B','a','l','i'),
-  HB_TAG('B','a','t','k'),
-  HB_TAG('B','l','i','s'),
-  HB_TAG('B','r','a','h'),
-  HB_TAG('C','h','a','m'),
-  HB_TAG('C','i','r','t'),
-  HB_TAG('C','y','r','s'),
-  HB_TAG('E','g','y','d'),
-  HB_TAG('E','g','y','h'),
-  HB_TAG('E','g','y','p'),
-  HB_TAG('G','e','o','k'),
-  HB_TAG('H','a','n','s'),
-  HB_TAG('H','a','n','t'),
-  HB_TAG('H','m','n','g'),
-  HB_TAG('H','u','n','g'),
-  HB_TAG('I','n','d','s'),
-  HB_TAG('J','a','v','a'),
-  HB_TAG('K','a','l','i'),
-  HB_TAG('L','a','t','f'),
-  HB_TAG('L','a','t','g'),
-  HB_TAG('L','e','p','c'),
-  HB_TAG('L','i','n','a'),
-  HB_TAG('M','a','n','d'),
-  HB_TAG('M','a','y','a'),
-  HB_TAG('M','e','r','o'),
-  HB_TAG('N','k','o','o'),
-  HB_TAG('O','r','k','h'),
-  HB_TAG('P','e','r','m'),
-  HB_TAG('P','h','a','g'),
-  HB_TAG('P','h','n','x'),
-  HB_TAG('P','l','r','d'),
-  HB_TAG('R','o','r','o'),
-  HB_TAG('S','a','r','a'),
-  HB_TAG('S','y','r','e'),
-  HB_TAG('S','y','r','j'),
-  HB_TAG('S','y','r','n'),
-  HB_TAG('T','e','n','g'),
-  HB_TAG('V','a','i','i'),
-  HB_TAG('V','i','s','p'),
-  HB_TAG('X','s','u','x'),
-  HB_TAG('Z','x','x','x'),
-  HB_TAG('Z','z','z','z'),
-  HB_TAG('C','a','r','i'),
-  HB_TAG('J','p','a','n'),
-  HB_TAG('L','a','n','a'),
-  HB_TAG('L','y','c','i'),
-  HB_TAG('L','y','d','i'),
-  HB_TAG('O','l','c','k'),
-  HB_TAG('R','j','n','g'),
-  HB_TAG('S','a','u','r'),
-  HB_TAG('S','g','n','w'),
-  HB_TAG('S','u','n','d'),
-  HB_TAG('M','o','o','n'),
-  HB_TAG('M','t','e','i'),
-  HB_TAG('A','r','m','i'),
-  HB_TAG('A','v','s','t'),
-  HB_TAG('C','a','k','m'),
-  HB_TAG('K','o','r','e'),
-  HB_TAG('K','t','h','i'),
-  HB_TAG('M','a','n','i'),
-  HB_TAG('P','h','l','i'),
-  HB_TAG('P','h','l','p'),
-  HB_TAG('P','h','l','v'),
-  HB_TAG('P','r','t','i'),
-  HB_TAG('S','a','m','r'),
-  HB_TAG('T','a','v','t'),
-  HB_TAG('Z','m','t','h'),
-  HB_TAG('Z','s','y','m'),
-  HB_TAG('B','a','m','u'),
-  HB_TAG('L','i','s','u'),
-  HB_TAG('N','k','g','b'),
-  HB_TAG('S','a','r','b'),
-  HB_TAG('B','a','s','s'),
-  HB_TAG('D','u','p','l'),
-  HB_TAG('E','l','b','a'),
-  HB_TAG('G','r','a','n'),
-  HB_TAG('K','p','e','l'),
-  HB_TAG('L','o','m','a'),
-  HB_TAG('M','e','n','d'),
-  HB_TAG('M','e','r','c'),
-  HB_TAG('N','a','r','b'),
-  HB_TAG('N','b','a','t'),
-  HB_TAG('P','a','l','m'),
-  HB_TAG('S','i','n','d'),
-  HB_TAG('W','a','r','a'),
-  HB_TAG('A','f','a','k'),
-  HB_TAG('J','u','r','c'),
-  HB_TAG('M','r','o','o'),
-  HB_TAG('N','s','h','u'),
-  HB_TAG('S','h','r','d'),
-  HB_TAG('S','o','r','a'),
-  HB_TAG('T','a','k','r'),
-  HB_TAG('T','a','n','g'),
-  HB_TAG('W','o','l','e'),
-  HB_TAG('H','l','u','w'),
-  HB_TAG('K','h','o','j'),
-  HB_TAG('T','i','r','h'),
-  HB_TAG('A','g','h','b'),
-  HB_TAG('M','a','h','j'),
-  HB_TAG('A','h','o','m'),
-  HB_TAG('H','a','t','r'),
-  HB_TAG('M','o','d','i'),
-  HB_TAG('M','u','l','t'),
-  HB_TAG('P','a','u','c'),
-  HB_TAG('S','i','d','d'),
-  HB_TAG('A','d','l','m'),
-  HB_TAG('B','h','k','s'),
-  HB_TAG('M','a','r','c'),
-  HB_TAG('N','e','w','a'),
-  HB_TAG('O','s','g','e'),
-  HB_TAG('H','a','n','b'),
-  HB_TAG('J','a','m','o'),
-  HB_TAG('Z','s','y','e')
-};
-#endif
-
-#if !ENABLE_INTL_API
-static const int16_t sMirrorOffsets[] = {
-  0,
-  1,
-  -1,
-  2,
-  -2,
-  16,
-  -16,
-  3,
-  -3,
-  2016,
-  138,
-  1824,
-  2104,
-  2108,
-  2106,
-  -138,
-  8,
-  7,
-  -8,
-  -7,
-  -1824,
-  -2016,
-  -2104,
-  -2106,
-  -2108
-};
-#endif
-
-
-#if !ENABLE_INTL_API
-#define kCharProp1MaxPlane  1
-#define kCharProp1IndexBits 11
-#define kCharProp1CharBits  5
-static const uint8_t sCharProp1Planes[1] = {1};
-
-static const uint8_t sCharProp1Pages[2][2048] = {
-  {0,1,2,2,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,5,6,7,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,9,10,11,0,12,0,13,14,0,0,15,16,17,18,19,0,0,0,0,20,21,22,23,0,0,0,24,25,0,26,27,0,0,26,28,0,0,26,28,0,0,26,28,0,0,26,28,0,0,0,28,0,0,0,29,0,0,26,28,0,0,30,28,0,0,0,31,0,0,32,33,0,0,34,35,0,36,37,0,38,39,0,40,0,0,41,0,0,42,0,0,0,43,43,43,44,44,45,46,46,0,0,0,0,0,0,0,0,0,0,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,0,0,0,49,49,0,0,0,0,50,0,0,0,0,0,0,51,0,0,0,52,0,0,0,0,0,0,53,0,0,54,0,55,0,0,0,56,57,58,0,59,0,60,0,61,0,0,0,0,62,63,0,0,0,0,0,0,64,65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,67,68,69,0,70,71,0,0,0,0,0,0,0,0,72,73,74,75,76,77,78,79,80,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,82,0,0,83,84,0,0,0,0,0,0,0,0,0,0,0,0,85,86,87,88,0,89,0,90,91,92,93,94,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,0,0,0,96,0,0,0,97,98,99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,101,0,0,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,104,0,0,105,0,0,0,0,0,0,0,0,106,0,0,0,0,0,57,107,0,108,109,110,0,111,112,0,0,0,0,0,0,113,114,115,0,0,0,0,0,0,0,28,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,123,124,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,128,129,0,0,0,0,1,2,130,131,0,0,0,0},
-  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,133,0,0,0,134,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,136,0,0,0,0,0,137,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,96,0,138,0,0,139,140,0,111,0,0,141,0,0,142,0,0,0,0,0,143,0,26,28,144,0,0,0,0,0,0,145,0,0,0,146,0,0,0,0,0,0,96,147,0,0,96,0,0,0,148,0,0,0,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,150,0,151,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,152,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,0,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,157,158,0,0,0,0,159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,161,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,162,0,0,0,163,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
-};
-
-static const nsCharProps1 sCharProp1Values[164][32] = {
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {3,0,0}, {0,0,0}, {4,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {3,0,0}, {0,0,0}, {4,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {5,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {6,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,232}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,232}, {0,0,216}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220},},
-  {{0,0,220}, {0,0,202}, {0,0,202}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,202}, {0,0,202}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,240}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,232}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,233}, {0,0,234}, {0,0,234}, {0,0,233},},
-  {{0,0,234}, {0,0,234}, {0,0,233}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,222}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,222}, {0,0,228}, {0,0,230}, {0,0,10}, {0,0,11}, {0,0,12}, {0,0,13}, {0,0,14}, {0,0,15}, {0,0,16}, {0,0,17}, {0,0,18}, {0,0,19}, {0,0,19}, {0,0,20}, {0,0,21}, {0,0,22}, {0,0,0}, {0,0,23},},
-  {{0,0,0}, {0,0,24}, {0,0,25}, {0,0,0}, {0,0,230}, {0,0,220}, {0,0,0}, {0,0,18}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,30}, {0,0,31}, {0,0,32}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,27}, {0,0,28}, {0,0,29}, {0,0,30}, {0,0,31}, {0,0,32}, {0,0,33}, {0,0,34}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,35}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,230},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,36}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,220}, {0,0,230},},
-  {{0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,230}, {0,0,230}, {0,0,0}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,27}, {0,0,28}, {0,0,29}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,84}, {0,0,91}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,103}, {0,0,103}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,107}, {0,0,107}, {0,0,107}, {0,0,107}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,118}, {0,0,118}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,122}, {0,0,122}, {0,0,122}, {0,0,122}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,0}, {0,0,220}, {0,0,0}, {0,0,216}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,129}, {0,0,130}, {0,0,0}, {0,0,132}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,130}, {0,0,130}, {0,0,130}, {0,0,130}, {0,0,0}, {0,0,0},},
-  {{0,0,130}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,9}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,9}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0},},
-  {{0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0},},
-  {{0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0},},
-  {{0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,228}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,222}, {0,0,230}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,220},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,1}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220},},
-  {{0,0,230}, {0,0,0}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,234}, {0,0,214}, {0,0,220}, {0,0,202}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,232}, {0,0,228}, {0,0,228}, {0,0,220}, {0,0,0}, {0,0,230}, {0,0,233}, {0,0,220}, {0,0,230}, {0,0,220},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,1}, {0,0,1}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, {0,0,1}, {0,0,230}, {0,0,220}, {0,0,230}, {0,0,1}, {0,0,1}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {7,0,0}, {7,0,0}, {7,0,0}, {8,0,0}, {8,0,0}, {8,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {9,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {10,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0},},
-  {{1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {11,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {12,0,0}, {0,0,0}, {13,0,0}, {14,0,0}, {0,0,0}, {14,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {15,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0},},
-  {{1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {16,0,0}, {16,0,0}, {16,0,0}, {0,0,0}, {17,0,0}, {17,0,0}, {0,0,0}, {0,0,0}, {18,0,0}, {18,0,0}, {18,0,0}, {19,0,0}, {19,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {3,0,0}, {0,0,0}, {4,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {7,0,0}, {1,0,0}, {2,0,0}, {8,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {20,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {21,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0},},
-  {{2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0},},
-  {{2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {22,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {23,0,0}, {24,0,0}, {23,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0},},
-  {{1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,218}, {0,0,228}, {0,0,232}, {0,0,222}, {0,0,224}, {0,0,224}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,8}, {0,0,8}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,1,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230},},
-  {{0,0,0}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,3,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,3,0}, {0,7,0}, {0,7,0}, {0,7,0},},
-  {{0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,3,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0},},
-  {{0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,3,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0},},
-  {{0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,3,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0},},
-  {{0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,3,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0},},
-  {{0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,3,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0},},
-  {{0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,3,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,7,0},},
-  {{0,7,0}, {0,7,0}, {0,7,0}, {0,7,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0},},
-  {{0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,2,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0},},
-  {{0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,4,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,26}, {0,0,0},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {1,0,0}, {2,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {3,0,0}, {0,0,0}, {4,0,0}, {0,0,0}, {1,0,0},},
-  {{2,0,0}, {0,0,0}, {1,0,0}, {2,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,0}, {0,0,0},},
-  {{0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,0}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,1}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,9}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,7}, {0,0,0}, {0,0,9}, {0,0,9}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,1}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,216}, {0,0,216}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,226}, {0,0,216}, {0,0,216}, {0,0,216}, {0,0,216}, {0,0,216}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220},},
-  {{0,0,220}, {0,0,220}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,220}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230},},
-  {{0,0,230}, {0,0,230}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,220}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},},
-  {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,230}, {0,0,7}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},}
-};
-#endif
-
-#if ENABLE_INTL_API
 #define kCharProp2MaxPlane  16
 #define kCharProp2IndexBits 9
 #define kCharProp2CharBits  7
 static const uint8_t sCharProp2Planes[16] = {1,2,3,4,4,4,4,4,4,4,4,4,4,4,3,3};
 
 static const uint8_t sCharProp2Pages[5][512] = {
   {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,34,35,36,37,38,39,34,34,34,34,16,16,40,16,41,16,16,16,16,16,16,16,42,16,16,43,44,45,46,47,48,49,50,51,16,52,53,54,34,16,55,56,34,57,58,16,16,16,16,16,16,59,60,16,16,61,62,16,34,34,34,63,64,65,66,34,34,67,34,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,69,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,70,34,34,34,34,34,34,34,34,34,71,16,16,72,73,74,75,16,16,76,77,78,16,79,16,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,81,34,16,16,16,16,16,16,82,16,83,84},
   {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,85,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,34,34,34,86,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,76,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,87,68,88,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,16,16,34,16,16,16,16,16,16,16,16,16,34,34,34,34,34,86,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,89,34,34,34,34,34,34,34,34,34,34,34,16,16,34,34,16,16,16,16,16,16,16,16,16,16,16,16},
@@ -564,1123 +152,16 @@ static const nsCharProps2 sCharProp2Valu
   {{2,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
   {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
   {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
   {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
   {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}},
   {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}},
   {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0}}
 };
-#endif
-
-#if !ENABLE_INTL_API
-#define kCharProp2MaxPlane  16
-#define kCharProp2IndexBits 12
-#define kCharProp2CharBits  4
-static const uint8_t sCharProp2Planes[16] = {1,2,3,4,4,4,4,4,4,4,4,4,4,5,6,6};
-
-static const uint16_t sCharProp2Pages[7][4096] = {
-  {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,16,17,18,16,16,19,20,21,22,23,24,25,26,27,16,28,29,30,31,32,33,33,33,34,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,56,56,57,57,57,58,58,59,60,60,60,61,60,60,60,60,60,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,78,79,80,81,82,83,78,78,78,78,84,85,86,87,88,89,90,91,78,78,78,92,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,106,106,107,108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,202,203,197,197,204,205,206,207,208,209,210,211,212,213,214,215,216,217,197,197,218,218,219,220,221,222,223,224,225,226,227,227,228,229,229,230,231,231,231,231,231,232,233,234,234,234,235,236,236,236,236,236,237,237,237,237,238,239,237,237,238,237,237,240,241,242,237,237,237,241,237,237,237,243,244,245,237,246,247,247,247,247,247,248,249,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,251,250,252,253,254,254,254,254,255,256,257,258,259,260,261,262,263,264,265,265,266,267,268,269,270,271,272,273,274,274,275,274,274,276,277,274,278,250,250,250,250,279,280,281,282,283,284,285,286,287,288,288,289,288,290,291,292,292,293,294,295,295,295,296,297,298,299,299,300,301,197,197,197,197,302,303,303,304,305,306,307,308,309,310,311,312,313,313,314,315,316,316,317,318,319,320,321,322,323,197,197,197,324,325,326,327,33,33,328,329,329,330,331,332,33,333,329,334,335,335,335,336,16,16,16,16,16,16,16,16,16,337,16,16,16,16,16,338,339,340,339,339,340,341,339,342,343,343,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,376,379,380,381,382,383,384,385,386,387,388,389,390,391,387,387,392,387,393,394,395,396,397,397,397,398,399,400,387,401,402,403,404,405,399,399,406,407,408,407,409,410,411,412,413,413,413,413,414,415,416,416,416,416,417,416,416,418,416,419,420,421,422,423,424,425,426,427,399,428,429,430,431,432,399,433,434,435,436,437,438,439,440,399,441,399,442,443,444,445,446,447,376,448,449,387,450,387,451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,387,387,387,387,387,387,387,387,452,453,387,387,387,454,387,455,387,387,387,387,387,387,387,387,387,387,387,387,387,387,387,387,376,456,399,387,457,458,376,459,376,460,376,461,462,463,464,407,465,465,466,467,467,468,469,470,471,471,471,471,471,471,472,473,474,474,475,476,476,476,477,478,237,479,480,480,480,480,481,481,482,483,484,485,486,197,197,197,487,488,487,487,487,487,487,489,487,487,487,487,487,487,487,487,487,487,487,487,487,490,407,491,492,493,494,495,496,497,498,497,499,500,501,502,503,502,504,505,506,507,508,509,510,510,511,510,512,513,507,514,515,515,516,517,518,519,520,521,522,523,518,524,520,521,521,525,526,527,527,528,529,529,529,529,529,530,521,531,521,521,521,521,521,532,521,533,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,535,399,399,399,399,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,536,537,538,539,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,540,541,541,541,542,543,543,544,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,546,545,547,197,58,58,548,549,58,550,551,551,551,551,552,553,39,554,555,556,557,557,557,558,559,560,561,562,197,197,197,563,564,565,566,567,568,568,568,569,570,571,571,572,573,574,575,576,577,578,579,580,581,582,231,583,584,585,585,586,587,588,589,590,591,591,592,593,594,595,218,596,597,597,597,598,599,600,601,602,603,604,480,33,33,605,606,607,607,607,607,607,608,608,609,610,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,615,613,611,612,613,614,613,616,234,617,236,236,618,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,