From 1b5e2b5129fac0b2225065251587e9b37cb12694 Mon Sep 17 00:00:00 2001 From: Marc Laval Date: Thu, 1 Sep 2016 00:55:13 +0200 Subject: [PATCH] test: add Intl polyfill and run Intl tests in all browsers (#10471) --- .../common/test/pipes/date_pipe_spec.ts | 140 +++++++++++------- .../common/test/pipes/number_pipe_spec.ts | 109 +++++++------- .../test/browser_util_spec.ts | 49 ++++-- .../platform-browser/testing/browser_util.ts | 18 ++- shims_for_IE.js | 9 ++ 5 files changed, 196 insertions(+), 129 deletions(-) diff --git a/modules/@angular/common/test/pipes/date_pipe_spec.ts b/modules/@angular/common/test/pipes/date_pipe_spec.ts index 09e359641b..25e58c8beb 100644 --- a/modules/@angular/common/test/pipes/date_pipe_spec.ts +++ b/modules/@angular/common/test/pipes/date_pipe_spec.ts @@ -18,6 +18,14 @@ export function main() { var date: Date; var pipe: DatePipe; + // TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs + // In some old versions of Chrome in Android emulators, time formatting returns dates in the + // timezone of the VM host, + // instead of the device timezone. Same symptoms as + // https://bugs.chromium.org/p/chromium/issues/detail?id=406382 + // This happens locally and in SauceLabs, so some checks are disabled to avoid failures. + // Tracking issue: https://github.com/angular/angular/issues/11187 + beforeEach(() => { date = DateWrapper.create(2015, 6, 15, 9, 3, 1); pipe = new DatePipe('en-US'); @@ -26,81 +34,99 @@ export function main() { it('should be marked as pure', () => { expect(new PipeResolver().resolve(DatePipe).pure).toEqual(true); }); - // TODO(mlaval): enable tests when Intl API is no longer used, see - // https://github.com/angular/angular/issues/3333 - // Have to restrict to Chrome as IE uses a different formatting - if (browserDetection.supportsIntlApi && browserDetection.isChromeDesktop) { - describe('supports', () => { - it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); }); - it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); }); - it('should support numeric strings', - () => { expect(() => pipe.transform('123456789')).not.toThrow(); }); + describe('supports', () => { + it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); }); + it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); }); + it('should support numeric strings', + () => { expect(() => pipe.transform('123456789')).not.toThrow(); }); - it('should support decimal strings', - () => { expect(() => pipe.transform('123456789.11')).not.toThrow(); }); + it('should support decimal strings', + () => { expect(() => pipe.transform('123456789.11')).not.toThrow(); }); - it('should support ISO string', - () => { expect(() => pipe.transform('2015-06-15T21:43:11Z')).not.toThrow(); }); + it('should support ISO string', + () => { expect(() => pipe.transform('2015-06-15T21:43:11Z')).not.toThrow(); }); - it('should not support other objects', () => { - expect(() => pipe.transform({})).toThrow(); - expect(() => pipe.transform('')).toThrow(); - }); + it('should not support other objects', () => { + expect(() => pipe.transform({})).toThrow(); + expect(() => pipe.transform('')).toThrow(); }); + }); - describe('transform', () => { - it('should format each component correctly', () => { - expect(pipe.transform(date, 'y')).toEqual('2015'); - expect(pipe.transform(date, 'yy')).toEqual('15'); - expect(pipe.transform(date, 'M')).toEqual('6'); - expect(pipe.transform(date, 'MM')).toEqual('06'); - expect(pipe.transform(date, 'MMM')).toEqual('Jun'); - expect(pipe.transform(date, 'MMMM')).toEqual('June'); - expect(pipe.transform(date, 'd')).toEqual('15'); - expect(pipe.transform(date, 'E')).toEqual('Mon'); - expect(pipe.transform(date, 'EEEE')).toEqual('Monday'); + describe('transform', () => { + it('should format each component correctly', () => { + expect(pipe.transform(date, 'y')).toEqual('2015'); + expect(pipe.transform(date, 'yy')).toEqual('15'); + expect(pipe.transform(date, 'M')).toEqual('6'); + expect(pipe.transform(date, 'MM')).toEqual('06'); + expect(pipe.transform(date, 'MMM')).toEqual('Jun'); + expect(pipe.transform(date, 'MMMM')).toEqual('June'); + expect(pipe.transform(date, 'd')).toEqual('15'); + expect(pipe.transform(date, 'E')).toEqual('Mon'); + expect(pipe.transform(date, 'EEEE')).toEqual('Monday'); + if (!browserDetection.isOldChrome) { expect(pipe.transform(date, 'h')).toEqual('9'); expect(pipe.transform(date, 'hh')).toEqual('09'); - expect(pipe.transform(date, 'HH')).toEqual('09'); expect(pipe.transform(date, 'j')).toEqual('9 AM'); + } + // IE and Edge can't format a date to minutes and seconds without hours + if (!browserDetection.isEdge && !browserDetection.isIE || + !browserDetection.supportsNativeIntlApi) { + if (!browserDetection.isOldChrome) { + expect(pipe.transform(date, 'HH')).toEqual('09'); + } expect(pipe.transform(date, 'm')).toEqual('3'); expect(pipe.transform(date, 's')).toEqual('1'); expect(pipe.transform(date, 'mm')).toEqual('03'); expect(pipe.transform(date, 'ss')).toEqual('01'); - expect(pipe.transform(date, 'Z')).toBeDefined(); - }); - - it('should format common multi component patterns', () => { - expect(pipe.transform(date, 'E, M/d/y')).toEqual('Mon, 6/15/2015'); - expect(pipe.transform(date, 'E, M/d')).toEqual('Mon, 6/15'); - expect(pipe.transform(date, 'MMM d')).toEqual('Jun 15'); - expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015'); - expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015'); - expect(pipe.transform(date, 'yMEd')).toEqual('20156Mon15'); - expect(pipe.transform(date, 'MEd')).toEqual('6Mon15'); - expect(pipe.transform(date, 'MMMd')).toEqual('Jun15'); - expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015'); + } + expect(pipe.transform(date, 'Z')).toBeDefined(); + }); + it('should format common multi component patterns', () => { + expect(pipe.transform(date, 'E, M/d/y')).toEqual('Mon, 6/15/2015'); + expect(pipe.transform(date, 'E, M/d')).toEqual('Mon, 6/15'); + expect(pipe.transform(date, 'MMM d')).toEqual('Jun 15'); + expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015'); + expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015'); + expect(pipe.transform(date, 'yMEd')).toEqual('20156Mon15'); + expect(pipe.transform(date, 'MEd')).toEqual('6Mon15'); + expect(pipe.transform(date, 'MMMd')).toEqual('Jun15'); + expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015'); + // IE and Edge can't format a date to minutes and seconds without hours + if (!browserDetection.isEdge && !browserDetection.isIE || + !browserDetection.supportsNativeIntlApi) { expect(pipe.transform(date, 'ms')).toEqual('31'); + } + if (!browserDetection.isOldChrome) { expect(pipe.transform(date, 'jm')).toEqual('9:03 AM'); - }); + } + }); - it('should format with pattern aliases', () => { - expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015, 9:03:01 AM'); - expect(pipe.transform(date, 'short')).toEqual('6/15/2015, 9:03 AM'); - expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015'); - expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015'); - expect(pipe.transform(date, 'fullDate')).toEqual('Monday, June 15, 2015'); - expect(pipe.transform(date, 'longDate')).toEqual('June 15, 2015'); - expect(pipe.transform(date, 'mediumDate')).toEqual('Jun 15, 2015'); - expect(pipe.transform(date, 'shortDate')).toEqual('6/15/2015'); + it('should format with pattern aliases', () => { + if (!browserDetection.isOldChrome) { + // IE and Edge do not add a coma after the year in these 2 cases + if ((browserDetection.isEdge || browserDetection.isIE) && + browserDetection.supportsNativeIntlApi) { + expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015 9:03:01 AM'); + expect(pipe.transform(date, 'short')).toEqual('6/15/2015 9:03 AM'); + } else { + expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015, 9:03:01 AM'); + expect(pipe.transform(date, 'short')).toEqual('6/15/2015, 9:03 AM'); + } + } + expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015'); + expect(pipe.transform(date, 'fullDate')).toEqual('Monday, June 15, 2015'); + expect(pipe.transform(date, 'longDate')).toEqual('June 15, 2015'); + expect(pipe.transform(date, 'mediumDate')).toEqual('Jun 15, 2015'); + expect(pipe.transform(date, 'shortDate')).toEqual('6/15/2015'); + if (!browserDetection.isOldChrome) { expect(pipe.transform(date, 'mediumTime')).toEqual('9:03:01 AM'); expect(pipe.transform(date, 'shortTime')).toEqual('9:03 AM'); - }); - - it('should remove bidi control characters', - () => { expect(pipe.transform(date, 'MM/dd/yyyy').length).toEqual(10); }); + } }); - } + + it('should remove bidi control characters', + () => { expect(pipe.transform(date, 'MM/dd/yyyy').length).toEqual(10); }); + }); }); } diff --git a/modules/@angular/common/test/pipes/number_pipe_spec.ts b/modules/@angular/common/test/pipes/number_pipe_spec.ts index b52812f057..e19a9e8786 100644 --- a/modules/@angular/common/test/pipes/number_pipe_spec.ts +++ b/modules/@angular/common/test/pipes/number_pipe_spec.ts @@ -12,73 +12,78 @@ import {browserDetection} from '@angular/platform-browser/testing/browser_util'; export function main() { describe('Number pipes', () => { - // TODO(mlaval): enable tests when Intl API is no longer used, see - // https://github.com/angular/angular/issues/3333 - // Have to restrict to Chrome as IE uses a different formatting - if (browserDetection.supportsIntlApi && browserDetection.isChromeDesktop) { - describe('DecimalPipe', () => { - var pipe: DecimalPipe; + describe('DecimalPipe', () => { + var pipe: DecimalPipe; - beforeEach(() => { pipe = new DecimalPipe('en-US'); }); + beforeEach(() => { pipe = new DecimalPipe('en-US'); }); - describe('transform', () => { - it('should return correct value for numbers', () => { - expect(pipe.transform(12345)).toEqual('12,345'); - expect(pipe.transform(123, '.2')).toEqual('123.00'); - expect(pipe.transform(1, '3.')).toEqual('001'); - expect(pipe.transform(1.1, '3.4-5')).toEqual('001.1000'); - expect(pipe.transform(1.123456, '3.4-5')).toEqual('001.12346'); - expect(pipe.transform(1.1234)).toEqual('1.123'); - }); + describe('transform', () => { + it('should return correct value for numbers', () => { + expect(pipe.transform(12345)).toEqual('12,345'); + expect(pipe.transform(123, '.2')).toEqual('123.00'); + expect(pipe.transform(1, '3.')).toEqual('001'); + expect(pipe.transform(1.1, '3.4-5')).toEqual('001.1000'); + expect(pipe.transform(1.123456, '3.4-5')).toEqual('001.12346'); + expect(pipe.transform(1.1234)).toEqual('1.123'); + }); - it('should support strings', () => { - expect(pipe.transform('12345')).toEqual('12,345'); - expect(pipe.transform('123', '.2')).toEqual('123.00'); - expect(pipe.transform('1', '3.')).toEqual('001'); - expect(pipe.transform('1.1', '3.4-5')).toEqual('001.1000'); - expect(pipe.transform('1.123456', '3.4-5')).toEqual('001.12346'); - expect(pipe.transform('1.1234')).toEqual('1.123'); - }); + it('should support strings', () => { + expect(pipe.transform('12345')).toEqual('12,345'); + expect(pipe.transform('123', '.2')).toEqual('123.00'); + expect(pipe.transform('1', '3.')).toEqual('001'); + expect(pipe.transform('1.1', '3.4-5')).toEqual('001.1000'); + expect(pipe.transform('1.123456', '3.4-5')).toEqual('001.12346'); + expect(pipe.transform('1.1234')).toEqual('1.123'); + }); - it('should not support other objects', () => { - expect(() => pipe.transform(new Object())).toThrowError(); - expect(() => pipe.transform('123abc')).toThrowError(); - }); + it('should not support other objects', () => { + expect(() => pipe.transform(new Object())).toThrowError(); + expect(() => pipe.transform('123abc')).toThrowError(); }); }); + }); - describe('PercentPipe', () => { - var pipe: PercentPipe; + describe('PercentPipe', () => { + var pipe: PercentPipe; - beforeEach(() => { pipe = new PercentPipe('en-US'); }); + beforeEach(() => { pipe = new PercentPipe('en-US'); }); - describe('transform', () => { - it('should return correct value for numbers', () => { - expect(pipe.transform(1.23)).toEqual('123%'); - expect(pipe.transform(1.2, '.2')).toEqual('120.00%'); - }); - - it('should not support other objects', - () => { expect(() => pipe.transform(new Object())).toThrowError(); }); + describe('transform', () => { + it('should return correct value for numbers', () => { + expect(normalize(pipe.transform(1.23))).toEqual('123%'); + expect(normalize(pipe.transform(1.2, '.2'))).toEqual('120.00%'); }); + + it('should not support other objects', + () => { expect(() => pipe.transform(new Object())).toThrowError(); }); }); + }); - describe('CurrencyPipe', () => { - var pipe: CurrencyPipe; + describe('CurrencyPipe', () => { + var pipe: CurrencyPipe; - beforeEach(() => { pipe = new CurrencyPipe('en-US'); }); + beforeEach(() => { pipe = new CurrencyPipe('en-US'); }); - describe('transform', () => { - it('should return correct value for numbers', () => { - expect(pipe.transform(123)).toEqual('USD123.00'); - expect(pipe.transform(12, 'EUR', false, '.1')).toEqual('EUR12.0'); - expect(pipe.transform(5.1234, 'USD', false, '.0-3')).toEqual('USD5.123'); - }); - - it('should not support other objects', - () => { expect(() => pipe.transform(new Object())).toThrowError(); }); + describe('transform', () => { + it('should return correct value for numbers', () => { + // In old Chrome, default formatiing for USD is different + if (browserDetection.isOldChrome) { + expect(normalize(pipe.transform(123))).toEqual('USD123'); + } else { + expect(normalize(pipe.transform(123))).toEqual('USD123.00'); + } + expect(normalize(pipe.transform(12, 'EUR', false, '.1'))).toEqual('EUR12.0'); + expect(normalize(pipe.transform(5.1234, 'USD', false, '.0-3'))).toEqual('USD5.123'); }); + + it('should not support other objects', + () => { expect(() => pipe.transform(new Object())).toThrowError(); }); }); - } + }); }); } + +// Between the symbol and the number, Edge adds a no breaking space and IE11 adds a standard space +function normalize(s: string): string { + return s.replace(/\u00A0| /g, ''); +} diff --git a/modules/@angular/platform-browser/test/browser_util_spec.ts b/modules/@angular/platform-browser/test/browser_util_spec.ts index f175326b8b..893b6ffd35 100644 --- a/modules/@angular/platform-browser/test/browser_util_spec.ts +++ b/modules/@angular/platform-browser/test/browser_util_spec.ts @@ -23,7 +23,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: false, - isChromeDesktop: true + isChromeDesktop: true, + isOldChrome: false }, { name: 'Chrome mobile', @@ -35,7 +36,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: false, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'Firefox', @@ -47,7 +49,8 @@ export function main() { isWebkit: false, isIOS7: false, isSlow: false, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'IE9', @@ -59,7 +62,8 @@ export function main() { isWebkit: false, isIOS7: false, isSlow: true, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'IE10', @@ -71,7 +75,8 @@ export function main() { isWebkit: false, isIOS7: false, isSlow: true, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'IE11', @@ -83,7 +88,8 @@ export function main() { isWebkit: false, isIOS7: false, isSlow: true, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'IEMobile', @@ -95,7 +101,8 @@ export function main() { isWebkit: false, isIOS7: false, isSlow: true, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'Edge', @@ -107,7 +114,8 @@ export function main() { isWebkit: false, isIOS7: false, isSlow: false, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'Android4.1', @@ -119,7 +127,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: true, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'Android4.2', @@ -131,7 +140,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: true, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'Android4.3', @@ -143,7 +153,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: true, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'Android4.4', @@ -155,7 +166,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: false, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: true }, { name: 'Safari7', @@ -167,7 +179,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: false, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'Safari8', @@ -179,7 +192,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: false, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'iOS7', @@ -191,7 +205,8 @@ export function main() { isWebkit: true, isIOS7: true, isSlow: true, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false }, { name: 'iOS8', @@ -203,7 +218,8 @@ export function main() { isWebkit: true, isIOS7: false, isSlow: false, - isChromeDesktop: false + isChromeDesktop: false, + isOldChrome: false } ]; @@ -218,6 +234,7 @@ export function main() { expect(bd.isIOS7).toBe(StringMapWrapper.get(browser, 'isIOS7')); expect(bd.isSlow).toBe(StringMapWrapper.get(browser, 'isSlow')); expect(bd.isChromeDesktop).toBe(StringMapWrapper.get(browser, 'isChromeDesktop')); + expect(bd.isOldChrome).toBe(StringMapWrapper.get(browser, 'isOldChrome')); }); }); }); diff --git a/modules/@angular/platform-browser/testing/browser_util.ts b/modules/@angular/platform-browser/testing/browser_util.ts index 982ade42da..04651f5aff 100644 --- a/modules/@angular/platform-browser/testing/browser_util.ts +++ b/modules/@angular/platform-browser/testing/browser_util.ts @@ -50,15 +50,25 @@ export class BrowserDetection { get isSlow(): boolean { return this.isAndroid || this.isIE || this.isIOS7; } - // The Intl API is only properly supported in recent Chrome and Opera. - // Note: Edge is disguised as Chrome 42, so checking the "Edge" part is needed, - // see https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx - get supportsIntlApi(): boolean { return !!(global).Intl; } + // The Intl API is only natively supported in Chrome, Firefox, IE11 and Edge. + // This detector is needed in tests to make the difference between: + // 1) IE11/Edge: they have a native Intl API, but with some discrepancies + // 2) IE9/IE10: they use the polyfill, and so no discrepancies + get supportsNativeIntlApi(): boolean { + return !!(global).Intl && (global).Intl !== (global).IntlPolyfill; + } get isChromeDesktop(): boolean { return this._ua.indexOf('Chrome') > -1 && this._ua.indexOf('Mobile Safari') == -1 && this._ua.indexOf('Edge') == -1; } + + // "Old Chrome" means Chrome 3X, where there are some discrepancies in the Intl API. + // Android 4.4 and 5.X have such browsers by default (respectively 30 and 39). + get isOldChrome(): boolean { + return this._ua.indexOf('Chrome') > -1 && this._ua.indexOf('Chrome/3') > -1 && + this._ua.indexOf('Edge') == -1; + } } BrowserDetection.setup(); diff --git a/shims_for_IE.js b/shims_for_IE.js index bad56593de..d3bb40baf4 100644 --- a/shims_for_IE.js +++ b/shims_for_IE.js @@ -1,3 +1,5 @@ +// This file is used for internal testing with Karma only, it should not be used in real applications. + // function.name (all IE) /*! @source http://stackoverflow.com/questions/6903762/function-name-not-supported-in-ie*/ if (!Object.hasOwnProperty('name')) { @@ -1404,3 +1406,10 @@ if (!window.console.assert) window.console.assert = function () { }; } w.FormData = FormData; })(window); + +// Intl (IE9, IE10, all Safari, all Android) +/*! @source https://github.com/andyearnshaw/Intl.js */ +/*! @licence https://github.com/andyearnshaw/Intl.js/blob/master/LICENSE.txt */ +!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):e.IntlPolyfill=r()}(this,function(){"use strict";function e(e){if("function"==typeof Math.log10)return Math.floor(Math.log10(e));var r=Math.round(Math.log(e)*Math.LOG10E);return r-(Number("1e"+r)>e)}function r(e){for(var t in e)(e instanceof r||ee.call(e,t))&&re(this,t,{value:e[t],enumerable:!0,writable:!0,configurable:!0})}function t(){re(this,"length",{writable:!0,value:0}),arguments.length&&oe.apply(this,ae.call(arguments))}function n(){if(ue.disableRegExpRestore)return function(){};for(var e={lastMatch:RegExp.lastMatch||"",leftContext:RegExp.leftContext,multiline:RegExp.multiline,input:RegExp.input},r=!1,n=1;n<=9;n++)r=(e["$"+n]=RegExp["$"+n])||r;return function(){var n=/[.?*+^$[\]\\(){}|-]/g,a=e.lastMatch.replace(n,"\\$&"),i=new t;if(r)for(var o=1;o<=9;o++){var s=e["$"+o];s?(s=s.replace(n,"\\$&"),a=a.replace(s,"("+s+")")):a="()"+a,oe.call(i,a.slice(0,a.indexOf("(")+1)),a=a.slice(a.indexOf("(")+1)}var l=se.call(i,"")+a;l=l.replace(/(\\\(|\\\)|[^()])+/g,function(e){return"[\\s\\S]{"+e.replace("\\","").length+"}"});var c=new RegExp(l,e.multiline?"gm":"g");c.lastIndex=e.leftContext.length,c.exec(e.input)}}function a(e){if(null===e)throw new TypeError("Cannot convert null or undefined to object");return Object(e)}function i(e){return ee.call(e,"__getInternalProperties")?e.__getInternalProperties(ge):ne(null)}function o(e){Se=e}function s(e){for(var r=e.length;r--;){var t=e.charAt(r);t>="a"&&t<="z"&&(e=e.slice(0,r)+t.toUpperCase()+e.slice(r+1))}return e}function l(e){return!!ze.test(e)&&(!ke.test(e)&&!Fe.test(e))}function c(e){var r=void 0,t=void 0;e=e.toLowerCase(),t=e.split("-");for(var n=1,a=t.length;n1&&(r.sort(),e=e.replace(RegExp("(?:"+Oe.source+")+","i"),se.call(r,""))),ee.call(Ee.tags,e)&&(e=Ee.tags[e]),t=e.split("-");for(var i=1,o=t.length;i-1)return t;var n=t.lastIndexOf("-");if(n<0)return;n>=2&&"-"===t.charAt(n-2)&&(n-=2),t=t.substring(0,n)}}function v(e,t){for(var n=0,a=t.length,i=void 0,o=void 0,s=void 0;n2){var O=u[F+1],S=k.call(D,O);S!==-1&&(j=O,z="-"+w+"-"+j)}else{var E=k(D,"true");E!==-1&&(j="true")}}if(ee.call(n,"[["+w+"]]")){var L=n["[["+w+"]]"];k.call(D,L)!==-1&&L!==j&&(j=L,z="")}h["[["+w+"]]"]=j,p+=z,y++}if(p.length>2){var P=l.indexOf("-x-");if(P===-1)l+=p;else{var N=l.substring(0,P),T=l.substring(P);l=N+p+T}l=c(l)}return h["[[locale]]"]=l,h}function p(e,r){for(var n=r.length,a=new t,i=0;in)throw new RangeError("Value is not a number or outside accepted range");return Math.floor(i)}return a}function D(){var e=arguments[0],r=arguments[1];return this&&this!==sr?j(a(this),e,r):new sr.NumberFormat(e,r)}function j(e,o,s){var l=i(e),c=n();if(l["[[initializedIntlObject]]"]===!0)throw new TypeError("`this` object has already been initialized as an Intl object");re(e,"__getInternalProperties",{value:function(){if(arguments[0]===ge)return l}}),l["[[initializedIntlObject]]"]=!0;var u=f(o);s=void 0===s?{}:a(s);var m=new r,v=w(s,"localeMatcher","string",new t("lookup","best fit"),"best fit");m["[[localeMatcher]]"]=v;var d=ue.NumberFormat["[[localeData]]"],p=h(ue.NumberFormat["[[availableLocales]]"],u,m,ue.NumberFormat["[[relevantExtensionKeys]]"],d);l["[[locale]]"]=p["[[locale]]"],l["[[numberingSystem]]"]=p["[[nu]]"],l["[[dataLocale]]"]=p["[[dataLocale]]"];var y=p["[[dataLocale]]"],b=w(s,"style","string",new t("decimal","percent","currency"),"decimal");l["[[style]]"]=b;var D=w(s,"currency","string");if(void 0!==D&&!g(D))throw new RangeError("'"+D+"' is not a valid currency code");if("currency"===b&&void 0===D)throw new TypeError("Currency code is required when style is currency");var j=void 0;"currency"===b&&(D=D.toUpperCase(),l["[[currency]]"]=D,j=z(D));var F=w(s,"currencyDisplay","string",new t("code","symbol","name"),"symbol");"currency"===b&&(l["[[currencyDisplay]]"]=F);var O=x(s,"minimumIntegerDigits",1,21,1);l["[[minimumIntegerDigits]]"]=O;var S="currency"===b?j:0,E=x(s,"minimumFractionDigits",0,20,S);l["[[minimumFractionDigits]]"]=E;var L="currency"===b?Math.max(E,j):"percent"===b?Math.max(E,0):Math.max(E,3),P=x(s,"maximumFractionDigits",E,20,L);l["[[maximumFractionDigits]]"]=P;var N=s.minimumSignificantDigits,T=s.maximumSignificantDigits;void 0===N&&void 0===T||(N=x(s,"minimumSignificantDigits",1,21,1),T=x(s,"maximumSignificantDigits",N,21,21),l["[[minimumSignificantDigits]]"]=N,l["[[maximumSignificantDigits]]"]=T);var _=w(s,"useGrouping","boolean",void 0,!0);l["[[useGrouping]]"]=_;var I=d[y],A=I.patterns,M=A[b];return l["[[positivePattern]]"]=M.positivePattern,l["[[negativePattern]]"]=M.negativePattern,l["[[boundFormat]]"]=void 0,l["[[initializedNumberFormat]]"]=!0,Q&&(e.format=k.call(e)),c(),e}function z(e){return void 0!==lr[e]?lr[e]:2}function k(){var e=null!==this&&"object"===ir.typeof(this)&&i(this);if(!e||!e["[[initializedNumberFormat]]"])throw new TypeError("`this` value for format() is not an initialized Intl.NumberFormat object.");if(void 0===e["[[boundFormat]]"]){var r=function(e){return S(this,Number(e))},t=ce.call(r,this);e["[[boundFormat]]"]=t}return e["[[boundFormat]]"]}function F(e,r){for(var t=O(e,r),n=[],a=0,i=0;t.length>i;i++){var o=t[i],s={};s.type=o["[[type]]"],s.value=o["[[value]]"],n[a]=s,a+=1}return n}function O(e,r){var n=i(e),a=n["[[dataLocale]]"],o=n["[[numberingSystem]]"],s=ue.NumberFormat["[[localeData]]"][a],l=s.symbols[o]||s.symbols.latn,c=void 0;!isNaN(r)&&r<0?(r=-r,c=n["[[negativePattern]]"]):c=n["[[positivePattern]]"];for(var u=new t,g=c.indexOf("{",0),f=0,m=0,v=c.length;g>-1&&gm){var d=c.substring(m,g);oe.call(u,{"[[type]]":"literal","[[value]]":d})}var h=c.substring(g+1,f);if("number"===h)if(isNaN(r)){var p=l.nan;oe.call(u,{"[[type]]":"nan","[[value]]":p})}else if(isFinite(r)){"percent"===n["[[style]]"]&&isFinite(r)&&(r*=100);var y=void 0;y=ee.call(n,"[[minimumSignificantDigits]]")&&ee.call(n,"[[maximumSignificantDigits]]")?E(r,n["[[minimumSignificantDigits]]"],n["[[maximumSignificantDigits]]"]):L(r,n["[[minimumIntegerDigits]]"],n["[[minimumFractionDigits]]"],n["[[maximumFractionDigits]]"]),cr[o]?!function(){var e=cr[o];y=String(y).replace(/\d/g,function(r){return e[r]})}():y=String(y);var b=void 0,w=void 0,x=y.indexOf(".",0);if(x>0?(b=y.substring(0,x),w=y.substring(x+1,x.length)):(b=y,w=void 0),n["[[useGrouping]]"]===!0){var D=l.group,j=[],z=s.patterns.primaryGroupSize||3,k=s.patterns.secondaryGroupSize||z;if(b.length>z){var F=b.length-z,O=F%k,S=b.slice(0,O);for(S.length&&oe.call(j,S);Oa;a++){var i=t[a];n+=i["[[value]]"]}return n}function E(r,t,n){var a=n,i=void 0,o=void 0;if(0===r)i=se.call(Array(a+1),"0"),o=0;else{o=e(Math.abs(r));var s=Math.round(Math.exp(Math.abs(o-a+1)*Math.LN10));i=String(Math.round(o-a+1<0?r*s:r/s))}if(o>=a)return i+se.call(Array(o-a+1+1),"0");if(o===a-1)return i;if(o>=0?i=i.slice(0,o+1)+"."+i.slice(o+1):o<0&&(i="0."+se.call(Array(-(o+1)+1),"0")+i),i.indexOf(".")>=0&&n>t){for(var l=n-t;l>0&&"0"===i.charAt(i.length-1);)i=i.slice(0,-1),l--;"."===i.charAt(i.length-1)&&(i=i.slice(0,-1))}return i}function L(e,r,t,n){var a=n,i=Math.pow(10,a)*e,o=0===i?"0":i.toFixed(0),s=void 0,l=(s=o.indexOf("e"))>-1?o.slice(s+1):0;l&&(o=o.slice(0,s).replace(".",""),o+=se.call(Array(l-(o.length-1)+1),"0"));var c=void 0;if(0!==a){var u=o.length;if(u<=a){var g=se.call(Array(a+1-u+1),"0");o=g+o,u=a+1}var f=o.substring(0,u-a),m=o.substring(u-a,o.length);o=f+"."+m,c=f.length}else c=o.length;for(var v=n-t;v>0&&"0"===o.slice(-1);)o=o.slice(0,-1),v--;if("."===o.slice(-1)&&(o=o.slice(0,-1)),cl&&(l=m,c=f),u++}return c}function $(e,r){var t=[];for(var n in pr)ee.call(pr,n)&&void 0!==e["[["+n+"]]"]&&t.push(n);if(1===t.length){var a=R(t[0],e["[["+t[0]+"]]"]);if(a)return a}for(var i=120,o=20,s=8,l=6,c=6,u=3,g=2,f=1,m=-(1/0),v=void 0,d=0,h=r.length;d=2||k>=2&&z<=1?F>0?y-=l:F<0&&(y-=s):F>1?y-=u:F<-1&&(y-=c)}}p._.hour12!==e.hour12&&(y-=f),y>m&&(m=y,v=p),d++}return v}function K(){var e=null!==this&&"object"===ir.typeof(this)&&i(this);if(!e||!e["[[initializedDateTimeFormat]]"])throw new TypeError("`this` value for format() is not an initialized Intl.DateTimeFormat object.");if(void 0===e["[[boundFormat]]"]){var r=function(){var e=Number(0===arguments.length?Date.now():arguments[0]);return H(this,e)},t=ce.call(r,this);e["[[boundFormat]]"]=t}return e["[[boundFormat]]"]}function Y(e,r){if(!isFinite(r))throw new RangeError("Invalid valid date passed to format");var a=e.__getInternalProperties(ge);n();for(var i=a["[[locale]]"],o=new sr.NumberFormat([i],{useGrouping:!1}),s=new sr.NumberFormat([i],{minimumIntegerDigits:2,useGrouping:!1}),l=X(r,a["[[calendar]]"],a["[[timeZone]]"]),c=a["[[pattern]]"],u=new t,g=0,f=c.indexOf("{"),m=0,v=a["[[dataLocale]]"],d=ue.DateTimeFormat["[[localeData]]"][v].calendars,h=a["[[calendar]]"];f!==-1;){var p=void 0;if(m=c.indexOf("}",f),m===-1)throw new Error("Unclosed pattern");f>g&&oe.call(u,{type:"literal",value:c.substring(g,f)});var y=c.substring(f+1,m);if(pr.hasOwnProperty(y)){var b=a["[["+y+"]]"],w=l["[["+y+"]]"];if("year"===y&&w<=0?w=1-w:"month"===y?w++:"hour"===y&&a["[[hour12]]"]===!0&&(w%=12,0===w&&a["[[hourNo0]]"]===!0&&(w=12)),"numeric"===b)p=S(o,w);else if("2-digit"===b)p=S(s,w),p.length>2&&(p=p.slice(-2));else if(b in hr)switch(y){case"month":p=q(d,h,"months",b,l["[["+y+"]]"]);break;case"weekday":try{p=q(d,h,"days",b,l["[["+y+"]]"])}catch(e){throw new Error("Could not find weekday data for locale "+i)}break;case"timeZoneName":p="";break;case"era":try{p=q(d,h,"eras",b,l["[["+y+"]]"])}catch(e){throw new Error("Could not find era data for locale "+i)}break;default:p=l["[["+y+"]]"]}oe.call(u,{type:y,value:p})}else if("ampm"===y){var x=l["[[hour]]"];p=q(d,h,"dayPeriods",x>11?"pm":"am",null),oe.call(u,{type:"dayPeriod",value:p})}else oe.call(u,{type:"literal",value:c.substring(f,m+1)});g=m+1,f=c.indexOf("{",g)}return ma;a++){var i=t[a];n+=i.value}return n}function W(e,r){for(var t=Y(e,r),n=[],a=0;t.length>a;a++){var i=t[a];n.push({type:i.type,value:i.value})}return n}function X(e,t,n){var a=new Date(e),i="get"+(n||"");return new r({"[[weekday]]":a[i+"Day"](),"[[era]]":+(a[i+"FullYear"]()>=0),"[[year]]":a[i+"FullYear"](),"[[month]]":a[i+"Month"](),"[[day]]":a[i+"Date"](),"[[hour]]":a[i+"Hours"](),"[[minute]]":a[i+"Minutes"](),"[[second]]":a[i+"Seconds"](),"[[inDST]]":!1})}function V(e,r){if(!e.number)throw new Error("Object passed doesn't contain locale data for Intl.NumberFormat");var t=void 0,n=[r],a=r.split("-");for(a.length>2&&4===a[1].length&&oe.call(n,a[0]+"-"+a[2]);t=le.call(n);)oe.call(ue.NumberFormat["[[availableLocales]]"],t),ue.NumberFormat["[[localeData]]"][t]=e.number,e.date&&(e.date.nu=e.number.nu,oe.call(ue.DateTimeFormat["[[availableLocales]]"],t),ue.DateTimeFormat["[[localeData]]"][t]=e.date);void 0===Se&&o(r)}var J=function(){var e={};try{return Object.defineProperty(e,"a",{get:function(){return 1}}),1===e.a}catch(e){return!1}}(),Q=!J&&!Object.prototype.__defineGetter__,ee=Object.prototype.hasOwnProperty,re=J?Object.defineProperty:function(e,r,t){"get"in t&&e.__defineGetter__?e.__defineGetter__(r,t.get):(!ee.call(e,r)||"value"in t)&&(e[r]=t.value)},te=Array.prototype.indexOf||function(e){var r=this;if(!r.length)return-1;for(var t=arguments[1]||0,n=r.length;t1){for(var l=Array(o),c=0;c=0||Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t},He=function(e,r){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!r||"object"!=typeof r&&"function"!=typeof r?e:r},We="undefined"==typeof global?self:global,Xe=function e(r,t,n,a){var i=Object.getOwnPropertyDescriptor(r,t);if(void 0===i){var o=Object.getPrototypeOf(r);null!==o&&e(o,t,n,a)}else if("value"in i&&i.writable)i.value=n;else{var s=i.set;void 0!==s&&s.call(a,n)}return n},Ve=function(){function e(e,r){var t=[],n=!0,a=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(n=(o=s.next()).done)&&(t.push(o.value),!r||t.length!==r);n=!0);}catch(e){a=!0,i=e}finally{try{!n&&s.return&&s.return()}finally{if(a)throw i}}return t}return function(r,t){if(Array.isArray(r))return r;if(Symbol.iterator in Object(r))return e(r,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),Je=function(e,r){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e)){for(var t,n=[],a=e[Symbol.iterator]();!(t=a.next()).done&&(n.push(t.value), +!r||n.length!==r););return n}throw new TypeError("Invalid attempt to destructure non-iterable instance")},Qe=function(e,r){return Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(r)}}))},er=function(e,r){return e.raw=r,e},rr=function(e,r,t){if(e===t)throw new ReferenceError(r+" is not defined - temporal dead zone");return e},tr={},nr=function(e){return Array.isArray(e)?e:Array.from(e)},ar=function(e){if(Array.isArray(e)){for(var r=0,t=Array(e.length);r