Merge pull request #8737 from fippo/kind-not-type

webrtc: use 'kind' instead of 'type'
diff --git a/beacon/OWNERS b/beacon/OWNERS
new file mode 100644
index 0000000..719eb69
--- /dev/null
+++ b/beacon/OWNERS
@@ -0,0 +1,2 @@
+@toddreifsteck
+@igrigorik
diff --git a/css/css-color/color-resolving-hsl.html b/css/css-color/color-resolving-hsl.html
new file mode 100644
index 0000000..d337017
--- /dev/null
+++ b/css/css-color/color-resolving-hsl.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: Resolving HSL color values</title>
+<link rel="author" title="Chris Nardi" href="mailto:csnardi1@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#resolving-color-values">
+<meta name="assert" content="Tests if HSL color values are resolved properly">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="parent" style="color: rgb(45, 23, 27)">
+    <div id="inner"></div>
+</div>
+
+<script>
+    function color_test(color, expected, reason) {
+        test(function() {
+            var element = document.getElementById('inner');
+            // Random value not in our test data.
+            fail_value = "rgb(12, 34, 223)"
+            element.style.color = "black";
+            element.style.cssText = "color: " + fail_value + "; color: " + color;
+
+            if (expected === null)
+                assert_equals(getComputedStyle(element).color, fail_value);
+            else
+                assert_equals(getComputedStyle(element).color, expected);
+        }, `${reason}: ${color}`);
+    }
+
+    function expected_value(rgb_channels) {
+        if (rgb_channels === null)
+            return null;
+        else if (rgb_channels.length === 3 || rgb_channels[3] == 1 || rgb_channels[3] === undefined)
+            return "rgb(" + rgb_channels.slice(0, 3).join(", ") + ")";
+        else
+            return "rgba(" + rgb_channels.join(", ") + ")";
+    }
+
+    // Taken mostly from https://drafts.csswg.org/css-color/#hsl-to-rgb
+    function hslToRgb(hue, sat, light) {
+      if (light <= .5) {
+        var t2 = light * (sat + 1);
+      } else {
+        var t2 = light + sat - (light * sat);
+      }
+      var t1 = light * 2 - t2;
+      var r = Math.min(Math.max(Math.round(hueToRgb(t1, t2, hue + 2) * 255), 0), 255);
+      var g = Math.min(Math.max(Math.round(hueToRgb(t1, t2, hue) * 255), 0), 255);
+      var b = Math.min(Math.max(Math.round(hueToRgb(t1, t2, hue - 2) * 255), 0), 255);
+      return [r,g,b];
+    }
+
+    function hueToRgb(t1, t2, hue) {
+      if (hue < 0) hue += 6;
+      if (hue >= 6) hue -= 6;
+
+      if (hue < 1) return (t2 - t1) * hue + t1;
+      else if (hue < 3) return t2;
+      else if (hue < 4) return (t2 - t1) * (4 - hue) + t1;
+      else return t1;
+    }
+
+    // Test HSL parsing
+    for (var hue of [0, 30, 60, 90, 120, 180, 210, 240, 270, 300, 330, 360]) {
+        for (var sat of [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1]) {
+            for (var light of [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1]) {
+                rgb_channels = hslToRgb(hue / 60, sat, light);
+                for (var alpha of [undefined, 0, 0.2, 1]) {
+                    hsl_color = "hsl(" + hue + ", " + sat * 100 + "%, " + light * 100 + "%)";
+                    rgb_channels[3] = alpha;
+                    if (alpha !== undefined) {
+                        hsl_color = "hsla(" + hue + ", " + sat * 100 + "%, " + light * 100 + "%, " + alpha + ")";
+                    }
+                    color_test(hsl_color, expected_value(rgb_channels), "HSL/HSLA value should parse and round correctly");
+                }
+            }
+        }
+    }
+</script>
diff --git a/css/css-color/color-resolving-keywords.html b/css/css-color/color-resolving-keywords.html
new file mode 100644
index 0000000..5cbdcbe
--- /dev/null
+++ b/css/css-color/color-resolving-keywords.html
@@ -0,0 +1,205 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: Resolving keyword color values</title>
+<link rel="author" title="Chris Nardi" href="mailto:csnardi1@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#resolving-color-values">
+<meta name="assert" content="Tests if keyword color values are resolved properly">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="parent" style="color: rgb(45, 23, 27)">
+    <div id="inner"></div>
+</div>
+
+<script>
+    function color_test(color, expected, reason) {
+        test(function() {
+            var element = document.getElementById('inner');
+            // Random value not in our test data.
+            fail_value = "rgb(12, 34, 223)"
+            element.style.color = "black";
+            element.style.cssText = "color: " + fail_value + "; color: " + color;
+
+            if (expected === null)
+                assert_equals(getComputedStyle(element).color, fail_value);
+            else
+                assert_equals(getComputedStyle(element).color, expected);
+        }, `${reason}: ${color}`);
+    }
+
+    function expected_value(rgb_channels) {
+        if (rgb_channels === null)
+            return null;
+        else if (rgb_channels.length === 3 || rgb_channels[3] == 1)
+            return "rgb(" + rgb_channels.slice(0, 3).join(", ") + ")";
+        else
+            return "rgba(" + rgb_channels.join(", ") + ")";
+    }
+
+    keywords = [
+        ['transparent', [0, 0, 0, 0]],
+        ['aliceblue', [240, 248, 255, 1]],
+        ['antiquewhite', [250, 235, 215, 1]],
+        ['aqua', [0, 255, 255, 1]],
+        ['aquamarine', [127, 255, 212, 1]],
+        ['azure', [240, 255, 255, 1]],
+        ['beige', [245, 245, 220, 1]],
+        ['bisque', [255, 228, 196, 1]],
+        ['black', [0, 0, 0, 1]],
+        ['blanchedalmond', [255, 235, 205, 1]],
+        ['blue', [0, 0, 255, 1]],
+        ['blueviolet', [138, 43, 226, 1]],
+        ['brown', [165, 42, 42, 1]],
+        ['burlywood', [222, 184, 135, 1]],
+        ['cadetblue', [95, 158, 160, 1]],
+        ['chartreuse', [127, 255, 0, 1]],
+        ['chocolate', [210, 105, 30, 1]],
+        ['coral', [255, 127, 80, 1]],
+        ['cornflowerblue', [100, 149, 237, 1]],
+        ['cornsilk', [255, 248, 220, 1]],
+        ['crimson', [220, 20, 60, 1]],
+        ['cyan', [0, 255, 255, 1]],
+        ['darkblue', [0, 0, 139, 1]],
+        ['darkcyan', [0, 139, 139, 1]],
+        ['darkgoldenrod', [184, 134, 11, 1]],
+        ['darkgray', [169, 169, 169, 1]],
+        ['darkgreen', [0, 100, 0, 1]],
+        ['darkgrey', [169, 169, 169, 1]],
+        ['darkkhaki', [189, 183, 107, 1]],
+        ['darkmagenta', [139, 0, 139, 1]],
+        ['darkolivegreen', [85, 107, 47, 1]],
+        ['darkorange', [255, 140, 0, 1]],
+        ['darkorchid', [153, 50, 204, 1]],
+        ['darkred', [139, 0, 0, 1]],
+        ['darksalmon', [233, 150, 122, 1]],
+        ['darkseagreen', [143, 188, 143, 1]],
+        ['darkslateblue', [72, 61, 139, 1]],
+        ['darkslategray', [47, 79, 79, 1]],
+        ['darkslategrey', [47, 79, 79, 1]],
+        ['darkturquoise', [0, 206, 209, 1]],
+        ['darkviolet', [148, 0, 211, 1]],
+        ['deeppink', [255, 20, 147, 1]],
+        ['deepskyblue', [0, 191, 255, 1]],
+        ['dimgray', [105, 105, 105, 1]],
+        ['dimgrey', [105, 105, 105, 1]],
+        ['dodgerblue', [30, 144, 255, 1]],
+        ['firebrick', [178, 34, 34, 1]],
+        ['floralwhite', [255, 250, 240, 1]],
+        ['forestgreen', [34, 139, 34, 1]],
+        ['fuchsia', [255, 0, 255, 1]],
+        ['gainsboro', [220, 220, 220, 1]],
+        ['ghostwhite', [248, 248, 255, 1]],
+        ['gold', [255, 215, 0, 1]],
+        ['goldenrod', [218, 165, 32, 1]],
+        ['gray', [128, 128, 128, 1]],
+        ['green', [0, 128, 0, 1]],
+        ['greenyellow', [173, 255, 47, 1]],
+        ['grey', [128, 128, 128, 1]],
+        ['honeydew', [240, 255, 240, 1]],
+        ['hotpink', [255, 105, 180, 1]],
+        ['indianred', [205, 92, 92, 1]],
+        ['indigo', [75, 0, 130, 1]],
+        ['ivory', [255, 255, 240, 1]],
+        ['khaki', [240, 230, 140, 1]],
+        ['lavender', [230, 230, 250, 1]],
+        ['lavenderblush', [255, 240, 245, 1]],
+        ['lawngreen', [124, 252, 0, 1]],
+        ['lemonchiffon', [255, 250, 205, 1]],
+        ['lightblue', [173, 216, 230, 1]],
+        ['lightcoral', [240, 128, 128, 1]],
+        ['lightcyan', [224, 255, 255, 1]],
+        ['lightgoldenrodyellow', [250, 250, 210, 1]],
+        ['lightgray', [211, 211, 211, 1]],
+        ['lightgreen', [144, 238, 144, 1]],
+        ['lightgrey', [211, 211, 211, 1]],
+        ['lightpink', [255, 182, 193, 1]],
+        ['lightsalmon', [255, 160, 122, 1]],
+        ['lightseagreen', [32, 178, 170, 1]],
+        ['lightskyblue', [135, 206, 250, 1]],
+        ['lightslategray', [119, 136, 153, 1]],
+        ['lightslategrey', [119, 136, 153, 1]],
+        ['lightsteelblue', [176, 196, 222, 1]],
+        ['lightyellow', [255, 255, 224, 1]],
+        ['lime', [0, 255, 0, 1]],
+        ['limegreen', [50, 205, 50, 1]],
+        ['linen', [250, 240, 230, 1]],
+        ['magenta', [255, 0, 255, 1]],
+        ['maroon', [128, 0, 0, 1]],
+        ['mediumaquamarine', [102, 205, 170, 1]],
+        ['mediumblue', [0, 0, 205, 1]],
+        ['mediumorchid', [186, 85, 211, 1]],
+        ['mediumpurple', [147, 112, 219, 1]],
+        ['mediumseagreen', [60, 179, 113, 1]],
+        ['mediumslateblue', [123, 104, 238, 1]],
+        ['mediumspringgreen', [0, 250, 154, 1]],
+        ['mediumturquoise', [72, 209, 204, 1]],
+        ['mediumvioletred', [199, 21, 133, 1]],
+        ['midnightblue', [25, 25, 112, 1]],
+        ['mintcream', [245, 255, 250, 1]],
+        ['mistyrose', [255, 228, 225, 1]],
+        ['moccasin', [255, 228, 181, 1]],
+        ['navajowhite', [255, 222, 173, 1]],
+        ['navy', [0, 0, 128, 1]],
+        ['oldlace', [253, 245, 230, 1]],
+        ['olive', [128, 128, 0, 1]],
+        ['olivedrab', [107, 142, 35, 1]],
+        ['orange', [255, 165, 0, 1]],
+        ['orangered', [255, 69, 0, 1]],
+        ['orchid', [218, 112, 214, 1]],
+        ['palegoldenrod', [238, 232, 170, 1]],
+        ['palegreen', [152, 251, 152, 1]],
+        ['paleturquoise', [175, 238, 238, 1]],
+        ['palevioletred', [219, 112, 147, 1]],
+        ['papayawhip', [255, 239, 213, 1]],
+        ['peachpuff', [255, 218, 185, 1]],
+        ['peru', [205, 133, 63, 1]],
+        ['pink', [255, 192, 203, 1]],
+        ['plum', [221, 160, 221, 1]],
+        ['powderblue', [176, 224, 230, 1]],
+        ['purple', [128, 0, 128, 1]],
+        ['red', [255, 0, 0, 1]],
+        ['rosybrown', [188, 143, 143, 1]],
+        ['royalblue', [65, 105, 225, 1]],
+        ['saddlebrown', [139, 69, 19, 1]],
+        ['salmon', [250, 128, 114, 1]],
+        ['sandybrown', [244, 164, 96, 1]],
+        ['seagreen', [46, 139, 87, 1]],
+        ['seashell', [255, 245, 238, 1]],
+        ['sienna', [160, 82, 45, 1]],
+        ['silver', [192, 192, 192, 1]],
+        ['skyblue', [135, 206, 235, 1]],
+        ['slateblue', [106, 90, 205, 1]],
+        ['slategray', [112, 128, 144, 1]],
+        ['slategrey', [112, 128, 144, 1]],
+        ['snow', [255, 250, 250, 1]],
+        ['springgreen', [0, 255, 127, 1]],
+        ['steelblue', [70, 130, 180, 1]],
+        ['tan', [210, 180, 140, 1]],
+        ['teal', [0, 128, 128, 1]],
+        ['thistle', [216, 191, 216, 1]],
+        ['tomato', [255, 99, 71, 1]],
+        ['turquoise', [64, 224, 208, 1]],
+        ['violet', [238, 130, 238, 1]],
+        ['wheat', [245, 222, 179, 1]],
+        ['white', [255, 255, 255, 1]],
+        ['whitesmoke', [245, 245, 245, 1]],
+        ['yellow', [255, 255, 0, 1]],
+        ['yellowgreen', [154, 205, 50, 1]],
+    ]
+
+    for (var value in keywords) {
+        items_to_test = keywords[value];
+        keyword = items_to_test[0];
+        expected = expected_value(items_to_test[1]);
+        letter = value % keyword.length;
+        replacement = keyword;
+
+        color_test(keyword, expected, "Keyword should parse properly");
+        color_test(keyword.toUpperCase(), expected, "Keywords should be case-insensitive");
+        replacement[letter] = "\\" + keyword.codePointAt(letter);
+        color_test(replacement, expected, "Code point should parse");
+        color_test(keyword.slice(0, letter) + keyword.slice(letter + 1, keyword.length), null, "Partial keywords shouldn't parse");
+        if (keyword.indexOf('k') !== -1)
+            color_test(keyword.replace('k', 'K'), null, "Unicode modification shouldn't parse");
+    }
+</script>
diff --git a/css/css-color/color-resolving.html b/css/css-color/color-resolving.html
new file mode 100644
index 0000000..b3d1c74
--- /dev/null
+++ b/css/css-color/color-resolving.html
@@ -0,0 +1,180 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Color 4: Resolving color values</title>
+<link rel="author" title="Chris Nardi" href="mailto:csnardi1@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#resolving-color-values">
+<meta name="assert" content="Tests if color values are resolved properly">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="parent" style="color: rgb(45, 23, 27)">
+    <div id="inner"></div>
+</div>
+
+<script>
+    function color_test(color, expected, reason) {
+        test(function() {
+            var element = document.getElementById('inner');
+            // Random value not in our test data.
+            fail_value = "rgb(12, 34, 223)"
+            element.style.color = "black";
+            element.style.cssText = "color: " + fail_value + "; color: " + color;
+
+            if (expected === null)
+                assert_equals(getComputedStyle(element).color, fail_value);
+            else
+                assert_equals(getComputedStyle(element).color, expected);
+        }, `${reason}: ${color}`);
+    }
+
+    function expected_value(rgb_channels) {
+        if (rgb_channels === null)
+            return null;
+        else if (rgb_channels.length === 3 || rgb_channels[3] == 1)
+            return "rgb(" + rgb_channels.slice(0, 3).join(", ") + ")";
+        else
+            return "rgba(" + rgb_channels.join(", ") + ")";
+    }
+
+    tests = [
+        // Keyword tests
+        ["", null, "Should not parse invalid keyword"],
+        [" /* hey */\n", null, "Should not parse invalid keyword"],
+        ["4", null, "Should not parse invalid keyword"],
+        ["top", null, "Should not parse invalid keyword"],
+        ["/**/transparent", [0, 0, 0, 0], "Should parse to completely transparent"],
+        ["transparent", [0, 0, 0, 0], "Should parse to completely transparent"],
+        [" transparent\n", [0, 0, 0, 0], "Should parse to completely transparent"],
+        ["TransParent", [0, 0, 0, 0], "Should parse to completely transparent"],
+        ["currentColor", [45, 23, 27], "Should be same as parent color"],
+        ["CURRENTcolor", [45, 23, 27], "Should be same as parent color"],
+        ["current-Color", null, "Should not parse invalid keyword"],
+        ["black", [0, 0, 0, 1], "Should parse as correct value"],
+        ["white", [255, 255, 255, 1], "Should parse as correct value"],
+        ["fuchsia", [255, 0, 255, 1], "Should parse as correct value"],
+        ["cyan", [0, 255, 255, 1], "Should parse as correct value"],
+        ["CyAn", [0, 255, 255, 1], "Should parse as cyan"],
+
+        // Hex tests
+        ["#", null, "Should not parse invalid hex"],
+        ["#f", null, "Should not parse invalid hex"],
+        ["#ff", null, "Should not parse invalid hex"],
+        ["#fff", [255, 255, 255, 1], "Valid 3-digit hex"],
+        ["#ffg", null, "Should not parse invalid hex"],
+        ["#ffff", [255, 255, 255, 1], "Valid 4-digit hex"],
+        ["#fffg", null, "Should not parse invalid hex"],
+        ["#fffff", null, "Should not parse invalid hex"],
+        ["#ffffff", [255, 255, 255, 1], "Valid 6-digit hex"],
+        ["#fffffg", null, "Should not parse invalid hex"],
+        ["#fffffff", null, "Should not parse invalid hex"],
+        ["#ffffffff", [255, 255, 255, 1], "Valid 8-digit hex"],
+        ["#fffffffg", null, "Should not parse invalid hex"],
+        ["#fffffffff", null, "Should not parse invalid hex"],
+        ["#FFCc99", [255, 204, 153, 1], "Valid 6-digit hex"],
+        ["#369", [51, 102, 153, 1], "Valid 3-digit hex"],
+
+        // RGB tests
+        ["rgb(00, 51, 102)", [0, 51, 102, 1], "Valid numbers should be parsed"],
+        ["r\\gb(00, 51, 102)", [0, 51, 102, 1], "Correct escape sequences should still parse"],
+        ["r\\67 b(00, 51, 102)", [0, 51, 102, 1], "Correct escape sequences should still parse"],
+        ["RGB(153, 204, 255)", [153, 204, 255, 1], "Capitalization should not affect parsing"],
+        ["rgB(0, 0, 0)", [0, 0, 0, 1], "Capitalization should not affect parsing"],
+        ["rgB(0, 51, 255)", [0, 51, 255, 1], "Capitalization should not affect parsing"],
+        ["rgb(0,51,255)", [0, 51, 255, 1], "Lack of whitespace should not affect parsing"],
+        ["rgb(0\t,  51 ,255)", [0, 51, 255, 1], "Whitespace should not affect parsing"],
+        ["rgb(/* R */0, /* G */51, /* B */255)", [0, 51, 255, 1], "Comments should be allowed within function"],
+        ["rgb(-51, 306, 0)", [0, 255, 0, 1], "Invalid values should be clamped to 0 and 255 respectively"],
+        ["rgb(42%, 3%, 50%)", [107, 8, 128, 1], "Valid percentages should be parsed"],
+        ["RGB(100%, 100%, 100%)", [255, 255, 255, 1], "Capitalization should not affect parsing"],
+        ["rgB(0%, 0%, 0%)", [0, 0, 0, 1], "Capitalization should not affect parsing"],
+        ["rgB(10%, 20%, 30%)", [26, 51, 77, 1], "Capitalization should not affect parsing"],
+        ["rgb(10%,20%,30%)", [26, 51, 77, 1], "Whitespace should not affect parsing"],
+        ["rgb(10%\t,  20% ,30%)", [26, 51, 77, 1], "Whitespace should not affect parsing"],
+        ["rgb(/* R */ 10%, /* G */ 20%, /* B */ 30%)", [26, 51, 77, 1], "Comments should not affect parsing"],
+        ["rgb(-12%, 110%, 1400%)", [0, 255, 255, 1], "Invalid values should be clamped to 0 and 255 respectively"],
+        ["rgb(10%, 50%, 0)", null, "Values must be all numbers or all percentages"],
+        ["rgb(255, 50%, 0%)", null, "Values must be all numbers or all percentages"],
+        ["rgb(0, 0 0)", null, "Comma optional syntax requires no commas at all"],
+        ["rgb(0, 0, 0deg)", null, "Angles are not accepted in the rgb function"],
+        ["rgb(0, 0, light)", null, "Keywords are not accepted in the rgb function"],
+        ["rgb()", null, "The rgb function requires 3 or 4 arguments"],
+        ["rgb(0)", null, "The rgb function requires 3 or 4 arguments"],
+        ["rgb(0, 0)", null, "The rgb function requires 3 or 4 arguments"],
+        ["rgb(0%)", null, "The rgb function requires 3 or 4 arguments"],
+        ["rgb(0%, 0%)", null, "The rgb function requires 3 or 4 arguments"],
+        ["rgb(0, 0, 0, 0)", [0, 0, 0, 0], "RGB and RGBA are synonyms"],
+        ["rgb(0%, 0%, 0%, 0%)", [0, 0, 0, 0], "RGB and RGBA are synonyms"],
+        ["rgb(0%, 0%, 0%, 0)", [0, 0, 0, 0], "RGB and RGBA are synonyms"],
+        ["rgba(0, 0, 0, 0)", [0, 0, 0, 0], "Valid numbers should be parsed"],
+        ["rgba(204, 0, 102, 0.3)", [204, 0, 102, 0.3], "Valid numbers should be parsed"],
+        ["RGBA(255, 255, 255, 0)", [255, 255, 255, 0], "Capitalization should not affect parsing"],
+        ["rgBA(0, 51, 255, 1)", [0, 51, 255, 1], "Capitalization should not affect parsing"],
+        ["rgba(0, 51, 255, 1.1)", [0, 51, 255, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["rgba(0, 51, 255, 37)", [0, 51, 255, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["rgba(0, 51, 255, 0.42)", [0, 51, 255, 0.42], "Valid numbers should be parsed"],
+        ["rgba(0, 51, 255, 0)", [0, 51, 255, 0], "Valid numbers should be parsed"],
+        ["rgba(0, 51, 255, -0.1)", [0, 51, 255, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["rgba(0, 51, 255, -139)", [0, 51, 255, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["RGBA(100%, 100%, 100%, 0)", [255, 255, 255, 0], "Capitalization should not affect parsing"],
+        ["rgba(42%, 3%, 50%, 0.3)", [107, 8, 128, 0.3], "Valid percentages should be parsed"],
+        ["rgBA(0%, 20%, 100%, 1)", [0, 51, 255, 1], "Capitalization should not affect parsing"],
+        ["rgba(0%, 20%, 100%, 1.1)", [0, 51, 255, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["rgba(0%, 20%, 100%, 37)", [0, 51, 255, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["rgba(0%, 20%, 100%, 0.42)", [0, 51, 255, 0.42], "Valid percentages should be parsed"],
+        ["rgba(0%, 20%, 100%, 0)", [0, 51, 255, 0], "Valid percentages should be parsed"],
+        ["rgba(0%, 20%, 100%, -0.1)", [0, 51, 255, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["rgba(0%, 20%, 100%, -139)", [0, 51, 255, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["rgba(255, 255, 255, 0%)", [255, 255, 255, 0], "Percent alpha values are accepted in rgb/rgba"],
+        ["rgba(0%, 0%, 0%, 0%)", [0, 0, 0, 0], "Percent alpha values are accepted in rgb/rgba"],
+        ["rgba(0%, 0%, 0%)", [0, 0, 0, 1], "RGB and RGBA are synonyms"],
+        ["rgba(0, 0, 0)", [0, 0, 0, 1], "RGB and RGBA are synonyms"],
+        ["rgba(10%, 50%, 0, 1)", null, "Values must be all numbers or all percentages"],
+        ["rgba(255, 50%, 0%, 1)", null, "Values must be all numbers or all percentages"],
+        ["rgba(0, 0, 0 0)", null, "Comma optional syntax requires no commas at all"],
+        ["rgba(0, 0, 0, 0deg)", null, "Angles are not accepted in the rgb function"],
+        ["rgba(0, 0, 0, light)", null, "Keywords are not accepted in the rgb function"],
+        ["rgba()", null, "The rgba function requires 3 or 4 arguments"],
+        ["rgba(0)", null, "The rgba function requires 3 or 4 arguments"],
+        ["rgba(0, 0, 0, 0, 0)", null, "The rgba function requires 3 or 4 arguments"],
+        ["rgba(0%)", null, "The rgba function requires 3 or 4 arguments"],
+        ["rgba(0%, 0%)", null, "The rgba function requires 3 or 4 arguments"],
+        ["rgba(0%, 0%, 0%, 0%, 0%)", null, "The rgba function requires 3 or 4 arguments"],
+
+        // HSL tests
+        ["HSL(0, 0%, 0%)", [0, 0, 0, 1], "Capitalization should not affect parsing"],
+        ["hsL(0, 100%, 50%)", [255, 0, 0, 1], "Capitalization should not affect parsing"],
+        ["hsl(60, 100%, 37.5%)", [191, 191, 0, 1], "Valid numbers should be parsed"],
+        ["hsl(780, 100%, 37.5%)", [191, 191, 0, 1], "Angles are represented as a part of a circle and wrap around"],
+        ["hsl(-300, 100%, 37.5%)", [191, 191, 0, 1], "Angles are represented as a part of a circle and wrap around"],
+        ["hsl(300, 50%, 50%)", [191, 64, 191, 1], "Valid numbers should be parsed"],
+        ["hsl(30deg, 100%, 100%)", [255, 255, 255, 1], "Angles are accepted in HSL/HSLA"],
+        ["hsl(0, 0%, 0%, 0%)", [0, 0, 0, 0], "HSL and HSLA are synonyms"],
+        ["hsl(10, 50%, 0)", null, "The second and third parameters of hsl/hsla must be a percent"],
+        ["hsl(50%, 50%, 0%)", null, "The first parameter of hsl/hsla must be a number or angle"],
+        ["hsl(0, 0% 0%)", null, "Comma optional syntax requires no commas at all"],
+        ["hsl(0, 0%, light)", null, "Keywords are not accepted in the hsl function"],
+        ["hsl()", null, "The hsl function requires 3 or 4 arguments"],
+        ["hsl(0)", null, "The hsl function requires 3 or 4 arguments"],
+        ["hsl(0, 0%)", null, "The hsl function requires 3 or 4 arguments"],
+        ["HSLA(-300, 100%, 37.5%, 1)", [191, 191, 0, 1], "Angles are represented as a part of a circle and wrap around"],
+        ["hsLA(-300, 100%, 37.5%, 12)", [191, 191, 0, 1], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["hsla(-300, 100%, 37.5%, 0.2)", [191, 191, 0, 0.2], "Angles are represented as a part of a circle and wrap around"],
+        ["hsla(-300, 100%, 37.5%, 0)", [191, 191, 0, 0], "Angles are represented as a part of a circle and wrap around"],
+        ["hsla(-300, 100%, 37.5%, -3)", [191, 191, 0, 0], "Invalid alpha values should be clamped to 0 and 1 respectively"],
+        ["hsla(0, 0%, 0%, 50%)", [0, 0, 0, 0.5], "Percent alpha values are accepted in hsl/hsla"],
+        ["hsla(30deg, 100%, 100%, 1)", [255, 255, 255, 1], "Angles are accepted in HSL/HSLA"],
+        ["hsla(10, 50%, 0, 1)", null, "The second and third parameters of hsl/hsla must be a percent"],
+        ["hsla(50%, 50%, 0%, 1)", null, "The first parameter of hsl/hsla must be a number or angle"],
+        ["hsla(0, 0% 0%, 1)", null, "Comma optional syntax requires no commas at all"],
+        ["hsla(0, 0%, light, 1)", null, "Keywords are not accepted in the hsla function"],
+        ["hsla()", null, "The hsla function requires 3 or 4 arguments"],
+        ["hsla(0)", null, "The hsla function requires 3 or 4 arguments"],
+        ["hsla(0, 0%)", null, "The hsla function requires 3 or 4 arguments"],
+        ["hsla(0, 0%, 0%, 1, 0%)", null, "The hsla function requires 3 or 4 arguments"]
+    ]
+
+    for (var value in tests) {
+        items_to_test = tests[value];
+        color_test(items_to_test[0], expected_value(items_to_test[1]), items_to_test[2]);
+    }
+</script>
diff --git a/css/css-transforms/css-transform-inherit-scale.html b/css/css-transforms/css-transform-inherit-scale.html
index b4702f8..fa9b5bb 100644
--- a/css/css-transforms/css-transform-inherit-scale.html
+++ b/css/css-transforms/css-transform-inherit-scale.html
@@ -1,50 +1,49 @@
 <!DOCTYPE html>
 <html>
-<head>
+  <head>
     <title>CSS Transforms Test: CSS transforms scale 2 inheritance on div elements</title>
     <link rel="author" title="Delong Gao" href="mailto:gaodl@uw.edu">
     <link rel="reviewer" title="Rebecca Hauck" href="mailto:rhauck@adobe.com">
     <link rel="help" href="http://www.w3.org/TR/css-transforms-1/#transform-property">
     <link rel="help" href="http://www.w3.org/TR/css-transforms-1/#two-d-transform-functions">
-    <!--<link rel="match" href="reference/ttwf-reftest-tutorial-ref.html">
-	<meta name="flags" content="svg">-->
+    <link rel="match" href="../reference/ref-filled-green-200px-square.html">
     <meta name="assert" content="While child div inherits property from its parent, scaling 2 on parent div will course the child to scale 4 and totally cover the red div. The test passes if there is a green square and no red. ">
     <style type="text/css">
-		* {
-			margin: 0;
-			padding: 0;
-		}
-		.red {
-			position: absolute;
-			width: 200px;
-			height: 200px;
-			background-color: red;
-		}
-        .parent {
-			background: yellow;
-            width: 50px;
-			height: 50px;
-			position: absolute;
-			top: 75px;
-			left: 75px;
-			transform: scale(2);
+      .test {
+          position: relative;
+      }
+      .red {
+          position: absolute;
+          width: 200px;
+          height: 200px;
+          background-color: red;
+      }
+      .parent {
+          background: yellow;
+          width: 50px;
+          height: 50px;
+          position: absolute;
+          top: 75px;
+          left: 75px;
+          transform: scale(2);
 
-        }
-        .child {
-			position: absolute;
-			top: 10px;
-			transform: inherit;
-            width: 50px;
-			height: 50px;
-			background-color: green;
-        }
+      }
+      .child {
+          position: absolute;
+          transform: inherit;
+          width: 50px;
+          height: 50px;
+          background-color: green;
+      }
     </style>
-</head>
-<body>
-    <p>The test passes if there is a green square and no red. </p>
-	<div class="red"></div>
-	<div class="parent">
-		<div class="child"></div>
-	</div>
-</body>
+  </head>
+  <body>
+    <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+    <div class="test">
+      <div class="red"></div>
+      <div class="parent">
+	<div class="child"></div>
+      </div>
+    </div>
+  </body>
 </html>
diff --git a/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html b/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html
index 4594a1e..7d9a31d 100644
--- a/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html
+++ b/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html
@@ -1,20 +1,18 @@
 <!DOCTYPE html>
 <meta name=timeout content=long>
 <title>Precedence of scroll restoration mode over fragment scrolling in cross-origin history traversal</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
 <style>
   iframe {
     height: 300px;
     width: 300px;
   }
 </style>
-
-<body>
-  <iframe></iframe>
-</body>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script type="text/javascript">
+<div id="log"></div>
+<iframe></iframe>
+<script>
   'use strict';
 
   // The test does the following navigation steps for iframe
@@ -23,13 +21,16 @@
   // 3. go back to page-with-fragment.html
   async_test(function(t) {
     var iframe = document.querySelector('iframe');
-    var baseURL = location.href.substring(0, location.href.lastIndexOf('/'));
+    var hostInfo = get_host_info();
+    var basePath = location.pathname.substring(0, location.pathname.lastIndexOf('/'));
+    var localURL = hostInfo.HTTP_ORIGIN + basePath + '/resources/page-with-fragment.html#fragment';
+    var remoteURL = hostInfo.HTTP_REMOTE_ORIGIN + basePath + "/resources/blank1.html"
 
     var steps = [
       function() {
         iframe.src = 'resources/page-with-fragment.html#fragment';
       }, function() {
-        assert_equals(iframe.contentWindow.location.href, baseURL + '/resources/page-with-fragment.html#fragment', 'should be on page-with-fragment page');
+        assert_equals(iframe.contentWindow.location.href, localURL, 'should be on page-with-fragment page');
         // wait one animation frame to ensure layout is run and fragment scrolling is complete
         iframe.contentWindow.requestAnimationFrame(function() {
           assert_equals(iframe.contentWindow.scrollY, 800, 'should scroll to fragment');
@@ -40,13 +41,13 @@
         });
       }, function() {
         // navigate to a new page from a different origin
-        iframe.src = iframe.src.replace("http://", "http://www.").replace("page-with-fragment.html#fragment", "blank1.html");
+        iframe.src = remoteURL;
       }, function() {
         // going back causes the iframe to traverse back
         history.back();
       }, function() {
         // coming back from history, scrollRestoration should be set to manual and respected
-        assert_equals(iframe.contentWindow.location.href, baseURL + '/resources/page-with-fragment.html#fragment', 'should be back on page-with-fragment page');
+        assert_equals(iframe.contentWindow.location.href, localURL, 'should be back on page-with-fragment page');
         iframe.contentWindow.requestAnimationFrame(t.step_func_done(function() {
           assert_equals(iframe.contentWindow.history.scrollRestoration, 'manual', 'navigating back should retain scrollRestoration value');
           assert_equals(iframe.contentWindow.scrollX, 0, 'should not scroll to fragment');
diff --git a/html/dom/usvstring-reflection.html b/html/dom/usvstring-reflection.html
index 47999df..c3a79e7 100644
--- a/html/dom/usvstring-reflection.html
+++ b/html/dom/usvstring-reflection.html
@@ -13,6 +13,16 @@
 }, "location : unpaired surrogate codepoint should be replaced with U+FFFD");
 
 test(() => {
+  var w = window.open("about:blank#\uD800");
+  assert_equals(w.location.hash, '#%EF%BF%BD');
+}, "window.open : unpaired surrogate codepoint should be replaced with U+FFFD");
+
+test(() => {
+  var w = document.open("about:blank#\uD800", "", "");
+  assert_equals(w.location.hash, '#%EF%BF%BD');
+}, "document.open : unpaired surrogate codepoint should be replaced with U+FFFD");
+
+test(() => {
   var element = document.createElement("a");
   element.ping = '\uD989';
   assert_equals(element.ping, '\uFFFD');
@@ -64,4 +74,16 @@
   assert_equals(element.src.endsWith('%EF%BF%BD'), true);
   assert_equals(element.srcset, '\uFFFD');
 }, "source : unpaired surrogate codepoint should be replaced with U+FFFD")
+
+test(() => {
+  const event = new StorageEvent('storage', {
+    url: window.location.href + '\uD999',
+  });
+  assert_equals(event.url, window.location.href + "\uFFFD");
+}, "storage event : unpaired surrogate codepoint should be replaced with U+FFFD")
+
+test(() => {
+  var wsocket = new EventSource('ws://www.example.com/socketserve\uD899/');
+  assert_true(wsocket.url.endsWith('ws://www.example.com/socketserve%EF%BF%BD/'));
+}, "websocket url : unpaired surrogate codepoint should be replaced with U+FFFD")
 </script>
diff --git a/html/semantics/forms/the-select-element/selected-index.html b/html/semantics/forms/the-select-element/selected-index.html
index 6c30698..46f19da 100644
--- a/html/semantics/forms/the-select-element/selected-index.html
+++ b/html/semantics/forms/the-select-element/selected-index.html
@@ -70,7 +70,7 @@
   assertSelectedIndex(select, 0);
   select.selectedIndex = 2;
   assertSelectedIndex(select, 2);
-  this.add_cleanup(() => select.selectedIndex = 0);
+  this.add_cleanup(() => { select.selectedIndex = 0; });
 }, "set (HTMLSelectElement)");
 
 test(function () {
@@ -78,7 +78,7 @@
   assertSelectedIndex(select, 0);
   select.options.selectedIndex = 2;
   assertSelectedIndex(select, 2);
-  this.add_cleanup(() => select.selectedIndex = 0);
+  this.add_cleanup(() => { select.selectedIndex = 0; });
 }, "set (HTMLOptionsCollection)");
 
 test(function () {
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html b/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html
new file mode 100644
index 0000000..73a6ce3
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Choice of parse errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    setup({allow_uncaught_exception: true});
+
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "Parse errors in different files should be reported " +
+        "depending on different roots");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_equals(log.length, 4);
+
+      // Two different parse errors from different module scripts
+      // should be reported for each <script> element.
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+
+      assert_equals(log[2].constructor, SyntaxError);
+      assert_equals(log[3], 2);
+
+      assert_not_equals(log[0], log[2],
+          'two different parse errors should be reported');
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./choice-of-error-1a.js"
+    onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./choice-of-error-1b.js"
+    onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js b/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js
new file mode 100644
index 0000000..f479e5e
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js
@@ -0,0 +1,2 @@
+import './choice-of-error-1b.js';
+import './syntaxerror.js?1c';
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js b/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js
new file mode 100644
index 0000000..257f4a4
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js
@@ -0,0 +1,2 @@
+import './choice-of-error-1a.js';
+import './syntaxerror.js?1d';
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html b/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html
new file mode 100644
index 0000000..0d67cb8
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Choice of instantiation errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    setup({allow_uncaught_exception: true});
+
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "Instantiation errors in different files should be reported " +
+        "depending on different roots");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_equals(log.length, 4);
+
+      // Two different instantiation errors from different module scripts
+      // should be reported for each <script> element.
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+
+      assert_equals(log[2].constructor, SyntaxError);
+      assert_equals(log[3], 2);
+
+      assert_not_equals(log[0], log[2],
+          'two different instantiation errors should be reported');
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./choice-of-error-2a.js"
+    onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./choice-of-error-2b.js"
+    onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js b/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js
new file mode 100644
index 0000000..2dc7aac
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js
@@ -0,0 +1,2 @@
+import './choice-of-error-2b.js';
+import './instantiation-error-1.js?2c';
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js b/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js
new file mode 100644
index 0000000..2adb9ee
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js
@@ -0,0 +1,2 @@
+import './choice-of-error-2a.js';
+import './instantiation-error-1.js?2d';
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html b/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html
new file mode 100644
index 0000000..5c0adff
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Choice of evaluation errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    setup({allow_uncaught_exception: true});
+
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "Evaluation errors are cached in intermediate module scripts");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_equals(log.length, 5);
+
+      // Evaluation errors, unlike parse/instantiation errors, are remembered
+      // and cached in module scripts between the root and the script that
+      // caused an evaluation error, and thus the same evaluation error
+      // is reported for both <script> elements.
+      assert_equals(log[0], "throw2");
+      assert_true(log[1].bar);
+      assert_equals(log[2], 1);
+
+      assert_true(log[3].bar);
+      assert_equals(log[4], 2);
+
+      assert_equals(log[1], log[3], 'evaluation errors must be the same');
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./choice-of-error-3a.js"
+    onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./choice-of-error-3b.js"
+    onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js b/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js
new file mode 100644
index 0000000..7115467
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js
@@ -0,0 +1,2 @@
+import './choice-of-error-3b.js';
+import './throw.js?3c';
diff --git a/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js b/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js
new file mode 100644
index 0000000..2131a35
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js
@@ -0,0 +1,2 @@
+import './choice-of-error-3a.js';
+import './throw2.js?3d';
diff --git a/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html b/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html
index 9390ce0..1578f85 100644
--- a/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html
+++ b/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html
@@ -9,7 +9,7 @@
   ["parse error", "../syntaxerror.js", new SyntaxError],
   ["bad module specifier", "does-not-start-with-dot.js", new TypeError, { differentErrorObjects: true }],
   ["bad module specifier in a dependency", "../bad-module-specifier.js", new TypeError],
-  ["instantiation error", "../instantiation-error-1.js", new SyntaxError],
+  ["instantiation error", "../instantiation-error-1.js", new SyntaxError, { differentErrorObjects: true }],
   ["evaluation error", "../throw-error.js", new Error]
 ];
 
diff --git a/html/semantics/scripting-1/the-script-element/module/error-type-1.html b/html/semantics/scripting-1/the-script-element/module/error-type-1.html
new file mode 100644
index 0000000..6f119e3
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/error-type-1.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Handling of different types of errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    setup({allow_uncaught_exception: true});
+
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "network error has higher priority than parse error");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_equals(log.length, 3);
+
+      // A parse error is reported for the first top-level
+      // <script> element for syntaxerror.js.
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+
+      // onerror is called (with no errors reported) due to a network error
+      // for the second top-level <script>.
+      assert_equals(log[2], 2);
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./syntaxerror.js"
+    onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./error-type-1.js"
+    onerror="log.push(2)" onload="unreachable()"></script>
diff --git a/html/semantics/scripting-1/the-script-element/module/error-type-1.js b/html/semantics/scripting-1/the-script-element/module/error-type-1.js
new file mode 100644
index 0000000..4882d3f
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/error-type-1.js
@@ -0,0 +1,2 @@
+import './syntaxerror.js';
+import './404.js';
diff --git a/html/semantics/scripting-1/the-script-element/module/error-type-2.html b/html/semantics/scripting-1/the-script-element/module/error-type-2.html
new file mode 100644
index 0000000..a7df1df
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/error-type-2.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Handling of different types of errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    setup({allow_uncaught_exception: true});
+
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "parse error has higher priority than instantiation error");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_equals(log.length, 4);
+
+      // An instantiation error is reported for the first top-level
+      // <script> element for instantiation-error-1.js.
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+
+      // A parse error is reported for the second top-level <script>.
+      assert_equals(log[2].constructor, SyntaxError);
+      assert_equals(log[3], 2);
+      assert_not_equals(log[0], log[2]);
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./instantiation-error-1.js"
+    onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./error-type-2.js"
+    onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/html/semantics/scripting-1/the-script-element/module/error-type-2.js b/html/semantics/scripting-1/the-script-element/module/error-type-2.js
new file mode 100644
index 0000000..6b11397
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/error-type-2.js
@@ -0,0 +1,2 @@
+import './instantiation-error-1.js';
+import './syntaxerror.js';
diff --git a/html/semantics/scripting-1/the-script-element/module/error-type-3.html b/html/semantics/scripting-1/the-script-element/module/error-type-3.html
new file mode 100644
index 0000000..9b00df3
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/error-type-3.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Handling of different types of errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    setup({allow_uncaught_exception: true});
+
+    window.log = [];
+
+    window.addEventListener("error", ev => log.push(ev.error));
+
+    const test_load = async_test(
+        "instantiation error has higher priority than evaluation error");
+    window.addEventListener("load", test_load.step_func_done(ev => {
+      assert_equals(log.length, 5);
+
+      // An evaluation error is reported for the first top-level
+      // <script> element for throw.js.
+      assert_equals(log[0], 'throw');
+      assert_true(log[1].foo);
+      assert_equals(log[2], 1);
+
+      // An instantiation error is reported for the second top-level <script>.
+      assert_equals(log[3].constructor, SyntaxError);
+      assert_equals(log[4], 2);
+    }));
+
+    function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./throw.js"
+    onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./error-type-3.js"
+    onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/html/semantics/scripting-1/the-script-element/module/error-type-3.js b/html/semantics/scripting-1/the-script-element/module/error-type-3.js
new file mode 100644
index 0000000..542be52
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/error-type-3.js
@@ -0,0 +1,2 @@
+import './throw.js';
+import './instantiation-error-1.js';
diff --git a/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html b/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html
index efdf587..1cb0799 100644
--- a/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html
+++ b/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html
@@ -12,11 +12,19 @@
 
     const test_load = async_test(
         "Test that missing exports lead to SyntaxError events on window and " +
-        "load events on script, and that exceptions are remembered");
+        "load events on script");
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2, exn, 3, exn, 4, exn, 5]);
-      assert_equals(exn.constructor, SyntaxError);
+      assert_equals(log.length, 10);
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+      assert_equals(log[2].constructor, SyntaxError);
+      assert_equals(log[3], 2);
+      assert_equals(log[4].constructor, SyntaxError);
+      assert_equals(log[5], 3);
+      assert_equals(log[6].constructor, SyntaxError);
+      assert_equals(log[7], 4);
+      assert_equals(log[8].constructor, SyntaxError);
+      assert_equals(log[9], 5);
     }));
 
     function unreachable() { log.push("unexpected"); }
diff --git a/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html b/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html
index 3d50ce6..d7151f2 100644
--- a/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html
+++ b/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html
@@ -12,11 +12,19 @@
 
     const test_load = async_test(
         "Test that missing exports lead to SyntaxError events on window and " +
-        "load events on script, and that exceptions are remembered");
+        "load events on script");
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2, exn, 3, exn, 4, exn, 5]);
-      assert_equals(exn.constructor, SyntaxError);
+      assert_equals(log.length, 10);
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+      assert_equals(log[2].constructor, SyntaxError);
+      assert_equals(log[3], 2);
+      assert_equals(log[4].constructor, SyntaxError);
+      assert_equals(log[5], 3);
+      assert_equals(log[6].constructor, SyntaxError);
+      assert_equals(log[7], 4);
+      assert_equals(log[8].constructor, SyntaxError);
+      assert_equals(log[9], 5);
     }));
 
     function unreachable() { log.push("unexpected"); }
diff --git a/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html b/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html
index ab510c6..739bf0e 100644
--- a/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html
+++ b/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html
@@ -12,11 +12,15 @@
 
     const test_load = async_test(
         "Test that unresolvable cycles lead to SyntaxError events on window " +
-        "and load events on script, and that exceptions are remembered");
+        "and load events on script");
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2, exn, 3]);
-      assert_equals(exn.constructor, SyntaxError);
+      assert_equals(log.length, 6);
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+      assert_equals(log[2].constructor, SyntaxError);
+      assert_equals(log[3], 2);
+      assert_equals(log[4].constructor, SyntaxError);
+      assert_equals(log[5], 3);
     }));
 
     function unreachable() { log.push("unexpected"); }
diff --git a/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html b/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html
index 4eb2f9f..b6be1db 100644
--- a/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html
+++ b/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html
@@ -14,9 +14,11 @@
         "Test that loading a graph in which a module is already " +
         "errored results in that module's error.");
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2]);
-      assert_equals(exn.constructor, SyntaxError);
+      assert_equals(log.length, 4);
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+      assert_equals(log[2].constructor, SyntaxError);
+      assert_equals(log[3], 2);
     }));
 
     function unreachable() { log.push("unexpected"); }
diff --git a/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html b/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html
index 86d0fb3..5afd011 100644
--- a/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html
+++ b/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html
@@ -14,9 +14,12 @@
         "Test that loading a graph in which a module is already " +
         "errored results in that module's error.");
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2]);
-      assert_equals(exn.constructor, SyntaxError);
+      assert_equals(log.length, 4);
+      assert_equals(log[0].constructor, SyntaxError);
+      assert_equals(log[1], 1);
+      assert_equals(log[2].constructor, SyntaxError);
+      assert_equals(log[3], 2);
+      assert_not_equals(log[0], log[2], "errors should be different");
     }));
 
     function unreachable() { log.push("unexpected"); }
diff --git a/html/semantics/scripting-1/the-script-element/module/throw2.js b/html/semantics/scripting-1/the-script-element/module/throw2.js
new file mode 100644
index 0000000..2931eec
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/module/throw2.js
@@ -0,0 +1,2 @@
+log.push("throw2");
+throw {bar: true}
diff --git a/service-workers/service-worker/postmessage.https.html b/service-workers/service-worker/postmessage.https.html
index 3a6487e..5c43b95 100644
--- a/service-workers/service-worker/postmessage.https.html
+++ b/service-workers/service-worker/postmessage.https.html
@@ -13,7 +13,11 @@
 
     return service_worker_unregister_and_register(t, script, scope)
       .then(r => {
-          t.add_cleanup(() => r.unregister());
+          // TODO: return the Promise created by `r.unregister`once
+          // `testharness.js` has been updated to honor thenables returned by
+          // cleanup functions.
+          // See https://github.com/w3c/web-platform-tests/pull/8748
+          t.add_cleanup(() => { r.unregister(); });
           registration = r;
           worker = registration.installing;
 
@@ -62,7 +66,11 @@
 
     return service_worker_unregister_and_register(t, script, scope)
       .then(r => {
-          t.add_cleanup(() => r.unregister());
+          // TODO: return the Promise created by `r.unregister`once
+          // `testharness.js` has been updated to honor thenables returned by
+          // cleanup functions.
+          // See https://github.com/w3c/web-platform-tests/pull/8748
+          t.add_cleanup(() => { r.unregister(); });
 
           var ab = text_encoder.encode(message);
           assert_equals(ab.byteLength, message.length);
@@ -102,7 +110,11 @@
 
     return service_worker_unregister_and_register(t, script, scope)
       .then(r => {
-          t.add_cleanup(() => r.unregister());
+          // TODO: return the Promise created by `r.unregister`once
+          // `testharness.js` has been updated to honor thenables returned by
+          // cleanup functions.
+          // See https://github.com/w3c/web-platform-tests/pull/8748
+          t.add_cleanup(() => { r.unregister(); });
 
           var channel = new MessageChannel;
           port = channel.port1;
diff --git a/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html b/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html
index a310d9a..d4663e5 100644
--- a/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html
+++ b/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html
@@ -409,4 +409,18 @@
     }));
   }, 'track.onmute fires before setRemoteDescription resolves.');
 
+  async_test(t => {
+    const pc = new RTCPeerConnection();
+    return getUserMediaTracksAndStreams(1)
+    .then(t.step_func(([tracks, streams]) => {
+      const sender = pc.addTrack(tracks[0]);
+      assert_not_equals(sender, null);
+      pc.removeTrack(sender);
+      pc.removeTrack(sender);
+      t.done();
+    }))
+    .catch(t.step_func(reason => {
+      assert_unreached(reason);
+    }));
+  }, 'removeTrack() twice is safe.');
 </script>
diff --git a/webxr/resources/webxr_check.html b/webxr/resources/webxr_check.html
new file mode 100644
index 0000000..2d8e5b3
--- /dev/null
+++ b/webxr/resources/webxr_check.html
@@ -0,0 +1,17 @@
+<script src=webxr_util.js></script>
+<script>
+'use strict';
+let definedObjects = [];
+let undefinedObjects = [];
+
+forEachWebxrObject((obj, name) => {
+    if(obj == undefined) {
+        undefinedObjects.push(name);
+    } else {
+        definedObjects.push(name);
+    }
+});
+
+window.parent.postMessage({ undefinedObjects, definedObjects}, '*');
+
+</script>
\ No newline at end of file
diff --git a/webxr/resources/webxr_util.js b/webxr/resources/webxr_util.js
new file mode 100644
index 0000000..a663b2d
--- /dev/null
+++ b/webxr/resources/webxr_util.js
@@ -0,0 +1,27 @@
+// This functions calls a callback with each API object as specified
+// by https://immersive-web.github.io/webxr/spec/latest/, allowing
+// checks to be made on all ojects.
+// Arguements:
+//      callback: A callback function with two arguements, the first
+//                being the API object, the second being the name of
+//                that API object.
+function forEachWebxrObject(callback) {
+  callback(window.navigator.xr, 'navigator.xr');
+  callback(window.XRDevice, 'XRDevice');
+  callback(window.XRSession, 'XRSession');
+  callback(window.XRSessionCreationOptions, 'XRSessionCreationOptions');
+  callback(window.XRFrameRequestCallback, 'XRFrameRequestCallback');
+  callback(window.XRPresentationFrame, 'XRPresentationFrame');
+  callback(window.XRView, 'XRView');
+  callback(window.XRViewport, 'XRViewport');
+  callback(window.XRDevicePose, 'XRDevicePose');
+  callback(window.XRLayer, 'XRLayer');
+  callback(window.XRWebGLLayer, 'XRWebGLLayer');
+  callback(window.XRWebGLLayerInit, 'XRWebGLLayerInit');
+  callback(window.XRCoordinateSystem, 'XRCoordinateSystem');
+  callback(window.XRFrameOfReference, 'XRFrameOfReference');
+  callback(window.XRStageBounds, 'XRStageBounds');
+  callback(window.XRStageBoundsPoint, 'XRStageBoundsPoint');
+  callback(window.XRSessionEvent, 'XRSessionEvent');
+  callback(window.XRCoordinateSystemEvent, 'XRCoordinateSystemEvent');
+}
\ No newline at end of file
diff --git a/webxr/webxr_availability.http.sub.html b/webxr/webxr_availability.http.sub.html
new file mode 100644
index 0000000..515b2ad
--- /dev/null
+++ b/webxr/webxr_availability.http.sub.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src=/webxr/resources/webxr_util.js></script>
+  <script>
+    'use strict';
+
+    var same_origin_src = '/webxr/resources/';
+    var cross_origin_https_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+      same_origin_src;
+
+    test(t => {
+      forEachWebxrObject((obj, name) => {
+        assert_equals(obj, undefined, name + ' was defined in insecure context.');
+      });
+    }, 'Test webxr not available in insecure context');
+
+    async_test(t => {
+      let frame = document.createElement('iframe');
+      frame.src = cross_origin_https_src + 'webxr_check.html';
+
+      window.addEventListener('message', t.step_func(function handler(evt) {
+          if (evt.source === frame.contentWindow) {
+            document.body.removeChild(frame);
+            window.removeEventListener('message', handler);
+
+            assert_equals(evt.data.definedObjects.length, 0,
+              "Some objects were defined in insecure context: " +
+              evt.data.definedObjects.toString());
+            t.done();
+          }
+      }));
+
+      document.body.appendChild(frame);
+    }, 'Test webxr not available in secure context in insecure context');
+
+  </script>
+</body>