mirror of
				https://github.com/tc39/test262.git
				synced 2025-11-04 05:33:50 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1168 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1168 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// Copyright 2011-2012 Norbert Lindenberg. All rights reserved.
 | 
						||
// Copyright 2012-2013 Mozilla Corporation. All rights reserved.
 | 
						||
// This code is governed by the BSD license found in the LICENSE file.
 | 
						||
 | 
						||
/**
 | 
						||
 * This file contains shared functions for the tests in the conformance test
 | 
						||
 * suite for the ECMAScript Internationalization API.
 | 
						||
 * @author Norbert Lindenberg
 | 
						||
 */
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * @description Calls the provided function for every service constructor in
 | 
						||
 * the Intl object, until f returns a falsy value. It returns the result of the
 | 
						||
 * last call to f, mapped to a boolean.
 | 
						||
 * @param {Function} f the function to call for each service constructor in
 | 
						||
 *     the Intl object.
 | 
						||
 *     @param {Function} Constructor the constructor object to test with.
 | 
						||
 * @result {Boolean} whether the test succeeded.
 | 
						||
 */
 | 
						||
function testWithIntlConstructors(f) {
 | 
						||
    var constructors = ["Collator", "NumberFormat", "DateTimeFormat"];
 | 
						||
    return constructors.every(function (constructor) {
 | 
						||
        var Constructor = Intl[constructor];
 | 
						||
        var result;
 | 
						||
        try {
 | 
						||
            result = f(Constructor);
 | 
						||
        } catch (e) {
 | 
						||
            e.message += " (Testing with " + constructor + ".)";
 | 
						||
            throw e;
 | 
						||
        }
 | 
						||
        return result;
 | 
						||
    });
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Returns the name of the given constructor object, which must be one of
 | 
						||
 * Intl.Collator, Intl.NumberFormat, or Intl.DateTimeFormat.
 | 
						||
 * @param {object} Constructor a constructor
 | 
						||
 * @return {string} the name of the constructor
 | 
						||
 */
 | 
						||
function getConstructorName(Constructor) {
 | 
						||
    switch (Constructor) {
 | 
						||
        case Intl.Collator:
 | 
						||
            return "Collator";
 | 
						||
        case Intl.NumberFormat:
 | 
						||
            return "NumberFormat";
 | 
						||
        case Intl.DateTimeFormat:
 | 
						||
            return "DateTimeFormat";
 | 
						||
        default:
 | 
						||
            $ERROR("test internal error: unknown Constructor");
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Taints a named data property of the given object by installing
 | 
						||
 * a setter that throws an exception.
 | 
						||
 * @param {object} obj the object whose data property to taint
 | 
						||
 * @param {string} property the property to taint
 | 
						||
 */
 | 
						||
function taintDataProperty(obj, property) {
 | 
						||
    Object.defineProperty(obj, property, {
 | 
						||
        set: function(value) {
 | 
						||
            $ERROR("Client code can adversely affect behavior: setter for " + property + ".");
 | 
						||
        },
 | 
						||
        enumerable: false,
 | 
						||
        configurable: true
 | 
						||
    });
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Taints a named method of the given object by replacing it with a function
 | 
						||
 * that throws an exception.
 | 
						||
 * @param {object} obj the object whose method to taint
 | 
						||
 * @param {string} property the name of the method to taint
 | 
						||
 */
 | 
						||
function taintMethod(obj, property) {
 | 
						||
    Object.defineProperty(obj, property, {
 | 
						||
        value: function() {
 | 
						||
            $ERROR("Client code can adversely affect behavior: method " + property + ".");
 | 
						||
        },
 | 
						||
        writable: true,
 | 
						||
        enumerable: false,
 | 
						||
        configurable: true
 | 
						||
    });
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Taints the given properties (and similarly named properties) by installing
 | 
						||
 * setters on Object.prototype that throw exceptions.
 | 
						||
 * @param {Array} properties an array of property names to taint
 | 
						||
 */
 | 
						||
function taintProperties(properties) {
 | 
						||
    properties.forEach(function (property) {
 | 
						||
        var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"];
 | 
						||
        adaptedProperties.forEach(function (property) {
 | 
						||
            taintDataProperty(Object.prototype, property);
 | 
						||
        });
 | 
						||
    });
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Taints the Array object by creating a setter for the property "0" and
 | 
						||
 * replacing some key methods with functions that throw exceptions.
 | 
						||
 */
 | 
						||
function taintArray() {
 | 
						||
    taintDataProperty(Array.prototype, "0");
 | 
						||
    taintMethod(Array.prototype, "indexOf");
 | 
						||
    taintMethod(Array.prototype, "join");
 | 
						||
    taintMethod(Array.prototype, "push");
 | 
						||
    taintMethod(Array.prototype, "slice");
 | 
						||
    taintMethod(Array.prototype, "sort");
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// auxiliary data for getLocaleSupportInfo
 | 
						||
var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"];
 | 
						||
var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant"];
 | 
						||
var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG"];
 | 
						||
var localeSupportInfo = {};
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Gets locale support info for the given constructor object, which must be one
 | 
						||
 * of Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat.
 | 
						||
 * @param {object} Constructor the constructor for which to get locale support info
 | 
						||
 * @return {object} locale support info with the following properties:
 | 
						||
 *     supported: array of fully supported language tags
 | 
						||
 *     byFallback: array of language tags that are supported through fallbacks
 | 
						||
 *     unsupported: array of unsupported language tags
 | 
						||
 */
 | 
						||
function getLocaleSupportInfo(Constructor) {
 | 
						||
    var constructorName = getConstructorName(Constructor);
 | 
						||
    if (localeSupportInfo[constructorName] !== undefined) {
 | 
						||
        return localeSupportInfo[constructorName];
 | 
						||
    }
 | 
						||
 | 
						||
    var allTags = [];
 | 
						||
    var i, j, k;
 | 
						||
    var language, script, country;
 | 
						||
    for (i = 0; i < languages.length; i++) {
 | 
						||
        language = languages[i];
 | 
						||
        allTags.push(language);
 | 
						||
        for (j = 0; j < scripts.length; j++) {
 | 
						||
            script = scripts[j];
 | 
						||
            allTags.push(language + "-" + script);
 | 
						||
            for (k = 0; k < countries.length; k++) {
 | 
						||
                country = countries[k];
 | 
						||
                allTags.push(language + "-" + script + "-" + country);
 | 
						||
            }
 | 
						||
        }
 | 
						||
        for (k = 0; k < countries.length; k++) {
 | 
						||
            country = countries[k];
 | 
						||
            allTags.push(language + "-" + country);
 | 
						||
        }
 | 
						||
    }
 | 
						||
    
 | 
						||
    var supported = [];
 | 
						||
    var byFallback = [];
 | 
						||
    var unsupported = [];
 | 
						||
    for (i = 0; i < allTags.length; i++) {
 | 
						||
        var request = allTags[i];
 | 
						||
        var result = new Constructor([request], {localeMatcher: "lookup"}).resolvedOptions().locale;
 | 
						||
         if (request === result) {
 | 
						||
            supported.push(request);
 | 
						||
        } else if (request.indexOf(result) === 0) {
 | 
						||
            byFallback.push(request);
 | 
						||
        } else {
 | 
						||
            unsupported.push(request);
 | 
						||
        }
 | 
						||
    }
 | 
						||
    
 | 
						||
    localeSupportInfo[constructorName] = {
 | 
						||
        supported: supported,
 | 
						||
        byFallback: byFallback,
 | 
						||
        unsupported: unsupported
 | 
						||
    };
 | 
						||
    
 | 
						||
    return localeSupportInfo[constructorName];
 | 
						||
}
 | 
						||
        
 | 
						||
 | 
						||
/**
 | 
						||
 * @description Tests whether locale is a String value representing a
 | 
						||
 * structurally valid and canonicalized BCP 47 language tag, as defined in
 | 
						||
 * sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API
 | 
						||
 * Specification.
 | 
						||
 * @param {String} locale the string to be tested.
 | 
						||
 * @result {Boolean} whether the test succeeded.
 | 
						||
 */
 | 
						||
function isCanonicalizedStructurallyValidLanguageTag(locale) {
 | 
						||
 | 
						||
    /**
 | 
						||
     * Regular expression defining BCP 47 language tags.
 | 
						||
     *
 | 
						||
     * Spec: RFC 5646 section 2.1.
 | 
						||
     */
 | 
						||
    var alpha = "[a-zA-Z]",
 | 
						||
        digit = "[0-9]",
 | 
						||
        alphanum = "(" + alpha + "|" + digit + ")",
 | 
						||
        regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)",
 | 
						||
        irregular = "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)",
 | 
						||
        grandfathered = "(" + irregular + "|" + regular + ")",
 | 
						||
        privateuse = "(x(-[a-z0-9]{1,8})+)",
 | 
						||
        singleton = "(" + digit + "|[A-WY-Za-wy-z])",
 | 
						||
        extension = "(" + singleton + "(-" + alphanum + "{2,8})+)",
 | 
						||
        variant = "(" + alphanum + "{5,8}|(" + digit + alphanum + "{3}))",
 | 
						||
        region = "(" + alpha + "{2}|" + digit + "{3})",
 | 
						||
        script = "(" + alpha + "{4})",
 | 
						||
        extlang = "(" + alpha + "{3}(-" + alpha + "{3}){0,2})",
 | 
						||
        language = "(" + alpha + "{2,3}(-" + extlang + ")?|" + alpha + "{4}|" + alpha + "{5,8})",
 | 
						||
        langtag = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?",
 | 
						||
        languageTag = "^(" + langtag + "|" + privateuse + "|" + grandfathered + ")$",
 | 
						||
        languageTagRE = new RegExp(languageTag, "i");
 | 
						||
    var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")",
 | 
						||
        duplicateSingletonRE = new RegExp(duplicateSingleton, "i"),
 | 
						||
        duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\3(?!" + alphanum + ")",
 | 
						||
        duplicateVariantRE = new RegExp(duplicateVariant, "i");
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * Verifies that the given string is a well-formed BCP 47 language tag
 | 
						||
     * with no duplicate variant or singleton subtags.
 | 
						||
     *
 | 
						||
     * Spec: ECMAScript Internationalization API Specification, draft, 6.2.2.
 | 
						||
     */
 | 
						||
    function isStructurallyValidLanguageTag(locale) {
 | 
						||
        if (!languageTagRE.test(locale)) {
 | 
						||
            return false;
 | 
						||
        }
 | 
						||
        locale = locale.split(/-x-/)[0];
 | 
						||
        return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * Mappings from complete tags to preferred values.
 | 
						||
     *
 | 
						||
     * Spec: IANA Language Subtag Registry.
 | 
						||
     */
 | 
						||
    var __tagMappings = {
 | 
						||
        // property names must be in lower case; values in canonical form
 | 
						||
 | 
						||
        // grandfathered tags from IANA language subtag registry, file date 2011-08-25
 | 
						||
        "art-lojban": "jbo",
 | 
						||
        "cel-gaulish": "cel-gaulish",
 | 
						||
        "en-gb-oed": "en-GB-oed",
 | 
						||
        "i-ami": "ami",
 | 
						||
        "i-bnn": "bnn",
 | 
						||
        "i-default": "i-default",
 | 
						||
        "i-enochian": "i-enochian",
 | 
						||
        "i-hak": "hak",
 | 
						||
        "i-klingon": "tlh",
 | 
						||
        "i-lux": "lb",
 | 
						||
        "i-mingo": "i-mingo",
 | 
						||
        "i-navajo": "nv",
 | 
						||
        "i-pwn": "pwn",
 | 
						||
        "i-tao": "tao",
 | 
						||
        "i-tay": "tay",
 | 
						||
        "i-tsu": "tsu",
 | 
						||
        "no-bok": "nb",
 | 
						||
        "no-nyn": "nn",
 | 
						||
        "sgn-be-fr": "sfb",
 | 
						||
        "sgn-be-nl": "vgt",
 | 
						||
        "sgn-ch-de": "sgg",
 | 
						||
        "zh-guoyu": "cmn",
 | 
						||
        "zh-hakka": "hak",
 | 
						||
        "zh-min": "zh-min",
 | 
						||
        "zh-min-nan": "nan",
 | 
						||
        "zh-xiang": "hsn",
 | 
						||
        // deprecated redundant tags from IANA language subtag registry, file date 2011-08-25
 | 
						||
        "sgn-br": "bzs",
 | 
						||
        "sgn-co": "csn",
 | 
						||
        "sgn-de": "gsg",
 | 
						||
        "sgn-dk": "dsl",
 | 
						||
        "sgn-es": "ssp",
 | 
						||
        "sgn-fr": "fsl",
 | 
						||
        "sgn-gb": "bfi",
 | 
						||
        "sgn-gr": "gss",
 | 
						||
        "sgn-ie": "isg",
 | 
						||
        "sgn-it": "ise",
 | 
						||
        "sgn-jp": "jsl",
 | 
						||
        "sgn-mx": "mfs",
 | 
						||
        "sgn-ni": "ncs",
 | 
						||
        "sgn-nl": "dse",
 | 
						||
        "sgn-no": "nsl",
 | 
						||
        "sgn-pt": "psr",
 | 
						||
        "sgn-se": "swl",
 | 
						||
        "sgn-us": "ase",
 | 
						||
        "sgn-za": "sfs",
 | 
						||
        "zh-cmn": "cmn",
 | 
						||
        "zh-cmn-hans": "cmn-Hans",
 | 
						||
        "zh-cmn-hant": "cmn-Hant",
 | 
						||
        "zh-gan": "gan",
 | 
						||
        "zh-wuu": "wuu",
 | 
						||
        "zh-yue": "yue",
 | 
						||
        // deprecated variant with prefix from IANA language subtag registry, file date 2011-08-25
 | 
						||
        "ja-latn-hepburn-heploc": "ja-Latn-alalc97"
 | 
						||
    };
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * Mappings from non-extlang subtags to preferred values.
 | 
						||
     *
 | 
						||
     * Spec: IANA Language Subtag Registry.
 | 
						||
     */
 | 
						||
    var __subtagMappings = {
 | 
						||
        // property names and values must be in canonical case
 | 
						||
        // language subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
 | 
						||
        "in": "id",
 | 
						||
        "iw": "he",
 | 
						||
        "ji": "yi",
 | 
						||
        "jw": "jv",
 | 
						||
        "mo": "ro",
 | 
						||
        "ayx": "nun",
 | 
						||
        "cjr": "mom",
 | 
						||
        "cmk": "xch",
 | 
						||
        "drh": "khk",
 | 
						||
        "drw": "prs",
 | 
						||
        "gav": "dev",
 | 
						||
        "mst": "mry",
 | 
						||
        "myt": "mry",
 | 
						||
        "tie": "ras",
 | 
						||
        "tkk": "twm",
 | 
						||
        "tnf": "prs",
 | 
						||
        // region subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
 | 
						||
        "BU": "MM",
 | 
						||
        "DD": "DE",
 | 
						||
        "FX": "FR",
 | 
						||
        "TP": "TL",
 | 
						||
        "YD": "YE",
 | 
						||
        "ZR": "CD"
 | 
						||
    };
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * Mappings from extlang subtags to preferred values.
 | 
						||
     *
 | 
						||
     * Spec: IANA Language Subtag Registry.
 | 
						||
     */
 | 
						||
    var __extlangMappings = {
 | 
						||
        // extlang subtags with Preferred-Value mappings from IANA language subtag registry, file date 2011-08-25
 | 
						||
        // values are arrays with [0] the replacement value, [1] (if present) the prefix to be removed
 | 
						||
        "aao": ["aao", "ar"],
 | 
						||
        "abh": ["abh", "ar"],
 | 
						||
        "abv": ["abv", "ar"],
 | 
						||
        "acm": ["acm", "ar"],
 | 
						||
        "acq": ["acq", "ar"],
 | 
						||
        "acw": ["acw", "ar"],
 | 
						||
        "acx": ["acx", "ar"],
 | 
						||
        "acy": ["acy", "ar"],
 | 
						||
        "adf": ["adf", "ar"],
 | 
						||
        "ads": ["ads", "sgn"],
 | 
						||
        "aeb": ["aeb", "ar"],
 | 
						||
        "aec": ["aec", "ar"],
 | 
						||
        "aed": ["aed", "sgn"],
 | 
						||
        "aen": ["aen", "sgn"],
 | 
						||
        "afb": ["afb", "ar"],
 | 
						||
        "afg": ["afg", "sgn"],
 | 
						||
        "ajp": ["ajp", "ar"],
 | 
						||
        "apc": ["apc", "ar"],
 | 
						||
        "apd": ["apd", "ar"],
 | 
						||
        "arb": ["arb", "ar"],
 | 
						||
        "arq": ["arq", "ar"],
 | 
						||
        "ars": ["ars", "ar"],
 | 
						||
        "ary": ["ary", "ar"],
 | 
						||
        "arz": ["arz", "ar"],
 | 
						||
        "ase": ["ase", "sgn"],
 | 
						||
        "asf": ["asf", "sgn"],
 | 
						||
        "asp": ["asp", "sgn"],
 | 
						||
        "asq": ["asq", "sgn"],
 | 
						||
        "asw": ["asw", "sgn"],
 | 
						||
        "auz": ["auz", "ar"],
 | 
						||
        "avl": ["avl", "ar"],
 | 
						||
        "ayh": ["ayh", "ar"],
 | 
						||
        "ayl": ["ayl", "ar"],
 | 
						||
        "ayn": ["ayn", "ar"],
 | 
						||
        "ayp": ["ayp", "ar"],
 | 
						||
        "bbz": ["bbz", "ar"],
 | 
						||
        "bfi": ["bfi", "sgn"],
 | 
						||
        "bfk": ["bfk", "sgn"],
 | 
						||
        "bjn": ["bjn", "ms"],
 | 
						||
        "bog": ["bog", "sgn"],
 | 
						||
        "bqn": ["bqn", "sgn"],
 | 
						||
        "bqy": ["bqy", "sgn"],
 | 
						||
        "btj": ["btj", "ms"],
 | 
						||
        "bve": ["bve", "ms"],
 | 
						||
        "bvl": ["bvl", "sgn"],
 | 
						||
        "bvu": ["bvu", "ms"],
 | 
						||
        "bzs": ["bzs", "sgn"],
 | 
						||
        "cdo": ["cdo", "zh"],
 | 
						||
        "cds": ["cds", "sgn"],
 | 
						||
        "cjy": ["cjy", "zh"],
 | 
						||
        "cmn": ["cmn", "zh"],
 | 
						||
        "coa": ["coa", "ms"],
 | 
						||
        "cpx": ["cpx", "zh"],
 | 
						||
        "csc": ["csc", "sgn"],
 | 
						||
        "csd": ["csd", "sgn"],
 | 
						||
        "cse": ["cse", "sgn"],
 | 
						||
        "csf": ["csf", "sgn"],
 | 
						||
        "csg": ["csg", "sgn"],
 | 
						||
        "csl": ["csl", "sgn"],
 | 
						||
        "csn": ["csn", "sgn"],
 | 
						||
        "csq": ["csq", "sgn"],
 | 
						||
        "csr": ["csr", "sgn"],
 | 
						||
        "czh": ["czh", "zh"],
 | 
						||
        "czo": ["czo", "zh"],
 | 
						||
        "doq": ["doq", "sgn"],
 | 
						||
        "dse": ["dse", "sgn"],
 | 
						||
        "dsl": ["dsl", "sgn"],
 | 
						||
        "dup": ["dup", "ms"],
 | 
						||
        "ecs": ["ecs", "sgn"],
 | 
						||
        "esl": ["esl", "sgn"],
 | 
						||
        "esn": ["esn", "sgn"],
 | 
						||
        "eso": ["eso", "sgn"],
 | 
						||
        "eth": ["eth", "sgn"],
 | 
						||
        "fcs": ["fcs", "sgn"],
 | 
						||
        "fse": ["fse", "sgn"],
 | 
						||
        "fsl": ["fsl", "sgn"],
 | 
						||
        "fss": ["fss", "sgn"],
 | 
						||
        "gan": ["gan", "zh"],
 | 
						||
        "gom": ["gom", "kok"],
 | 
						||
        "gse": ["gse", "sgn"],
 | 
						||
        "gsg": ["gsg", "sgn"],
 | 
						||
        "gsm": ["gsm", "sgn"],
 | 
						||
        "gss": ["gss", "sgn"],
 | 
						||
        "gus": ["gus", "sgn"],
 | 
						||
        "hab": ["hab", "sgn"],
 | 
						||
        "haf": ["haf", "sgn"],
 | 
						||
        "hak": ["hak", "zh"],
 | 
						||
        "hds": ["hds", "sgn"],
 | 
						||
        "hji": ["hji", "ms"],
 | 
						||
        "hks": ["hks", "sgn"],
 | 
						||
        "hos": ["hos", "sgn"],
 | 
						||
        "hps": ["hps", "sgn"],
 | 
						||
        "hsh": ["hsh", "sgn"],
 | 
						||
        "hsl": ["hsl", "sgn"],
 | 
						||
        "hsn": ["hsn", "zh"],
 | 
						||
        "icl": ["icl", "sgn"],
 | 
						||
        "ils": ["ils", "sgn"],
 | 
						||
        "inl": ["inl", "sgn"],
 | 
						||
        "ins": ["ins", "sgn"],
 | 
						||
        "ise": ["ise", "sgn"],
 | 
						||
        "isg": ["isg", "sgn"],
 | 
						||
        "isr": ["isr", "sgn"],
 | 
						||
        "jak": ["jak", "ms"],
 | 
						||
        "jax": ["jax", "ms"],
 | 
						||
        "jcs": ["jcs", "sgn"],
 | 
						||
        "jhs": ["jhs", "sgn"],
 | 
						||
        "jls": ["jls", "sgn"],
 | 
						||
        "jos": ["jos", "sgn"],
 | 
						||
        "jsl": ["jsl", "sgn"],
 | 
						||
        "jus": ["jus", "sgn"],
 | 
						||
        "kgi": ["kgi", "sgn"],
 | 
						||
        "knn": ["knn", "kok"],
 | 
						||
        "kvb": ["kvb", "ms"],
 | 
						||
        "kvk": ["kvk", "sgn"],
 | 
						||
        "kvr": ["kvr", "ms"],
 | 
						||
        "kxd": ["kxd", "ms"],
 | 
						||
        "lbs": ["lbs", "sgn"],
 | 
						||
        "lce": ["lce", "ms"],
 | 
						||
        "lcf": ["lcf", "ms"],
 | 
						||
        "liw": ["liw", "ms"],
 | 
						||
        "lls": ["lls", "sgn"],
 | 
						||
        "lsg": ["lsg", "sgn"],
 | 
						||
        "lsl": ["lsl", "sgn"],
 | 
						||
        "lso": ["lso", "sgn"],
 | 
						||
        "lsp": ["lsp", "sgn"],
 | 
						||
        "lst": ["lst", "sgn"],
 | 
						||
        "lsy": ["lsy", "sgn"],
 | 
						||
        "ltg": ["ltg", "lv"],
 | 
						||
        "lvs": ["lvs", "lv"],
 | 
						||
        "lzh": ["lzh", "zh"],
 | 
						||
        "max": ["max", "ms"],
 | 
						||
        "mdl": ["mdl", "sgn"],
 | 
						||
        "meo": ["meo", "ms"],
 | 
						||
        "mfa": ["mfa", "ms"],
 | 
						||
        "mfb": ["mfb", "ms"],
 | 
						||
        "mfs": ["mfs", "sgn"],
 | 
						||
        "min": ["min", "ms"],
 | 
						||
        "mnp": ["mnp", "zh"],
 | 
						||
        "mqg": ["mqg", "ms"],
 | 
						||
        "mre": ["mre", "sgn"],
 | 
						||
        "msd": ["msd", "sgn"],
 | 
						||
        "msi": ["msi", "ms"],
 | 
						||
        "msr": ["msr", "sgn"],
 | 
						||
        "mui": ["mui", "ms"],
 | 
						||
        "mzc": ["mzc", "sgn"],
 | 
						||
        "mzg": ["mzg", "sgn"],
 | 
						||
        "mzy": ["mzy", "sgn"],
 | 
						||
        "nan": ["nan", "zh"],
 | 
						||
        "nbs": ["nbs", "sgn"],
 | 
						||
        "ncs": ["ncs", "sgn"],
 | 
						||
        "nsi": ["nsi", "sgn"],
 | 
						||
        "nsl": ["nsl", "sgn"],
 | 
						||
        "nsp": ["nsp", "sgn"],
 | 
						||
        "nsr": ["nsr", "sgn"],
 | 
						||
        "nzs": ["nzs", "sgn"],
 | 
						||
        "okl": ["okl", "sgn"],
 | 
						||
        "orn": ["orn", "ms"],
 | 
						||
        "ors": ["ors", "ms"],
 | 
						||
        "pel": ["pel", "ms"],
 | 
						||
        "pga": ["pga", "ar"],
 | 
						||
        "pks": ["pks", "sgn"],
 | 
						||
        "prl": ["prl", "sgn"],
 | 
						||
        "prz": ["prz", "sgn"],
 | 
						||
        "psc": ["psc", "sgn"],
 | 
						||
        "psd": ["psd", "sgn"],
 | 
						||
        "pse": ["pse", "ms"],
 | 
						||
        "psg": ["psg", "sgn"],
 | 
						||
        "psl": ["psl", "sgn"],
 | 
						||
        "pso": ["pso", "sgn"],
 | 
						||
        "psp": ["psp", "sgn"],
 | 
						||
        "psr": ["psr", "sgn"],
 | 
						||
        "pys": ["pys", "sgn"],
 | 
						||
        "rms": ["rms", "sgn"],
 | 
						||
        "rsi": ["rsi", "sgn"],
 | 
						||
        "rsl": ["rsl", "sgn"],
 | 
						||
        "sdl": ["sdl", "sgn"],
 | 
						||
        "sfb": ["sfb", "sgn"],
 | 
						||
        "sfs": ["sfs", "sgn"],
 | 
						||
        "sgg": ["sgg", "sgn"],
 | 
						||
        "sgx": ["sgx", "sgn"],
 | 
						||
        "shu": ["shu", "ar"],
 | 
						||
        "slf": ["slf", "sgn"],
 | 
						||
        "sls": ["sls", "sgn"],
 | 
						||
        "sqs": ["sqs", "sgn"],
 | 
						||
        "ssh": ["ssh", "ar"],
 | 
						||
        "ssp": ["ssp", "sgn"],
 | 
						||
        "ssr": ["ssr", "sgn"],
 | 
						||
        "svk": ["svk", "sgn"],
 | 
						||
        "swc": ["swc", "sw"],
 | 
						||
        "swh": ["swh", "sw"],
 | 
						||
        "swl": ["swl", "sgn"],
 | 
						||
        "syy": ["syy", "sgn"],
 | 
						||
        "tmw": ["tmw", "ms"],
 | 
						||
        "tse": ["tse", "sgn"],
 | 
						||
        "tsm": ["tsm", "sgn"],
 | 
						||
        "tsq": ["tsq", "sgn"],
 | 
						||
        "tss": ["tss", "sgn"],
 | 
						||
        "tsy": ["tsy", "sgn"],
 | 
						||
        "tza": ["tza", "sgn"],
 | 
						||
        "ugn": ["ugn", "sgn"],
 | 
						||
        "ugy": ["ugy", "sgn"],
 | 
						||
        "ukl": ["ukl", "sgn"],
 | 
						||
        "uks": ["uks", "sgn"],
 | 
						||
        "urk": ["urk", "ms"],
 | 
						||
        "uzn": ["uzn", "uz"],
 | 
						||
        "uzs": ["uzs", "uz"],
 | 
						||
        "vgt": ["vgt", "sgn"],
 | 
						||
        "vkk": ["vkk", "ms"],
 | 
						||
        "vkt": ["vkt", "ms"],
 | 
						||
        "vsi": ["vsi", "sgn"],
 | 
						||
        "vsl": ["vsl", "sgn"],
 | 
						||
        "vsv": ["vsv", "sgn"],
 | 
						||
        "wuu": ["wuu", "zh"],
 | 
						||
        "xki": ["xki", "sgn"],
 | 
						||
        "xml": ["xml", "sgn"],
 | 
						||
        "xmm": ["xmm", "ms"],
 | 
						||
        "xms": ["xms", "sgn"],
 | 
						||
        "yds": ["yds", "sgn"],
 | 
						||
        "ysl": ["ysl", "sgn"],
 | 
						||
        "yue": ["yue", "zh"],
 | 
						||
        "zib": ["zib", "sgn"],
 | 
						||
        "zlm": ["zlm", "ms"],
 | 
						||
        "zmi": ["zmi", "ms"],
 | 
						||
        "zsl": ["zsl", "sgn"],
 | 
						||
        "zsm": ["zsm", "ms"]
 | 
						||
    };
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags.
 | 
						||
     *
 | 
						||
     * Spec: ECMAScript Internationalization API Specification, draft, 6.2.3.
 | 
						||
     * Spec: RFC 5646, section 4.5.
 | 
						||
     */
 | 
						||
    function canonicalizeLanguageTag(locale) {
 | 
						||
 | 
						||
        // start with lower case for easier processing, and because most subtags will need to be lower case anyway
 | 
						||
        locale = locale.toLowerCase();
 | 
						||
 | 
						||
        // handle mappings for complete tags
 | 
						||
        if (__tagMappings.hasOwnProperty(locale)) {
 | 
						||
            return __tagMappings[locale];
 | 
						||
        }
 | 
						||
 | 
						||
        var subtags = locale.split("-");
 | 
						||
        var i = 0;
 | 
						||
 | 
						||
        // handle standard part: all subtags before first singleton or "x"
 | 
						||
        while (i < subtags.length) {
 | 
						||
            var subtag = subtags[i];
 | 
						||
            if (subtag.length === 1 && (i > 0 || subtag === "x")) {
 | 
						||
                break;
 | 
						||
            } else if (i !== 0 && subtag.length === 2) {
 | 
						||
                subtag = subtag.toUpperCase();
 | 
						||
            } else if (subtag.length === 4) {
 | 
						||
                subtag = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase();
 | 
						||
            }
 | 
						||
            if (__subtagMappings.hasOwnProperty(subtag)) {
 | 
						||
                subtag = __subtagMappings[subtag];
 | 
						||
            } else if (__extlangMappings.hasOwnProperty(subtag)) {
 | 
						||
                subtag = __extlangMappings[subtag][0];
 | 
						||
                if (i === 1 && __extlangMappings[subtag][1] === subtags[0]) {
 | 
						||
                    subtags.shift();
 | 
						||
                    i--;
 | 
						||
                }
 | 
						||
            }
 | 
						||
            subtags[i] = subtag;
 | 
						||
            i++;
 | 
						||
        }
 | 
						||
        var normal = subtags.slice(0, i).join("-");
 | 
						||
 | 
						||
        // handle extensions
 | 
						||
        var extensions = [];
 | 
						||
        while (i < subtags.length && subtags[i] !== "x") {
 | 
						||
            var extensionStart = i;
 | 
						||
            i++;
 | 
						||
            while (i < subtags.length && subtags[i].length > 1) {
 | 
						||
                i++;
 | 
						||
            }
 | 
						||
            var extension = subtags.slice(extensionStart, i).join("-");
 | 
						||
            extensions.push(extension);
 | 
						||
        }
 | 
						||
        extensions.sort();
 | 
						||
 | 
						||
        // handle private use
 | 
						||
        var privateUse;
 | 
						||
        if (i < subtags.length) {
 | 
						||
            privateUse = subtags.slice(i).join("-");
 | 
						||
        }
 | 
						||
 | 
						||
        // put everything back together
 | 
						||
        var canonical = normal;
 | 
						||
        if (extensions.length > 0) {
 | 
						||
            canonical += "-" + extensions.join("-");
 | 
						||
        }
 | 
						||
        if (privateUse !== undefined) {
 | 
						||
            if (canonical.length > 0) {
 | 
						||
                canonical += "-" + privateUse;
 | 
						||
            } else {
 | 
						||
                canonical = privateUse;
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        return canonical;
 | 
						||
    }
 | 
						||
 | 
						||
    return typeof locale === "string" && isStructurallyValidLanguageTag(locale) &&
 | 
						||
            canonicalizeLanguageTag(locale) === locale;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests whether the named options property is correctly handled by the given constructor.
 | 
						||
 * @param {object} Constructor the constructor to test.
 | 
						||
 * @param {string} property the name of the options property to test.
 | 
						||
 * @param {string} type the type that values of the property are expected to have
 | 
						||
 * @param {Array} [values] an array of allowed values for the property. Not needed for boolean.
 | 
						||
 * @param {any} fallback the fallback value that the property assumes if not provided.
 | 
						||
 * @param {object} testOptions additional options:
 | 
						||
 *     @param {boolean} isOptional whether support for this property is optional for implementations.
 | 
						||
 *     @param {boolean} noReturn whether the resulting value of the property is not returned.
 | 
						||
 *     @param {boolean} isILD whether the resulting value of the property is implementation and locale dependent.
 | 
						||
 *     @param {object} extra additional option to pass along, properties are value -> {option: value}.
 | 
						||
 * @return {boolean} whether the test succeeded.
 | 
						||
 */
 | 
						||
function testOption(Constructor, property, type, values, fallback, testOptions) {
 | 
						||
    var isOptional = testOptions !== undefined && testOptions.isOptional === true;
 | 
						||
    var noReturn = testOptions !== undefined && testOptions.noReturn === true;
 | 
						||
    var isILD = testOptions !== undefined && testOptions.isILD === true;
 | 
						||
    
 | 
						||
    function addExtraOptions(options, value, testOptions) {
 | 
						||
        if (testOptions !== undefined && testOptions.extra !== undefined) {
 | 
						||
            var extra;
 | 
						||
            if (value !== undefined && testOptions.extra[value] !== undefined) {
 | 
						||
                extra = testOptions.extra[value];
 | 
						||
            } else if (testOptions.extra.any !== undefined) {
 | 
						||
                extra = testOptions.extra.any;
 | 
						||
            }
 | 
						||
            if (extra !== undefined) {
 | 
						||
                Object.getOwnPropertyNames(extra).forEach(function (prop) {
 | 
						||
                    options[prop] = extra[prop];
 | 
						||
                });
 | 
						||
            }
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    var testValues, options, obj, expected, actual, error;
 | 
						||
 | 
						||
    // test that the specified values are accepted. Also add values that convert to specified values.
 | 
						||
    if (type === "boolean") {
 | 
						||
        if (values === undefined) {
 | 
						||
            values = [true, false];
 | 
						||
        }
 | 
						||
        testValues = values.slice(0);
 | 
						||
        testValues.push(888);
 | 
						||
        testValues.push(0);
 | 
						||
    } else if (type === "string") {
 | 
						||
        testValues = values.slice(0);
 | 
						||
        testValues.push({toString: function () { return values[0]; }});
 | 
						||
    }
 | 
						||
    testValues.forEach(function (value) {
 | 
						||
        options = {};
 | 
						||
        options[property] = value;
 | 
						||
        addExtraOptions(options, value, testOptions);
 | 
						||
        obj = new Constructor(undefined, options);
 | 
						||
        if (noReturn) {
 | 
						||
            if (obj.resolvedOptions().hasOwnProperty(property)) {
 | 
						||
                $ERROR("Option property " + property + " is returned, but shouldn't be.");
 | 
						||
            }
 | 
						||
        } else {
 | 
						||
            actual = obj.resolvedOptions()[property];
 | 
						||
            if (isILD) {
 | 
						||
                if (actual !== undefined && values.indexOf(actual) === -1) {
 | 
						||
                    $ERROR("Invalid value " + actual + " returned for property " + property + ".");
 | 
						||
                }
 | 
						||
            } else {
 | 
						||
                if (type === "boolean") {
 | 
						||
                    expected = Boolean(value);
 | 
						||
                } else if (type === "string") {
 | 
						||
                    expected = String(value);
 | 
						||
                }
 | 
						||
                if (actual !== expected && !(isOptional && actual === undefined)) {
 | 
						||
                    $ERROR("Option value " + value + " for property " + property +
 | 
						||
                        " was not accepted; got " + actual + " instead.");
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
    });
 | 
						||
 | 
						||
    // test that invalid values are rejected
 | 
						||
    if (type === "string") {
 | 
						||
        var invalidValues = ["invalidValue", -1, null];
 | 
						||
        // assume that we won't have values in caseless scripts
 | 
						||
        if (values[0].toUpperCase() !== values[0]) {
 | 
						||
            invalidValues.push(values[0].toUpperCase());
 | 
						||
        } else {
 | 
						||
            invalidValues.push(values[0].toLowerCase());
 | 
						||
        }
 | 
						||
        invalidValues.forEach(function (value) {
 | 
						||
            options = {};
 | 
						||
            options[property] = value;
 | 
						||
            addExtraOptions(options, value, testOptions);
 | 
						||
            error = undefined;
 | 
						||
            try {
 | 
						||
                obj = new Constructor(undefined, options);
 | 
						||
            } catch (e) {
 | 
						||
                error = e;
 | 
						||
            }
 | 
						||
            if (error === undefined) {
 | 
						||
                $ERROR("Invalid option value " + value + " for property " + property + " was not rejected.");
 | 
						||
            } else if (error.name !== "RangeError") {
 | 
						||
                $ERROR("Invalid option value " + value + " for property " + property + " was rejected with wrong error " + error.name + ".");
 | 
						||
            }
 | 
						||
        });
 | 
						||
    }
 | 
						||
 | 
						||
    // test that fallback value or another valid value is used if no options value is provided
 | 
						||
    if (!noReturn) {
 | 
						||
        options = {};
 | 
						||
        addExtraOptions(options, undefined, testOptions);
 | 
						||
        obj = new Constructor(undefined, options);
 | 
						||
        actual = obj.resolvedOptions()[property];
 | 
						||
        if (!(isOptional && actual === undefined)) {
 | 
						||
            if (fallback !== undefined) {
 | 
						||
                if (actual !== fallback) {
 | 
						||
                    $ERROR("Option fallback value " + fallback + " for property " + property +
 | 
						||
                        " was not used; got " + actual + " instead.");
 | 
						||
                }
 | 
						||
            } else {
 | 
						||
                if (values.indexOf(actual) === -1 && !(isILD && actual === undefined)) {
 | 
						||
                    $ERROR("Invalid value " + actual + " returned for property " + property + ".");
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    return true;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests whether the named property of the given object has a valid value
 | 
						||
 * and the default attributes of the properties of an object literal.
 | 
						||
 * @param {Object} obj the object to be tested.
 | 
						||
 * @param {string} property the name of the property
 | 
						||
 * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
 | 
						||
 *     an array of valid values.
 | 
						||
 * @exception if the property has an invalid value.
 | 
						||
 */
 | 
						||
function testProperty(obj, property, valid) {
 | 
						||
    var desc = Object.getOwnPropertyDescriptor(obj, property);
 | 
						||
    if (!desc.writable) {
 | 
						||
        $ERROR("Property " + property + " must be writable.");
 | 
						||
    }
 | 
						||
    if (!desc.enumerable) {
 | 
						||
        $ERROR("Property " + property + " must be enumerable.");
 | 
						||
    }
 | 
						||
    if (!desc.configurable) {
 | 
						||
        $ERROR("Property " + property + " must be configurable.");
 | 
						||
    }
 | 
						||
    var value = desc.value;
 | 
						||
    var isValid = (typeof valid === "function") ? valid(value) : (valid.indexOf(value) !== -1);
 | 
						||
    if (!isValid) {
 | 
						||
        $ERROR("Property value " + value + " is not allowed for property " + property + ".");
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests whether the named property of the given object, if present at all, has a valid value
 | 
						||
 * and the default attributes of the properties of an object literal.
 | 
						||
 * @param {Object} obj the object to be tested.
 | 
						||
 * @param {string} property the name of the property
 | 
						||
 * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
 | 
						||
 *     an array of valid values.
 | 
						||
 * @exception if the property is present and has an invalid value.
 | 
						||
 */
 | 
						||
function mayHaveProperty(obj, property, valid) {
 | 
						||
    if (obj.hasOwnProperty(property)) {
 | 
						||
        testProperty(obj, property, valid);
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests whether the given object has the named property with a valid value
 | 
						||
 * and the default attributes of the properties of an object literal.
 | 
						||
 * @param {Object} obj the object to be tested.
 | 
						||
 * @param {string} property the name of the property
 | 
						||
 * @param {Function|Array} valid either a function that tests value for validity and returns a boolean,
 | 
						||
 *     an array of valid values.
 | 
						||
 * @exception if the property is missing or has an invalid value.
 | 
						||
 */
 | 
						||
function mustHaveProperty(obj, property, valid) {
 | 
						||
    if (!obj.hasOwnProperty(property)) {
 | 
						||
        $ERROR("Object is missing property " + property + ".");
 | 
						||
    }
 | 
						||
    testProperty(obj, property, valid);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests whether the given object does not have the named property.
 | 
						||
 * @param {Object} obj the object to be tested.
 | 
						||
 * @param {string} property the name of the property
 | 
						||
 * @exception if the property is present.
 | 
						||
 */
 | 
						||
function mustNotHaveProperty(obj, property) {
 | 
						||
    if (obj.hasOwnProperty(property)) {
 | 
						||
        $ERROR("Object has property it mustn't have: " + property + ".");
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Properties of the RegExp constructor that may be affected by use of regular
 | 
						||
 * expressions, and the default values of these properties. Properties are from
 | 
						||
 * https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Deprecated_and_obsolete_features#RegExp_Properties
 | 
						||
 */
 | 
						||
var regExpProperties = ["$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
 | 
						||
    "$_", "$*", "$&", "$+", "$`", "$'",
 | 
						||
    "input", "lastMatch", "lastParen", "leftContext", "rightContext"
 | 
						||
];
 | 
						||
 | 
						||
var regExpPropertiesDefaultValues = (function () {
 | 
						||
    var values = Object.create(null);
 | 
						||
    regExpProperties.forEach(function (property) {
 | 
						||
        values[property] = RegExp[property];
 | 
						||
    });
 | 
						||
    return values;
 | 
						||
}());
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests that executing the provided function (which may use regular expressions
 | 
						||
 * in its implementation) does not create or modify unwanted properties on the
 | 
						||
 * RegExp constructor.
 | 
						||
 */
 | 
						||
function testForUnwantedRegExpChanges(testFunc) {
 | 
						||
    regExpProperties.forEach(function (property) {
 | 
						||
        RegExp[property] = regExpPropertiesDefaultValues[property];
 | 
						||
    });
 | 
						||
    testFunc();
 | 
						||
    regExpProperties.forEach(function (property) {
 | 
						||
        if (RegExp[property] !== regExpPropertiesDefaultValues[property]) {
 | 
						||
            $ERROR("RegExp has unexpected property " + property + " with value " +
 | 
						||
                RegExp[property] + ".");
 | 
						||
        }
 | 
						||
    });
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests whether name is a valid BCP 47 numbering system name
 | 
						||
 * and not excluded from use in the ECMAScript Internationalization API.
 | 
						||
 * @param {string} name the name to be tested.
 | 
						||
 * @return {boolean} whether name is a valid BCP 47 numbering system name and
 | 
						||
 *     allowed for use in the ECMAScript Internationalization API.
 | 
						||
 */
 | 
						||
 | 
						||
function isValidNumberingSystem(name) {
 | 
						||
    
 | 
						||
    // source: CLDR file common/bcp47/number.xml; version CLDR 21.
 | 
						||
    var numberingSystems = [
 | 
						||
        "arab",
 | 
						||
        "arabext",
 | 
						||
        "armn",
 | 
						||
        "armnlow",
 | 
						||
        "bali",
 | 
						||
        "beng",
 | 
						||
        "brah",
 | 
						||
        "cakm",
 | 
						||
        "cham",
 | 
						||
        "deva",
 | 
						||
        "ethi",
 | 
						||
        "finance",
 | 
						||
        "fullwide",
 | 
						||
        "geor",
 | 
						||
        "grek",
 | 
						||
        "greklow",
 | 
						||
        "gujr",
 | 
						||
        "guru",
 | 
						||
        "hanidec",
 | 
						||
        "hans",
 | 
						||
        "hansfin",
 | 
						||
        "hant",
 | 
						||
        "hantfin",
 | 
						||
        "hebr",
 | 
						||
        "java",
 | 
						||
        "jpan",
 | 
						||
        "jpanfin",
 | 
						||
        "kali",
 | 
						||
        "khmr",
 | 
						||
        "knda",
 | 
						||
        "osma",            
 | 
						||
        "lana",
 | 
						||
        "lanatham",
 | 
						||
        "laoo",
 | 
						||
        "latn",
 | 
						||
        "lepc",
 | 
						||
        "limb",
 | 
						||
        "mlym",
 | 
						||
        "mong",
 | 
						||
        "mtei",
 | 
						||
        "mymr",
 | 
						||
        "mymrshan",
 | 
						||
        "native",
 | 
						||
        "nkoo",
 | 
						||
        "olck",
 | 
						||
        "orya",
 | 
						||
        "roman",
 | 
						||
        "romanlow",
 | 
						||
        "saur",
 | 
						||
        "shrd",
 | 
						||
        "sora",
 | 
						||
        "sund",
 | 
						||
        "talu",
 | 
						||
        "takr",
 | 
						||
        "taml",
 | 
						||
        "tamldec",
 | 
						||
        "telu",
 | 
						||
        "thai",
 | 
						||
        "tibt",
 | 
						||
        "traditio",
 | 
						||
        "vaii"
 | 
						||
    ];
 | 
						||
    
 | 
						||
    var excluded = [
 | 
						||
        "finance",
 | 
						||
        "native",
 | 
						||
        "traditio"
 | 
						||
    ];
 | 
						||
        
 | 
						||
    
 | 
						||
    return numberingSystems.indexOf(name) !== -1 && excluded.indexOf(name) === -1;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Provides the digits of numbering systems with simple digit mappings,
 | 
						||
 * as specified in 11.3.2.
 | 
						||
 */
 | 
						||
 | 
						||
var numberingSystemDigits = {
 | 
						||
    arab: "٠١٢٣٤٥٦٧٨٩",
 | 
						||
    arabext: "۰۱۲۳۴۵۶۷۸۹",
 | 
						||
    beng: "০১২৩৪৫৬৭৮৯",
 | 
						||
    deva: "०१२३४५६७८९",
 | 
						||
    fullwide: "0123456789",
 | 
						||
    gujr: "૦૧૨૩૪૫૬૭૮૯",
 | 
						||
    guru: "੦੧੨੩੪੫੬੭੮੯",
 | 
						||
    hanidec: "〇一二三四五六七八九",
 | 
						||
    khmr: "០១២៣៤៥៦៧៨៩",
 | 
						||
    knda: "೦೧೨೩೪೫೬೭೮೯",
 | 
						||
    laoo: "໐໑໒໓໔໕໖໗໘໙",
 | 
						||
    latn: "0123456789",
 | 
						||
    mlym: "൦൧൨൩൪൫൬൭൮൯",
 | 
						||
    mong: "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙",
 | 
						||
    mymr: "၀၁၂၃၄၅၆၇၈၉",
 | 
						||
    orya: "୦୧୨୩୪୫୬୭୮୯",
 | 
						||
    tamldec: "௦௧௨௩௪௫௬௭௮௯",
 | 
						||
    telu: "౦౧౨౩౪౫౬౭౮౯",
 | 
						||
    thai: "๐๑๒๓๔๕๖๗๘๙",
 | 
						||
    tibt: "༠༡༢༣༤༥༦༧༨༩"
 | 
						||
};
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests that number formatting is handled correctly. The function checks that the
 | 
						||
 * digit sequences in formatted output are as specified, converted to the
 | 
						||
 * selected numbering system, and embedded in consistent localized patterns.
 | 
						||
 * @param {Array} locales the locales to be tested.
 | 
						||
 * @param {Array} numberingSystems the numbering systems to be tested.
 | 
						||
 * @param {Object} options the options to pass to Intl.NumberFormat. Options
 | 
						||
 *     must include {useGrouping: false}, and must cause 1.1 to be formatted
 | 
						||
 *     pre- and post-decimal digits.
 | 
						||
 * @param {Object} testData maps input data (in ES5 9.3.1 format) to expected output strings
 | 
						||
 *     in unlocalized format with Western digits.
 | 
						||
 */
 | 
						||
 | 
						||
function testNumberFormat(locales, numberingSystems, options, testData) {
 | 
						||
    locales.forEach(function (locale) {
 | 
						||
        numberingSystems.forEach(function (numbering) {
 | 
						||
            var digits = numberingSystemDigits[numbering];
 | 
						||
            var format = new Intl.NumberFormat([locale + "-u-nu-" + numbering], options);
 | 
						||
    
 | 
						||
            function getPatternParts(positive) {
 | 
						||
                var n = positive ? 1.1 : -1.1;
 | 
						||
                var formatted = format.format(n);
 | 
						||
                var oneoneRE = "([^" + digits + "]*)[" + digits + "]+([^" + digits + "]+)[" + digits + "]+([^" + digits + "]*)";
 | 
						||
                var match = formatted.match(new RegExp(oneoneRE));
 | 
						||
                if (match === null) {
 | 
						||
                    $ERROR("Unexpected formatted " + n + " for " +
 | 
						||
                        format.resolvedOptions().locale + " and options " +
 | 
						||
                        JSON.stringify(options) + ": " + formatted);
 | 
						||
                }
 | 
						||
                return match;
 | 
						||
            }
 | 
						||
            
 | 
						||
            function toNumbering(raw) {
 | 
						||
                return raw.replace(/[0-9]/g, function (digit) {
 | 
						||
                    return digits[digit.charCodeAt(0) - "0".charCodeAt(0)];
 | 
						||
                });
 | 
						||
            }
 | 
						||
            
 | 
						||
            function buildExpected(raw, patternParts) {
 | 
						||
                var period = raw.indexOf(".");
 | 
						||
                if (period === -1) {
 | 
						||
                    return patternParts[1] + toNumbering(raw) + patternParts[3];
 | 
						||
                } else {
 | 
						||
                    return patternParts[1] + 
 | 
						||
                        toNumbering(raw.substring(0, period)) +
 | 
						||
                        patternParts[2] +
 | 
						||
                        toNumbering(raw.substring(period + 1)) +
 | 
						||
                        patternParts[3];
 | 
						||
                }
 | 
						||
            }
 | 
						||
            
 | 
						||
            if (format.resolvedOptions().numberingSystem === numbering) {
 | 
						||
                // figure out prefixes, infixes, suffixes for positive and negative values
 | 
						||
                var posPatternParts = getPatternParts(true);
 | 
						||
                var negPatternParts = getPatternParts(false);
 | 
						||
                
 | 
						||
                Object.getOwnPropertyNames(testData).forEach(function (input) {
 | 
						||
                    var rawExpected = testData[input];
 | 
						||
                    var patternParts;
 | 
						||
                    if (rawExpected[0] === "-") {
 | 
						||
                        patternParts = negPatternParts;
 | 
						||
                        rawExpected = rawExpected.substring(1);
 | 
						||
                    } else {
 | 
						||
                        patternParts = posPatternParts;
 | 
						||
                    }
 | 
						||
                    var expected = buildExpected(rawExpected, patternParts);
 | 
						||
                    var actual = format.format(input);
 | 
						||
                    if (actual !== expected) {
 | 
						||
                        $ERROR("Formatted value for " + input + ", " +
 | 
						||
                        format.resolvedOptions().locale + " and options " +
 | 
						||
                        JSON.stringify(options) + " is " + actual + "; expected " + expected + ".");
 | 
						||
                    }
 | 
						||
                });
 | 
						||
            }
 | 
						||
        });
 | 
						||
    });
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Return the components of date-time formats.
 | 
						||
 * @return {Array} an array with all date-time components.
 | 
						||
 */
 | 
						||
 | 
						||
function getDateTimeComponents() {
 | 
						||
    return ["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"];
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Return the valid values for the given date-time component, as specified
 | 
						||
 * by the table in section 12.1.1.
 | 
						||
 * @param {string} component a date-time component.
 | 
						||
 * @return {Array} an array with the valid values for the component.
 | 
						||
 */
 | 
						||
 | 
						||
function getDateTimeComponentValues(component) {
 | 
						||
    
 | 
						||
    var components = {
 | 
						||
        weekday: ["narrow", "short", "long"],
 | 
						||
        era: ["narrow", "short", "long"],
 | 
						||
        year: ["2-digit", "numeric"],
 | 
						||
        month: ["2-digit", "numeric", "narrow", "short", "long"],
 | 
						||
        day: ["2-digit", "numeric"],
 | 
						||
        hour: ["2-digit", "numeric"],
 | 
						||
        minute: ["2-digit", "numeric"],
 | 
						||
        second: ["2-digit", "numeric"],
 | 
						||
        timeZoneName: ["short", "long"]
 | 
						||
    };
 | 
						||
    
 | 
						||
    var result = components[component];
 | 
						||
    if (result === undefined) {
 | 
						||
        $ERROR("Internal error: No values defined for date-time component " + component + ".");
 | 
						||
    }
 | 
						||
    return result;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Tests that the given value is valid for the given date-time component.
 | 
						||
 * @param {string} component a date-time component.
 | 
						||
 * @param {string} value the value to be tested.
 | 
						||
 * @return {boolean} true if the test succeeds.
 | 
						||
 * @exception if the test fails.
 | 
						||
 */
 | 
						||
 | 
						||
function testValidDateTimeComponentValue(component, value) {
 | 
						||
    if (getDateTimeComponentValues(component).indexOf(value) === -1) {
 | 
						||
        $ERROR("Invalid value " + value + " for date-time component " + component + ".");
 | 
						||
    }
 | 
						||
    return true;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 * Verifies that the actual array matches the expected one in length, elements,
 | 
						||
 * and element order.
 | 
						||
 * @param {Array} expected the expected array.
 | 
						||
 * @param {Array} actual the actual array.
 | 
						||
 * @return {boolean} true if the test succeeds.
 | 
						||
 * @exception if the test fails.
 | 
						||
 */
 | 
						||
function testArraysAreSame(expected, actual) {
 | 
						||
    for (i = 0; i < Math.max(actual.length, expected.length); i++) {
 | 
						||
        if (actual[i] !== expected[i]) {
 | 
						||
            $ERROR("Result array element at index " + i + " should be \"" +
 | 
						||
                expected[i] + "\" but is \"" + actual[i] + "\".");
 | 
						||
        }
 | 
						||
    }
 | 
						||
    return true;
 | 
						||
}
 | 
						||
 |